為了降低風險,大部分App采用漸進式方式引入Flutter,在App裡選幾個頁面用Flutter來編寫,但都碰到了相同的問題,在原生頁面和Flutter頁面共存的情況下,如何管理路由? 官方沒有提供這樣的解決方案,而FlutterBoost就是為了解決這個問題而生。FlutterBoost從開源後受到了社群開發者的歡迎,已經有很多App使用了FlutterBoost,社群開發者也很活躍,提了很多Issue和PR。感謝開發者的一路支援和包容,無論是意見回報還是吐槽,我們都會認真看,會持續關注Issue。
作者:閑魚技術——石磬
背景
随着Flutter的發展,國内越來越多的App開始使用Flutter。為了降低風險,大部分App采用漸進式方式引入Flutter,在App裡選幾個頁面用Flutter來編寫,但都碰到了相同的問題,在原生頁面和Flutter頁面共存的情況下,如何管理路由? 官方沒有提供這樣的解決方案,而FlutterBoost就是為了解決這個問題而生。FlutterBoost從開源後受到了社群開發者的歡迎,已經有很多App使用了FlutterBoost,社群開發者也很活躍,提了很多Issue和PR。感謝開發者的一路支援和包容,無論是意見回報還是吐槽,我們都會認真看,會持續關注Issue。
使命
FlutterBoost的使命是讓開發者非常簡單的在原生App中開發Flutter頁面。 FlutterBoost做為Flutter sdk上層的解決方案,有一定的局限性,我們需要依賴sdk更多的開放能力。是以我們同時在做兩件事情:
- 推動Flutter官方開放更多的底層接口
我們參與Flutter 組織的
Multiple Flutters的讨論。也多次發郵件給Flutter團隊回報sdk的Bug和一些無法支援的應用場景。 很欣慰的是在Flutter 2.0 上看到混合開發的重大進展,Flutter2.0 提供了 FlutterEngineGroup,FlutterEngineGroup建立一個新Engine,記憶體隻增加180k,這個給我們提供了很多想象空間。但FlutterEngineGroup最大的問題是多Engine之間不是isolate層面的記憶體共享。 從目前看FlutterBoost這種單Engine記憶體共享的方式還不能被完全取代。
- FlutterBoost的更新
雖然開源社群很活躍,star很多,使用者也很多,但FlutterBoost離優秀的開源項目還很遠。
FlutterBoost的問題
梳理了一下問題:
- 穩定性,每次Flutter釋出一個stable版本,開發者會來問我,FlutterBoost針對新版本适配了沒有?他們準備更新新版本,需要FlutterBoost能适配最新版本。而我每次都要針對新版本拉2個新分支(Androidx 和Support分支),進行适配。 時間長了,會産生很多分支,這個給分支管理帶來很大的成本,比如在某個分支上修複的issue要同步到其他分支,一不小心就會遺漏同步。
- 社群的issue沒有收斂的趨勢。
- 設計過于複雜,概念太多。這讓一個新手看FlutterBoost的代碼很吃力。
這些問題促使我們重新梳理設計,為了徹底解決這些頑固的問題,我們做一次大更新,我們把這次更新命名為FlutterBoost 3.0(上一次更新是2.0)
FlutterBoost3.0做了什麼
針對上面的問題,我們做了幾個事項 不侵入引擎,相容Flutter的各種版本,Flutter sdk的更新不需要再更新FlutterBoost,極大降低更新成本。 不區分Androidx和Support分支。 簡化架構和接口,和FlutterBoost2.0比,代碼減少了一半。 雙端統一,包括接口和設計上的統一。 支援打開Flutter頁面,不再打開容器場景。 頁面生命周期變化通知更友善業務使用。 * 解決了2.0中的遺留問題,例如,Fragment接入困難、頁面關閉後不能傳遞資料、dispose不執行,記憶體占用過高等。
架構圖

