
最近專案中需要在Android原生的應用中添加一些功能,時間緊,任務重,考慮再三,只有Android與Flutter混合才能按時完成,如上圖所示,在Android頁面中有些按鈕需要在Android中跳轉,而一些按鈕則需跳轉至Flutter頁面,本文簡單梳理一下混合開發流程,
1. 創建flutter module

在Android專案中點擊New,然后New Module,然后在彈出的面板中選擇Flutter Module,之后輸入Flutter module的Project name,選擇Flutter SDK所在的路徑,選擇Flutter module的檔案位置,最后輸入Flutter module的描述,然后Next,如下圖所示

上訴基本資訊填充完畢后,點擊Next,在彈出的面板中輸入Flutter module的包名,如下圖所示

輸入Package name后點擊Finish后Flutter module就正式創建完畢,創建好的flutter module和新建的flutter專案在內容上基本沒有差別,
2. 關聯Flutter Module
一般來講,當用戶創建好Flutter module后,Android專案中會自動關聯創建好的flutter module,是否關聯可以在Android專案中settings.gradle中查看,

若開發中是匯入flutter module,或想直接使用其他的flutter專案,可手動在settings.gradle中添加
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir,
'../flutter_module/.android/include_flutter.groovy'
))
其中’…/flutter_module/.android/include_flutter.groovy’是flutter module中include_flutter.groovy的檔案路徑,由于flutter module所在的位置不一定在Android專案中,只要這個路徑寫對,flutter module在電腦中任意位置都可以,
同時還需要在使用flutter module的Android module下的build.gradle中dependencies添加
implementation project(path: ':flutter')
3. Android中跳轉Flutter頁面
- FlutterActivity直接跳轉
在跳轉之前需要先在AndroidManifest.xml注冊FlutterActivity,
<activity
android:name="io.flutter.embedding.android.FlutterActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize" >
</activity>
在需要跳轉的時候,使用FlutterActivity.withNewEngine()進行跳轉:
startActivity(FlutterActivity.withNewEngine()
.initialRoute("params")
.build(xxxxActivity.this));
其中initialRoute是Android跳轉到flutter需要的引數,非必需,
在flutter接收引數如下
...
class _MyHomePageState extends State<MyHomePage> {
String route = window.defaultRouteName;
...
}
window.defaultRouteName就是獲取Android傳遞過來的引數,當Android端需要跳轉多個flutter頁面,通常這個用于路由分發,若需要的資訊比較多的時候可以傳遞json字串,注:window.defaultRouteName的導包為’dart:ui’,而不是’dart:html’,
- FlutterActivity間接跳轉
所謂的間接跳轉其實就是通過繼承FlutterActivity來實作的
public class Hybrid extends FlutterActivity {
public final static String PARAMS = "params";
private String params;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
params = getIntent().getStringExtra(PARAMS);
}
@NonNull
@Override
public String getInitialRoute() {
return params == null ? super.getInitialRoute() : params;
}
public static void toFlutter(Context context, String params) {
Intent intent = new Intent(context, Hybrid.class);
intent.putExtra(PARAMS, params);
context.startActivity(intent);
}
}
在AndroidManifest.xm注冊Hybrid后就可以通過
Hybrid.toFlutter(xxxxxActivity.this,"params");
進行跳轉,
- 通過FlutterEngine和BasicMessageChannel進行跳轉
為什么會有這種方式,是因為使用前兩種方式跳轉時會有短暫的空白,使用起來感覺非常不流暢,嚴重影響用戶體驗,這種跳轉方式和上面的兩種不同,邊跳邊發,適用于多種場景,這里也不一定非要使用BasicMessageChannel,也可使用MethodChannel或EventChannel,只是混合開發通常涉及到兩端頻繁通信,個人更加傾向使用BasicMessageChannel,不分主客,使用和通信更方便,
- FlutterEngine和BasicMessageChannel的初始化和使用
public class HyBridRouteAndMessageHandleCenter{
private static FlutterEngine flutterEngine;
private static BasicMessageChannel basicMessageChannel;
private static String channelName = "com.hybrid.basic.message.channel";
public static final String ENGINE_ID = "default_engine_id";
private static Context mContext;
private static BasicMessageChannel.Reply mReplay;
public static void init(Context context) {
mContext = context;
if (flutterEngine == null) {
flutterEngine = new FlutterEngine(context);
flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
FlutterEngineCache.getInstance().put(ENGINE_ID, flutterEngine);
}
if (basicMessageChannel == null) {
if (flutterEngine != null) {
basicMessageChannel = new BasicMessageChannel<Object>(flutterEngine.getDartExecutor(), channelName, StandardMessageCodec.INSTANCE);
basicMessageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler() {
@Override
public void onMessage(@Nullable @org.jetbrains.annotations.Nullable Object message, @NonNull @NotNull BasicMessageChannel.Reply reply) {
mReplay = reply;
// 接收訊息并處理
handleMessage(message, reply);
}
});
}
}
}
// 處理訊息
private static void handleMessage(Object message, BasicMessageChannel.Reply reply) {
...
}
public static void toFlutter(Context context, Object params) {
sendMessage(params);
context.startActivity(FlutterActivity.withCachedEngine(ENGINE_ID).build(context));
}
public static void sendMessage(Object object) {
if (basicMessageChannel != null) {
basicMessageChannel.send(object, new BasicMessageChannel.Reply() {
@Override
public void reply(@Nullable @org.jetbrains.annotations.Nullable Object reply) {
// 發送回呼
...
}
});
}
}
public static void destroyEngine() {
if (flutterEngine != null) {
flutterEngine.destroy();
}
}
}
- 使用FlutterActivity.withCachedEngine(ENGINE_ID).build(context)使因為從快取中取更快,更省,而且只需要創建一個flutterEngine即可,Android端其實是可以創建多個flutterEngine,只要ENGINE_ID不同,就不是同一個flutterEngine,但是在iOS中只能有一個flutterEngine,使用多個會無效閃退,為了節省資源,避免過多損耗,全域使用一個flutterEngine比較好,
- 關于Flutter向Android發送訊息,比如flutter想拍照,拍完照后的圖片路徑需要傳給flutter,照片的路徑發送可以使用BasicMessageChannel.Reply回復,也可以使用sendMessage主動再發一次訊息,個人認為接收訊息并回復訊息屬于一次通信,所以傾向于使用BasicMessageChannel.Reply,若在Android端有多個頁面需要向flutter回復結果,建議使用sendMessage,
- Flutter收發訊息
static const BasicMessageChannel messageChannel = const BasicMessageChannel(
"com.hybrid.basic.message.channel", StandardMessageCodec());
static Future<dynamic> sendMessage(Object message) async{
dynamic result = await messageChannel.send(message);
print("**********$result");
return result;
}
...
messageChannel.setMessageHandler((message) async {
...
}
...
- sendMessage即flutter向Android端發送訊息,比如拍照,拍完照后Android端通過BasicMessageChannel.Reply將圖片路徑reply.reply(imageUrl)給flutter,而flutter通過dynamic result = await messageChannel.send(message)接識訓復的訊息,其中result即為Android端回傳imageUrl,
- messageChannel.setMessageHandler是Android主動向flutter發訊息,flutter端的訊息監聽,通過決議message,可以知道Android需要flutter做什么,比如要跳轉到什么頁面,需要增刪改什么資料等等,
4. 效果

5. 總結
1. 若熟練使用Flutter,混合開發可節省至少30%時間,
2. 直接使用FlutterActivity進行跳轉,跳轉程序中會出現空白間隙,建議使用FlutterEngineCache,效果更好,
3. 創建的Flutter Module不一定非要在Android專案中,可以在任意位置,關聯正確就好,
注 :Android Studio 4.2.1,Android SDK 30 ,Flutter 2.2.0 , Dart 2.13.0,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/286417.html
標籤:其他
上一篇:2021-06-03 iOS的alloc的底層代碼流程
下一篇:Android中的執行緒(一)
