Flutter 多引擎渲染,在稿定 App 的實踐

語言: CN / TW / HK

大家好,第一次在社群發文章,文筆不好,多多諒解 ~

發這篇文章的原因主要是關於 multiple-flutters Flutter 多引擎的介紹也好,實踐也好,可參考的資源實在太少,包括官方的 issues 也沒很多有價值的資訊,前幾個月確實在坑的泥潭裡死去活來。但好在已經走出了一條羊腸小道,可供大家參考。

對於 Flutter 多引擎的優劣,筆者在這裡不多做介紹,只說最重要的一點:如果有 Native + Flutter 同一頁面混合佈局的需求(UI 一致性 / 降本增效),但又不能整個 App 或者整個頁面替換成 Flutter 的,可以考慮使用 FlutterEngineGroup(multiple-flutters)。

閒話少說,先看效果。

APP 展示

1660267286030.jpg

如上圖紅框處,即為4個不同引擎的 FlutterView,繪製在同一個 Native 佈局中。

篇幅有限,就不發影片了,有興趣的同學可以下載 “稿定設計” 來看下效果(不過還在 AB 放量階段,不一定能看到新版模版頁哈~)。

為什麼市面多引擎用的人那麼少?

multiple-flutters 絕對是 Flutter 的坑中之王

首先,Flutter 版本至少升級到 2.10+,才能有初步的 iOS / Android 多引擎同時佈局的可用性。 但建議升級到 Flutter 3+ ,2.5.3 ~ 2.10.5 版本中,iOS 有記憶體崩潰風險,詳細原因可以見同事發的這篇 解決 Flutter 引起的 iOS 記憶體崩潰問題

第一次渡劫歷程:

先是接入 FlutterEngineGroup 時發現,編譯沒有問題,但就是死活無法正常顯示 FlutterView,翻查了大量資料(也沒什麼有用的資料),跟 Flutter 官方 Demo 對比等方式,耗時2天,最後只能鎖定在 Flutter 版本或者 flutter_boost 的問題上,死馬當作活馬醫,直接硬幹升級 Flutter 到最新版(2.10.2)及相關依賴升級,發現 Debug 正常了 ...

再就是在打包 flutter Android 時又發現, flutter_boost 報錯,從 github issues 瞭解到,flutter_boost 並沒去支援 Flutter 2.10.x,且還有閃白屏問題。根據 issues 建議,2.8+版本上存在 Release 包不可用的問題,推薦降低到 2.5.3,這才總算是從 FlutterEngineGroup 初步落地的可行性坑中爬了出來。

因為 2.5.3 同時佈局多個 FlutterEngine (3 ~ 10 個不等),導致會發生 ANR 的現象,在尋找解決方案無果的情況下,嘗試升級到當時最新版本 Flutter 2.10.5 ,結果正常了

這在升級過程中還遇到另一個問題,筆者公司專案裡還有很多 flutter_boost 的實現,而 flutter_boost 由於某些原因(可以見他們的 issues) 不支援 Flutter 2.5.3 以上版本。那就還需 Fork 下 flutter_boost 進行修改才可正常使用。

FlutterEngineGroup 離實用太遠

  • 缺乏內部固定佈局方式,只能通過外部佈局位置大小來讓 FlutterView 自適應。
  • 通訊層極其繁瑣,從有限的 Demo 中看出需三端各自實現 Bridge Channel。橋方法通過“字串”作為對應型別,導致個性化開發維護成本非常高。
  • 應用場景狹窄,多 FlutterEngine 間只能通過 Native 互動通訊。
  • Flutter Debug 模式下多引擎 = 記憶體炸裂,要用 Flutter Release 才可以穩定正常到官方描述的 180K / Engine 的記憶體佔用效果

我們是怎麼做的

image.png

利用指令碼開發了一套 FGUIComponentAPI 工具鏈來連結 Native 與 Flutter UI 的關係。

  • 保證 Flutter 開發無感,對於 Flutter 來說,和通常一樣開發 UI,並可以在獨立除錯中直接驗證效果。
  • 保證 Native 開發無感,對於 Native 來說,只是直接引用使用源生類,無需關心其中實現,開箱即用。
  • 額外的帶來的好處就是天然的 UI 單元測試,並且只要 Flutter 一端驗證即可。

這裡特別說一下,內建了官方推薦的 pigeon 外掛來處理 model 傳輸的問題,但 pigeon 外掛執行起來效率不高,越多的元件執行起來就越慢,所以後面又增加了檔案對比跳過的功能來加速。後續考慮替換掉 pigeon,不用 dart 來實現,改用 python 就能解決效率問題。

image.png

在開發過程上,筆者使用 YAML 來定義 UI 元件,通過 FGUIComponentAPI 多向生成各類程式碼及服務。

image.png

上圖即為自動生成的開發文件,可以看到 Native 呼叫上是完全無感知的,右側的預覽頁面也是天然使用 Flutter 跨端 Web 的能力,直接把 Flutter Example 輸出在文件上。

還有多少坑

筆者也還在一步一踩。

比如市面上常見的 pub 也要慎用,特別是有跟 Native 互動的外掛,基本上都沒有考慮多引擎實現的。 舉個例子,常用的 flutter_cache_manager,它因為使用了 sqlite 資料庫做儲存,在多引擎同時佈局的情況下,Android 裝置可能會出現資料庫等待導致圖片快取寫入/讀取失敗的問題(當然可以通過定義 cachedKey 來指定使用不同的 db 來解決)。這其實也不是第三方庫的問題,而是多引擎市面真實使用的人太少的緣故,沒有需求就沒有市場。

image.png

可以看到筆者已經快踩完整個字母表了 ... 手動狗頭

篇幅有限,這裡不展開說明了,如果有需求的同學可以下方評論,人數多的話單獨開一篇來介紹如何優雅的避開其中的坑坑坑坑坑炕鈧錕燙燙燙

後續

在看到 Flutter3 更多的跨端潛力後,筆者公司後續會嘗試進一步將 Flutter UI 推向 Web 端,讓 WebApp 與 App 保持更多的 UI 一致性。

如果有同學對 FGUIComponentAPI 實現上有更多興趣的話,也可以下方留言評論,筆者會從公司程式碼中抽出能講的部分單獨開篇聊一下~