FlutterBoost插件分為平台和Dart兩端,中間通過Message Channel連接配接。平台側提供了Flutter引擎的配置和管理、Native容器的建立/銷毀、頁面可見性變化通知,以及Flutter頁面的打開/關閉接口等。而Dart側除了提供類似原生Navigator的頁面導航接口的能力外,還負責Flutter頁面的路由管理
不入侵引擎
為了解決官方引擎複用引起的問題,FlutterBoost2.0拷貝了Flutter引擎Embedding層的一些代碼進行改造,這使得後期的更新成本極高。而FlutterBoost3.0采用繼承的方式擴充FlutterActivity/FlutterFragment等元件的能力,并且通過在适當時機給Dart側發送appIsResumed消息解決引擎複用時生命周期事件錯亂導緻的頁面卡死問題。FlutterBoost3.0 也相容最新的官方釋出的 Flutter 2.0。
不區分Androidx和Support分支
FlutterBoost2.0通過自己實作FlutterActivityAndFragmentDelegate.Host接口來擴充FlutterActivity和FlutterFragment的能力,而getLifecycle是必須實作的接口,這就導緻對androidx的依賴。 這也是為什麼FlutterBoostView的實作沒有被放入FlutterBoost3.0插件中的原因。而FlutterBoost3.0通過繼承的方式擴充FlutterActivity/FlutterFragment的能力的額外收益就是,可以做到不依賴androidx。
雙端設計統一,接口統一
很多Flutter開發者隻會一端,隻會Android 或者隻會IOS,但他需要接入雙端,是以雙端統一能降低他的 學習成本和接入成本。FlutterBoost3.0,在設計上 Android和IOS都做了對齊,特别接口上做到了參數級的對齊。
支援 “打開flutter頁面不再打開容器” 場景。
在很多場景下,Flutter 頁面跳轉Flutter 頁面,這個時候可以不需要再打開容器。不打開容器,能節省記憶體開銷。 在FlutterBoost3.0上,打開容器和不打開容器的差別表現在使用者接口上僅僅是withContainer參數是否為true就好。代碼如下:
InkWell(
child: Container(
color: Colors.yellow,
child: Text(
'打開外部路由',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => BoostNavigator.of().push("flutterPage",
arguments: <String, String>{'from': widget.uniqueId}),
),
InkWell(
child: Container(
color: Colors.yellow,
child: Text(
'打開内部路由',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => BoostNavigator.of().push("flutterPage",
withContainer: true,
arguments: <String, String>{'from': widget.uniqueId}),
)
生命周期的精準通知
在FlutterBoost2.0上,每個頁面都會收到頁面生命周期通知,而FlutterBoost3.0隻會通知頁面可見性實際發生了變化的頁面,接口也更符合flutter的設計。
Top Issue 解決
對于回報比較多的issue進行了統計和歸類,主要解決了以下issue
- 頁面關閉後參數的傳遞,之前隻有iOS支援,android不支援,目前在dart側實作,Ios 和Android 都支援
- 解決了Android 狀态欄字型和顔色問題。
- 解決了頁面回退willpopscope不起作用問題。
- 解決了不在棧頂的頁面也收到生命周期回調的問題
- 解決了多次setState耗性能問題。
- 提供了Framgent 多種接入方式的Demo,友善tab 場景的接入。
- 生命周期的回調代碼,可以使用者代碼裡面with的方式接入,使用更簡單。
- 全面簡化了,接入成本,包括 dart側,android側和ios
- 豐富了demo,包含了基本場景,友善使用者接入 和測試回歸。
FlutterBoost3.0 接入和使用
接入方式
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: 'v3.0-beta.3'
FlutterBoost的未來發展
後續會繼續做這3件事情:
- FlutterBoost3.0會繼續在單Engine方向完善和優化,讓他更穩定,支援更多場景。
- 持續和Flutter 官方溝通,包括能否支援FlutterEngineGroup在isolate層面的記憶體共享。
- 探索Flutter2.0 多engine方案下新的混合棧。