前言
最近我在業餘時間開發了一個Flutter外掛用於Android應用內的版本更新:flutter_xupdate,發現在開發的過程中沒遇到什麼坑,但就是在釋出到flutter外掛平臺時碰到了很多問題,這裡我記錄一下,給後來的人一點建議.
Flutter Plugin外掛開發
1.建立Flutter Plugin外掛專案
這裡推薦使用Android Studio建立專案,根據提示一步一步來就行了,截圖如下:
生成的專案目錄主要包含以下內容:- “android”目錄是外掛API在Android平臺的實現。
- “ios”目錄是外掛API在iOS平臺的實現。
- “example”目錄是使用外掛的一個示例專案。
- “lib”目錄的檔案,主要是建立“MethodChannel”,然後接收並處理來自原生平臺發來的訊息
2.實現外掛功能
這裡我主要介紹一下Android端的API實現.
坑點一: Flutter外掛載入存在兩個版本
由於Flutter自動依賴外掛的方式存在兩個版本(Registrar和FlutterPluginBinding), 因此我們在實現Android的外掛的時候,為了能提高相容性,最好把這兩種都實現一遍.所以,Android的外掛需要實現FlutterPlugin
, ActivityAware
, MethodCallHandler
這三個介面, 以我的flutter_xupdate外掛為例,實現如下:
public class FlutterXUpdatePlugin implements FlutterPlugin, ActivityAware, MethodCallHandler {
private static final String PLUGIN_NAME = "com.xuexiang/flutter_xupdate";
private MethodChannel mMethodChannel;
private Application mApplication;
private WeakReference<Activity> mActivity;
//此處是新的外掛載入註冊方式
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
mMethodChannel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), PLUGIN_NAME);
mApplication = (Application) flutterPluginBinding.getApplicationContext();
mMethodChannel.setMethodCallHandler(this);
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
mMethodChannel.setMethodCallHandler(null);
mMethodChannel = null;
}
public FlutterXUpdatePlugin initPlugin(MethodChannel methodChannel, Registrar registrar) {
mMethodChannel = methodChannel;
mApplication = (Application) registrar.context().getApplicationContext();
mActivity = new WeakReference<>(registrar.activity());
return this;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
switch (call.method) {
case "getPlatformVersion":
result.success("Android " + android.os.Build.VERSION.RELEASE);
break;
case "initXUpdate":
initXUpdate(call, result);
break;
...
default:
result.notImplemented();
break;
}
}
@Override
public void onAttachedToActivity(ActivityPluginBinding binding) {
mActivity = new WeakReference<>(binding.getActivity());
}
@Override
public void onDetachedFromActivityForConfigChanges() {
}
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
}
@Override
public void onDetachedFromActivity() {
mActivity = null;
}
//此處是舊的外掛載入註冊方式
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), PLUGIN_NAME);
channel.setMethodCallHandler(new FlutterXUpdatePlugin().initPlugin(channel, registrar));
}
}
複製程式碼
以上程式碼需要注意的是:
registerWith
靜態方法是flutter舊的載入外掛的方式,通過反射進行載入.onAttachedToEngine
和onDetachedFromEngine
是FlutterPlugin
的介面方法,是flutter新的載入外掛的方式.onAttachedToActivity
和onDetachedFromActivity
是ActivityAware
的介面方法,主要是用於獲取當前flutter頁面所處的Activity.onMethodCall
是MethodCallHandler
的介面方法,主要用於接收Flutter端對原生方法呼叫的實現.
坑點二:原生和flutter之間資料互動型別有限制
在進行外掛的開發時,就必定會涉及到原生和flutter之間的資料互動.這裡需要注意的是,就像我們在進行react-native和JNI的開發時,並不是什麼型別的資料都是支援互動的.下面我給出原生和flutter之間可互動的資料型別:
Dart | Android | iOS |
---|---|---|
null | null | nil (NSNull when nested) |
bool | java.lang.Boolean | NSNumber numberWithBool: |
int | java.lang.Integer | NSNumber numberWithInt: |
int, if 32 bits not enough | java.lang.Long | NSNumber numberWithLong: |
double | java.lang.Double | NSNumber numberWithDouble: |
String | java.lang.String | NSString |
Uint8List | byte[] | FlutterStandardTypedData typedDataWithBytes: |
Int32List | int[] | FlutterStandardTypedData typedDataWithInt32: |
Int64List | long[] | FlutterStandardTypedData typedDataWithInt64: |
Float64List | double[] | FlutterStandardTypedData typedDataWithFloat64: |
List | java.util.ArrayList | NSArray |
Map | java.util.HashMap | NSDictionary |
這裡我們用得最多的就是bool
、int
、String
、Map
這幾個型別了
3.外掛釋出
外掛釋出遇到的坑最多,需要額外注意.
完善文件
建議將以下文件新增到外掛專案中:
README.md
:介紹包的檔案CHANGELOG.md
記錄每個版本中的更改LICENSE
包含軟體包許可條款的檔案- 所有公共API的API文件
釋出外掛
執行下面的命令進行釋出:
flutter packages pub publish
複製程式碼
你以為就這樣就完事了?不不不,下面坑可多了!!
坑點三:許可權認證需要翻牆
由於我們要將外掛釋出到flutter外掛平臺,要知道這平臺可是google建的,需要釋出的話,就必須要登入google賬號進行認證.在我們輸入flutter packages pub publish
命令之後,我們會收到一條認證連結,這就是需要我們登入google賬號.
要知道google可是被牆的,這裡我們需要翻牆軟體翻牆登入google賬號並進行認證.
坑點四:Flutter中文網搭建文件有毒
你以為登入完google賬號就完事了?想太多了!這裡有個大坑就是flutter中文網上的環境配置問題,如下圖所示:
這裡官方讓我們配置一下Flutter的臨時映象,一般人剛接觸的時候都是按照官方文件一步一步來,相信這一步肯定也少不了.可就是這麼不起眼的一步,就讓我在認證一步一直卡著.在網上找了半天的解決方法都沒有任何用.中間也有人說是因為配置了映象的問題,不敢我怎麼也不相信是這個問題導致的.這裡我們去掉映象配置就可以通過認證了.
坑點五:翻牆工具對命令終端不起作用
本來以為好不容易認證通過了,這下總能上傳成功吧,結果意外又出現了,我一直卡在Uploading...
,怎麼也上傳不成功.
Uploading...
Failed to upload the package.
複製程式碼
在網上百度了,說是翻牆工具對命令終端不起作用,需要給命令列設定代理.
export https_proxy=http://127.0.0.1:1087
export http_proxy=http://127.0.0.1:1087
set https_proxy=https://127.0.0.1:1087
set http_proxy=http://127.0.0.1:1087
複製程式碼
因為我使用的是小飛機翻牆工具,mac,所以我的代理埠是1087
.
可是直接這樣設定也是無法上傳成功的.需要我們藉助privoxy
工具完成終端的代理,操作如下:
- 安裝privoxy
brew install privoxy
複製程式碼
- 修改privoxy配置
vim /usr/local/etc/privoxy/config
複製程式碼
加入這兩個配置(注意第一行的埠號要根據你的科學上網的代理來看,我這裡沒有改,它預設的是 1087),另外注意不要忘了最後有一個空格和點號。
listen-address 0.0.0.0:1087
forward-socks5 / localhost:1080 .
複製程式碼
- 啟動 privoxy
sudo /usr/local/sbin/privoxy /usr/local/etc/privoxy/config
複製程式碼
啟動之後我們檢視一下是否啟動了:
netstat -na | grep 1087
複製程式碼
出現類似如下結果, 就證明啟動成功了。
tcp4 0 0 127.0.0.1.1087 *.* LISTEN
複製程式碼
這時候再重新執行一下:
export https_proxy=http://127.0.0.1:1087
export http_proxy=http://127.0.0.1:1087
set https_proxy=https://127.0.0.1:1087
set http_proxy=http://127.0.0.1:1087
複製程式碼
最後再執行一下發布命令:
flutter packages pub publish
複製程式碼
如果出現如下結果,就證明發布成功了!
Waiting for your authorization...
Authorization received, processing...
Successfully authorized.
Uploading...
Successfully uploaded package.
複製程式碼