一.Package類型
-
Dart packages:用Dart編寫(xiě)的通用包,其中一些可能包含Flutter特定的功能,因此依賴于Flutter框架,僅可用于Flutter,例如fluro包。 -
Plugin packages:一種專用的Dart包,其中包含一個(gè)用Dart代碼編寫(xiě)的API以及一個(gè)或多個(gè)特定于平臺(tái)的實(shí)現(xiàn),例如url_launcher包。
二.開(kāi)發(fā)Dart packages
1.創(chuàng)建包
flutter create --template=package hello
2.直接在hello/lib下進(jìn)行flutter平臺(tái)的代碼開(kāi)發(fā)。
三.開(kāi)發(fā)Plugin packages
1.創(chuàng)建包
--platforms=后面表示插件支持的平臺(tái),可用的平臺(tái)有:android、ios、web、linux、macos和windows。
--org用于生成插件的包標(biāo)識(shí)符。
-a表示android支持的語(yǔ)言,默認(rèn)為kotlin。
-i表示ios支持的語(yǔ)言,默認(rèn)為swift。
flutter create --org com.example --template=plugin --platforms=android,ios -i swift -a kotlin hello
2.添加ios平臺(tái)代碼
<1>確保代碼至少已經(jīng)構(gòu)建過(guò)一次:
cd hello/example
flutter clean
flutter build ios --no-codesign
<2>啟動(dòng)Xcode:hello/example/ios/Runner.xcworkspace,開(kāi)始編輯ios平臺(tái)代碼。
<3>添加第三方依賴Pods/Development Pods/hello/Pod/hello.podspec:
Pod::Spec.new do |s|
# lines skipped
s.dependency 'MTBBarcodeScanner'
添加完成后
pod install
<4>插件代碼位于Pods/Development Pods/hello/../../example/ios/.symlinks/plugins/hello/ios/Classes下。
遵守FlutterPlatformViewFactory協(xié)議的文件:
import UIKit
class BarcodeScannerFactory: NSObject, FlutterPlatformViewFactory {
private var messenger: FlutterBinaryMessenger?
init(messenger: FlutterBinaryMessenger) {
super.init()
self.messenger = messenger
}
func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
/// 注:frame和viewId獲取不到,frame為zero,viewId為0
return BarcodeScannerView(
frame: frame,
viewIdentifier: viewId,
arguments: args,
binaryMessenger: messenger
)
}
func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
return FlutterStandardMessageCodec(readerWriter: FlutterStandardReaderWriter())
}
}
遵守FlutterPlatformView協(xié)議的文件:
import UIKit
import MTBBarcodeScanner
class BarcodeScannerView: NSObject, FlutterPlatformView {
private var scannerView: UIView!
private var scanner: MTBBarcodeScanner!
init(
frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?,
binaryMessenger messenger: FlutterBinaryMessenger?
) {
super.init()
scannerView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
scanner = MTBBarcodeScanner(previewView: scannerView)
do {
try scanner.startScanning(resultBlock: { _ in })
} catch {}
}
func view() -> UIView {
return scannerView;
}
}
在插件中注冊(cè)FlutterPlatformViewFactory:
import Flutter
import UIKit
class BarcodeScannerPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
registrar.register(BarcodeScannerFactory(messenger: registrar.messenger()), withId: "view_type_id_scanner_view")
}
}
3.添加android平臺(tái)代碼
<1>運(yùn)行example文件代碼
構(gòu)建依賴:
cd hello/example
flutter pub get
Android Studio->File->Open,選擇hello/example/android/build.gradle啟動(dòng)并運(yùn)行。
<2>啟動(dòng)Android Studio:hello/android,開(kāi)始編輯android平臺(tái)代碼。
<3>添加第三方依賴Gradle Scripts/build.gradle(Module:android.hello):
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
/// 添加第三方庫(kù)
implementation 'me.dm7.barcodescanner:zxing:1.9.13'
}
<4>插件代碼位于hello/java/下。
若出現(xiàn)
Unresolved reference: io.flutter,選擇File->Invalidate Caches/Restart...。
繼承混合類PlatformViewFactory的文件:
import android.content.Context
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory
class BarcodeScannerFactory(private var messenger: BinaryMessenger) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
return BarcodeScannerView(messenger, context, viewId, args)
}
}
繼承混合類PlatformView的文件:
import android.content.Context
import android.view.View
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.platform.PlatformView
import me.dm7.barcodescanner.zxing.ZXingScannerView
class BarcodeScannerView(binaryMessenger: BinaryMessenger, context: Context, viewId: Int, args: Any?) : PlatformView {
private var scannerView = ZXingScannerView(context)
init {
scannerView.startCamera()
}
override fun getView(): View {
return scannerView
}
override fun dispose() {}
}
在插件中注冊(cè)PlatformViewFactory:
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
flutterPluginBinding.platformViewRegistry.registerViewFactory("view_type_id_scanner_view", BarcodeScannerFactory(flutterPluginBinding.binaryMessenger))
}
4.添加flutter平臺(tái)代碼
代碼位于hello/lib:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class BarcodeScanner extends StatelessWidget {
const BarcodeScanner({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
const String viewType = 'view_type_id_scanner_view';
const Map<String, dynamic> creationParams = {'name': '張三'};
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return const AndroidView(
viewType: viewType,
creationParams: creationParams,
creationParamsCodec: StandardMessageCodec(),
);
case TargetPlatform.iOS:
return const UiKitView(
viewType: viewType,
creationParams: creationParams,
creationParamsCodec: StandardMessageCodec(),
);
default:
return const Text('暫不支持該平臺(tái)');
}
}
}
四.插件發(fā)布
1.完善pubspec.yaml文件
name: 插件名稱
description: 插件描述
version: 插件版本號(hào),0.0.1
author: 作者,xxxx<xx@xxx.com>
homepage: 項(xiàng)目主頁(yè)地址
publish_to: 填寫(xiě)私有服務(wù)器的地址(如果是發(fā)布到flutter pub則不用填寫(xiě),插件默認(rèn)是上傳到flutter pub)
2.檢驗(yàn)是否可以發(fā)布
flutter packages pub publish --dry-run
--dry-run 參數(shù)表示本次執(zhí)行會(huì)檢查插件的配置信息是否有效,插件是否滿足上傳條件。如果成功的話并不會(huì)真正的將插件上傳,而是會(huì)顯示本次要發(fā)布插件的信息,并提示成功。一般在插件的正式發(fā)布前,建議先執(zhí)行該命令,避免在上傳過(guò)程中出現(xiàn)錯(cuò)誤。
3.正式發(fā)布
發(fā)布到pub平臺(tái):
flutter packages pub publish
發(fā)布到私有服務(wù)器:
flutter packages pub publish --server $服務(wù)器地址
pubspec.yaml文件中列出的包作者與授權(quán)發(fā)布該包的人員列表不同。發(fā)布某個(gè)軟件包的第一個(gè)版本的人自動(dòng)成為第一個(gè)也是唯一一個(gè)有權(quán)上傳其他版本軟件包的人。要允許或禁止其他人上載版本,請(qǐng)使用pub uploader命令。
五.iOS中podspec文件
1.Podfile與podspec的區(qū)別
-
Podfile指的是將本地或遠(yuǎn)端的庫(kù)導(dǎo)入到該工程。 -
podspec指的是依賴于該庫(kù),若該庫(kù)在本地沒(méi)有,會(huì)先去cocoapods下載導(dǎo)入到該工程。
2.podsepc依賴于git庫(kù)
podsepc文件中的s.dependency只能依賴于cocoapods中的版本,而不能依賴于git庫(kù)??墒褂靡韵路椒ń鉀Q。
事例:依賴于IMKit的git庫(kù)https://github.com/imkit/imkit-ios-framework-v3.git
<1>在插件工程的podsepc文件中依賴:
s.dependency 'IMKit'
<2>在項(xiàng)目工程的Podfile文件中導(dǎo)入:
target 'Runner' do
use_frameworks!
use_modular_headers!
pod 'IMKit', :git => 'https://github.com/imkit/imkit-ios-framework-v3.git'
end
3.podsepc依賴于cocoapods的靜態(tài)framework庫(kù)
事例:依賴于靜態(tài)庫(kù)PrintSDK.framework
<1>在插件工程的podsepc文件中依賴:
# 使用靜態(tài)庫(kù)
s.static_framework = true
# 依賴第三方的framework
s.dependency 'PrinterSDK'
# 依賴系統(tǒng)庫(kù)(可選)
s.frameworks = 'UIKit', 'SystemConfiguration'
# Xcode里面Build Settings ->Other Linker Flags設(shè)置-ObjC(可選)
s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-lObjC' }
若不設(shè)置s.static_framework = true,會(huì)報(bào)錯(cuò):The 'Pods-Runner' target has transitive dependencies that include statically linked binaries。