一、簡介
此文章主要記錄本人的flutter插件開發(fā)過程以及遇到的問題等,如有錯(cuò)誤請(qǐng)指正.
二、開發(fā)準(zhǔn)備(Windows)
1.Android Studio 4.0以上
2.Flutter SDK
三、環(huán)境配置
1.安裝flutter sdk
下載好之后,解壓,找到根目錄下的flutter文件下找到flutter_console.bat,雙擊運(yùn)行并啟動(dòng)flutter命令行。
2.更新環(huán)境變量
要在終端運(yùn)行 flutter 命令, 你需要添加以下環(huán)境變量到系統(tǒng)PATH:
轉(zhuǎn)到 “控制面板>用戶帳戶>用戶帳戶>更改我的環(huán)境變量”
在“用戶變量”下檢查是否有名為“Path”的條目:
如果該條目存在, 追加 flutter\bin的全路徑,使用 ; 作為分隔符.
如果條目不存在, 創(chuàng)建一個(gè)新用戶變量 Path ,然后將 flutter\bin的全路徑作為它的值.
在“用戶變量”下檢查是否有名為”PUB_HOSTED_URL”和”FLUTTER_STORAGE_BASE_URL”的條目,如果沒有,也添加它們。
重啟Windows以應(yīng)用此更改
3.測試flutter環(huán)境
打開命令行輸入:flutter doctor

如圖可以看到有兩個(gè)報(bào)錯(cuò)為插件工具沒有導(dǎo)入可查看這里解決問題:
http://www.itdecent.cn/p/3dc7dbd0712c
四、插件開發(fā)
1.使用Android Studio創(chuàng)建flutter插件
參照: http://www.itdecent.cn/p/3dc7dbd0712c
2.編譯插件橋接類
找到插件橋接類

打開后可以看到很多紅色報(bào)錯(cuò),如下圖可以點(diǎn)開新的AS界面進(jìn)行編譯:

3.方法簡介
onAttachedToEngine方法
初始化方法,"flutter_vin_plugin"為定義好的插件橋接類名,后面調(diào)用需要一一對(duì)應(yīng)。
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_vin_plugin");
channel.setMethodCallHandler(this);
}
onMethodCall方法
接受從js層獲取參數(shù)的方法"isCropImage"等都是傳遞的參數(shù)標(biāo)識(shí)通過MethodCall 對(duì)象獲取傳遞過來的數(shù)據(jù)
startScanVin等為自定義的原生方法,里面可以自定義一些操作
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
resultPlugin = result;
String isCrop = call.argument("isCropImage");
ConstantConfig.isImportCrop = !TextUtils.isEmpty(isCrop) && isCrop.equals("1");
ConstantConfig.isCheckMotorbike = Boolean.getBoolean(call.argument("containMoto") + "");
initOcrFile();
if (call.method.equals("scanVin")) {
startScanVin();
} else if (call.method.equals("imageVin")) {
startImport();
} else {
unInitOcrApi();
result.notImplemented();
}
}
onAttachedToActivity方法
此方法的包含一些原生的activity中的一些監(jiān)聽方法,添加監(jiān)聽后可實(shí)現(xiàn)對(duì)應(yīng)的原生方法。
①addRequestPermissionsResultListener: 對(duì)應(yīng)原生中的權(quán)限監(jiān)聽方法
②addActivityResultListener:對(duì)應(yīng)原生中activity回調(diào)方法等一些有關(guān)activity生命周期的方法
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
this.activity = binding.getActivity();
binding.addRequestPermissionsResultListener(new PluginRegistry.RequestPermissionsResultListener() {
@Override
public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case SCAN_PERMISSION_CODE:
if (permissions.length != 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {//失敗
Toast.makeText(activity, "請(qǐng)?jiān)试S權(quán)限在識(shí)別", Toast.LENGTH_SHORT).show();
} else {//成功
//啟動(dòng)啟動(dòng)VIN碼掃描識(shí)別頁面
Intent intent = new Intent(activity, ScanVinActivity.class);
activity.startActivityForResult(intent, VIN_RECOG_CODE);
}
break;
case IMPORT_PERMISSION_CODE:
if (permissions.length != 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {//失敗
Toast.makeText(activity, "請(qǐng)?jiān)试S權(quán)限在識(shí)別", Toast.LENGTH_SHORT).show();
} else {//成功
//啟動(dòng)啟動(dòng)VIN碼導(dǎo)入識(shí)別頁面
Intent intent = new Intent(activity, VinRecogActivity.class);
activity.startActivityForResult(intent, VIN_RECOG_CODE);
}
break;
}
return false;
}
});
binding.addActivityResultListener(new PluginRegistry.ActivityResultListener() {
@Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (data != null && requestCode == VIN_RECOG_CODE) {
//接收所有識(shí)別結(jié)果,圖片
String vinResult = data.getStringExtra("vinResult");
//接收識(shí)別結(jié)果的狀態(tài)碼,0表示成功,其他值表示識(shí)別失敗
int recogCode = data.getIntExtra("recogCode", -1);
String vinThumbPath = data.getStringExtra("vinThumbPath");
String vinAreaPath = data.getStringExtra("vinAreaPath");
Map<String, String> map = new HashMap<>();
map.put("ocrResult", vinResult);
map.put("ocrThumbPath", vinThumbPath);
map.put("ocrAreaPath", vinAreaPath);
resultPlugin.success(map);
}
return false;
}
});
}
到此插件部分已經(jīng)開發(fā)的差不多了
五、引用插件
1.在插件中的demo調(diào)用測試
找到插件目錄下的lib文件夾下的文件打開如下;

