本文未提供 iOS 端集成與使用示例
當一個成熟的產品/項目,想要開始 Flutter 開發,同時又不想從零開始全面使用 Flutter 開發,最后選擇保留原有 Native 項目代碼和功能,在新業務或變動上使用 Flutter 進行開發,這種以 既有原生,又有 Flutter 的開發模式就稱之為 Flutter 混合開發模式。該開發模式的好處體現在,不用全面推翻 APP 項目的原有積累, Native 端就可以無感接入 Flutter ,開始 Flutter 開發,擁抱 Flutter 的特性特點。
1.FlutterBoost 簡介
FlutterBoost 是阿里系閑魚技術團隊開源的 Flutter 插件,它可以輕松為現有原生應用程序提供 Flutter 混合集成方案。其理念是將 Flutter 像 WebView 那樣來使用。FlutterBoost 幫開發者處理 Native 與 Flutter 頁面的映射和跳轉,開發者只需關心頁面的名字和參數即可 ( 通常可以是 URL ) 。
FlutterBoost 的優點
- 官方的集成方案有諸多弊病,eg:日志不能輸出到原生端、存在內存泄漏的問題、資源冗余……
- FlutterBoost 的通道的封裝使得 Native 調用 Flutter 、Flutter 調用 Native 的開發更加簡便
- FlutterBoost 對于頁面生命周期的管理,也梳理的比較整齊
- FlutterBoost 為阿里出品,已在閑魚生產環境中使用,正穩定為億級用戶提供服務
2.FlutterBoost 集成 ( 版本 1.17.1 )
2.1 Flutter 端集成
通過 IDE 創建 Flutter Module ,命名為 flutter_module ( 本示例使用的是 Android Studio ,也可以通過別的 IDE 或命令臺方式創建 Flutter Module )
使用 IDE 打開上面步驟創建的 Flutter Module,在根目錄 pubspec.yaml 文件中的 dependencies : 下添加 FlutterBoost 依賴 ( 點擊跳轉查看源碼 )
#閑魚 flutter_boost
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: '1.17.1'
通過命令 flutter build apk 來檢查是否完成 FlutterBoost 的依賴,成功示意圖如下
2.2 Android 端集成
新建 Android 項目或在原有 Android 項目(本示例中的 Android 項目名為 AndroidDemo )的根目錄中的 settings.gradle 內引用上一個步驟創建的 Flutter Module ,代碼如下 ( PS :文件名與路徑請視實際情況調整 ) ( 點擊跳轉查看源碼 )
//引用 Flutter 模塊
setBinding(new Binding([gradle:this]))
evaluate(new File('../flutter_module/.android/include_flutter.groovy'))
include ':flutter_module'
project(':flutter_module').projectDir = new File('../flutter_module')
本示例中對應的文件路徑/層級關系如下圖
添加完成后編譯項目,sync now,完成后得到如下項目結構,項目中多出了 flutter、flutter_boost 和 flutter_module
接著完成 Android 端 FlutterBoost 的依賴,在 app 下的 build.gradle 中的 dependencies 下添加 FlutterBoost 依賴并同步 ( 點擊跳轉查看源碼 )
以上操作就完成了Android 端 Flutter Module 和 FlutterBoost 的引用和依賴,因為 iOS 端的引用需要在 macOS 上操作,故在此不做演示 。
3.FlutterBoost 使用
只介紹 Android 端和 Flutter 端的相互調用,因當前操作系統為 Windows 而非 macOS 所以未包含 iOS 端。
主要講解如下功能點的實現:
- FlutterBoost 的初始化
- 基于 FlutterBoost 實現 Native 啟動 Flutter 頁面,攜帶請求參數并接收返回結果
- 基于 FlutterBoost 實現 Flutter 啟動 Native 頁面,攜帶請求參數并接收返回結果
- 基于 FlutterBoost 實現 Flutter 啟動 Flutter 頁面,攜帶請求參數并接收返回結果
3.1 FlutterBoost 初始化
3.1.1 Android 端初始化
1.在 AndroidManifest.xml 中添加配置 ( 點擊跳轉查看源碼 )
<!-- FlutterBoost 配置 -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
2.自定義 Application ,并在 onCreate 方法中初始化 FlutterBoost ( 點擊跳轉查看源碼 )
3.1.2 Flutter 端初始化
1.在 main.dart 中 AppWidget 的 State 的 initState () 方法中注冊 FlutterBoost ,并在 build 方法中初始化 FlutterBoost ( 點擊跳轉查看源碼 )
3.2 Native 傳參啟動 Flutter 頁面,并接收返回結果
啟動 Flutter 頁面需要一個 Activity 作為載體,該載體應為 BoostFlutterActivity 或其子類,所以有兩種方式啟動 Flutter 頁面。
1.單純通過 BoostFlutterActivity 啟動 Flutter 頁面
1.1 在 AndroidManifest.xml 注冊 BoostFlutterActivity ( 點擊跳轉查看源碼 )
1.2 根據設定的 路由地址( 該地址應與 Flutter Module 中設定的保持一致 ) 跳轉啟動 Flutter 頁面,這里封裝成方法 openPageByUrl ( 點擊跳轉查看源碼 )
//跳轉 Flutter 頁面
val intent =
BoostFlutterActivity.withNewEngine().url(url)
.params(requestParams ?: mutableMapOf())
.backgroundMode(BoostFlutterActivity.BackgroundMode.opaque)
.build(context)
if (context is Activity) {
context.startActivityForResult(intent, requestCode)
} else {
context.startActivity(intent)
}
1.3 在調用 openPageByUrl 方法的 Activity 上重寫 onActivityResult 方法接收回調
2.通過自定義 Activity 繼承 BoostFlutterActivity 為載體啟動 Flutter 頁面
2.1 自定義 FlutterPageActivity 繼承 BoostFlutterActivity 并重寫 getContainerUrlParams () 、 getContainerUrl () 和 onActivityResult 方法 ( 點擊跳轉查看源碼 )
2.2 啟動 FlutterPageActivity ( 別忘了在 AndroidManifest.xml 中注冊該 Activity )
3.Flutter 端進行相應配置
3.1 在 main.adrt 的 FlutterBoost.singleton.registerPageBuilders 方法中注冊 路由地址 ( 該地址應與 Native 層的保持一致 ) 與其 對應的 Widget 并接收 請求數據 params ( 點擊跳轉查看源碼 )
3.2 Widget 中調用 FlutterBoost 提供的 closeCurrent 方法關閉當前 Flutter 頁面并返回數據給上一個頁面 ( Flutter / Native )
3.3 Flutter 傳參啟動 Native / Flutter 頁面,并接收返回結果
當 Flutter 端通過 FlutterBoost 啟動新的頁面時,無論要啟動的目標頁面屬于 Native 頁面還是 Flutter 頁面,其都只是觸發 Native 端 ( 以 Android 端為例 ) INativeRouter 接口的 openContainer 回調,然后 Native 端在該回調方法中接收請求參數 urlParams ,并根據 url 控制是否啟動及啟動哪一個新頁面。
3.3.1 Flutter 端傳參啟動新頁面
1.Flutter 端啟動新頁面 ( 點擊跳轉查看源碼 )
//啟動新頁面帶請求參數和回調監聽
Map<String, dynamic> requestParams = Map();
requestParams[HasRequestParamsNative.EXTRA_KEY_NATIVE] = "Hello native";
FlutterBoost.singleton
.open(Test.PAGE_NATIVE_HAS_RESULT,
urlParams: requestParams)
.then((Map<dynamic, dynamic> value) {
//TODO 回調監聽 value 則是新頁面返回的數據
});
2.Android 端在 FlutterBoost 初始化的時候,注冊路由跳轉監聽,并在回調方法中判斷啟動新頁面 ( 點擊跳轉查看源碼 )
//路由跳轉監聽
val router = INativeRouter { context, url, urlParams, requestCode, exts ->
/**
* 當 Flutter 中使用 FlutterBoost 啟動新頁面 (Flutter/Native) 時,觸發該回調
* 如果需要啟動 Native 頁面,則通過 context.startActivity 啟動指定頁面
* 如果需要啟動 Flutter 頁面,則通過 FlutterBoost 啟動指定頁面
*/
//TODO 判斷啟動新頁面
//PageRouter.openPageByUrl(context, url, urlParams, requestCode)
}
val platform = FlutterBoost.ConfigBuilder(this, router)
.isDebug(true)
.whenEngineStart(FlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
.renderMode(FlutterView.RenderMode.texture)
.lifecycleListener(boostLifecycleListener)
.build()
FlutterBoost.instance().init(platform)
3.3.2 Android 端返回數據給上一個頁面 ( 點擊跳轉查看源碼 )
/**
* 關閉當前頁面并返回數據至 Flutter 頁面
* @param resultData 返回數據
*/
fun finishAndResult(activity: Activity, resultData: MutableMap<String, Any>? = null) {
val intent = Intent()
val bundle = Bundle()
bundle.putSerializable(
IFlutterViewContainer.RESULT_KEY,
(resultData ?: mutableMapOf()) as Serializable
)
intent.putExtras(bundle)
activity.setResult(0, intent)
activity.finish()
}
3.3.3 Flutter 端返回數據給上一個頁面 ( 點擊跳轉查看源碼 )
// FlutterBoost 關閉當前頁面并回調數據給上一個頁面
var resultMap = Map<String, dynamic>();
resultMap[HasResult.EXTRA_KEY_NAME] = "張先生";
resultMap[HasResult.EXTRA_KEY_AGE] = 26;
FlutterBoost.singleton.closeCurrent(result: resultMap);
4.最后
因為發現現階段 FlutterBoost 的集成與使用文檔較少或較舊,所以本文主要講原生項目如何借助 FlutterBoost 集成 Flutter 開始混合開發,基于 FlutterBoost 的 Flutter 與 Native 的基礎交互也已詳細交代清楚。
針對那些還對 Flutter 開發持觀望態度的開發人員來說,建議可以借著 FlutterBoost 的簡潔便利,試著把項目從原生項目開始嘗試 Flutter 開發,同時讓自己從原生開發人員開始兼職 Flutter 開發人員,擁抱和體驗 " 新 " 技術。
- 源碼及 Demo 地址:https://github.com/ziwenL/FlutterBoostDemo
- 如有更好的見解或建議,歡迎留言