此文件為插件原生與js端溝通的橋梁所有的方法交互都需要通過此方法
如下圖,一共定義幾個(gè)方法,比如licName等參數(shù)是js傳遞過來的參數(shù),將這些參數(shù)放入param中,通過我們上面定義的flutter_vin_plugin的對(duì)象_channel執(zhí)行invokeMethod方法調(diào)用原生并聲明原生中的方法名scanVin以及傳遞js端數(shù)據(jù)集合param,,通過map接受原生中返回的數(shù)據(jù)即可.

找到j(luò)s端主頁

打開后可以定義我們?cè)跇蚪又卸x好的方法名稱

下面在main.dart中定義對(duì)應(yīng)調(diào)用的方法:
result為從原生獲取的數(shù)據(jù)_resultOcr為定義好的變量.
Future<void> scanVin() async {
Map<String, String> result;
// 參數(shù)說明 ("授權(quán)文件名稱","是否屏蔽部分校驗(yàn)規(guī)則") 0為false 1為true
result = await FlutterVinPlugin.scanVin("7332DBAFD2FD18301EF6", "0"); // TODO 掃描識(shí)別
setState(() {
_resultMap = result;
_resultOcr = _resultMap['ocrResult'];
_resultThumbPath = _resultMap['ocrThumbPath'];
_resultAreaPath = _resultMap['ocrAreaPath'];
});
}
然后即可在view中點(diǎn)擊監(jiān)聽調(diào)用:

main.dart中這里不多做描述了,具體可以查看官方文檔學(xué)習(xí)如何開發(fā)。
2.在實(shí)際項(xiàng)目中調(diào)用測試
①將插件復(fù)制進(jìn)Flutter項(xiàng)目目錄中
②Flutter項(xiàng)目中的pubspec.yaml文件,進(jìn)行如下圖配置,path根據(jù)自己的插件的相對(duì)路徑配置

③在你的項(xiàng)目中打開pubspec.yam文件執(zhí)行插件引用如圖:

④在你的項(xiàng)目中打開example下GeneratedPluginRegistrant.Java代碼,可以看到這里已經(jīng)成功引用了FlutterVinPlugin插件如圖

六、調(diào)試運(yùn)行

運(yùn)行成功
