探索Flutter混合開發技術方案(下)——淺析Flutter Boost原理

2022-01-05 開水 Kais

好像拖延了兩個多月才更新博客,或許忙是理由,各種各樣的事情堆積起來似乎都處理不過來了,頭髮也白了一片。好不容易閒下來了,只想著狠狠睡一覺,睡醒了才想起來還有幾篇計劃要寫的博客。
對了,公眾號的名字改成了開水Kais,未來會更多地去聊一下人生的暢想,寫一些心情隨記,不再單單是寫技術類的文章。

上篇講了Native和Flutter端混合開發的交互方式,並由此引出了Flutter Boost的基本用法。本篇我們繼續對Flutter Boost進行深入了解。
在理解原理之前,我假設大家都對Flutter Boost的基本用法都已經了解,如果還沒有用過Flutter Boost,我建議大家先閱讀官方文檔以及看看example的代碼。
GitHub地址:https://github.com/alibaba/flutter_boost

概括一下,Flutter Boost在Android中使用的步驟如下:

調用FlutterBoost.singleton.registerPageBuilders註冊路由表FlutterBoost.singleton.addBoostNavigatorObserver註冊路由跳轉觀察者(可選)Flutter跳轉Android頁面:FlutterBoost.singleton.open(url)Android跳轉Flutter:Intent intent = BoostFlutterActivity.withNewEngine().url("url").params(params).build(context);

本篇將會從以下幾個點來深入理解Flutter Boost的機制:

⚠️:基於v1.17.1-hotfixes分支

Flutter Boost架構基礎架構圖

參考文檔《已開源|碼上用它開始Flutter混合開發——FlutterBoost》

我們從Flutter端和Android端來拆解Flutter Boost的整體架構。

Native層概念
Container:Native容器,平臺Controller,Activity,ViewController
Container Manager:容器的管理者
Adaptor:Flutter是適配層
Messaging:基於Channel的消息通信

Dart層概念
Container:Flutter用來容納Widget的容器,具體實現為Navigator的派生類
Container Manager:Flutter容器的管理,提供show,remove等Api
Coordinator: 協調器,接受Messaging消息,負責調用Container Manager的狀態管理
Messaging:基於Channel的消息通信

我把官方的架構圖細化了一下,加上自己的理解,重新整理出整體的架構圖如下:

上面為Native端的流程,以Android端為例(如不做特殊說明,以下內容皆以Android端的代碼為基準),Container即為BoostFlutterActivity或者FlutterFragment。按照Flutter Boost的設計理念,你可以把Container比作Webview,用來承載Flutter頁面。

Delegate主要負責FlutterView的創建,使用代理模式,將Container的共同邏輯解藕。

Native端和Flutter端通過MethodChannel通信,FlutterBoostPlugin負責method的調度。Native端的Container初始化完成後,會發送消息通知Flutter端展示頁面。

Flutter端的ContainerCoordinator負責消息處理,當接收到Native端展示頁面的消息後,FlutterContainerManager會創建BoostContainer,並根據路由找到相應頁面加載到BoostContainer中。

BoostContainerNative端加載容器

在Android側,結合項目的路由框架,然後定義Flutter跳轉的schema協議,比如flutter://page,當調用Router.openPage("flutter://page")時(假如你的路由框架是這麼設定的),路由層判定為跳轉Flutter頁面,則調用BoostFlutterActivity.withNewEngine().url("url").params(params).build(context)就可以打開Flutter頁面了。
我們從該入口方法開始,這裡其實就是創建並打開了BoostFlutterActivity。我們知道BoostFlutterActivity為Native容器,那麼問題來了,打開BoostFlutterActivity後是如何加載Flutter頁面的?很顯然,頁面的加載與Activity的生命周期相關,從Activity的onCreate開始,看看在BoostFlutterActivity整個加載過程中都做了哪些工作。

onCreate:在該方法中創建了FlutterActivityAndFragmentDelegate,最終調用到Delegate的onCreateView方法創建FlutterView。

FlutterActivityAndFragmentDelegate#onCreateView:在該方法中實例化了mSyncer,實力化對象為ContainerRecord,ContainerRecord實現了IContainerRecord、IOperateSyncer接口。ContainerRecord關聯了對應的Flutter頁面,將Native容器與Flutter容器的生命周期同步。

下面一張圖表示Native端容器啟動時,View的層級關係:

前面說過,mSyncer的實現類為ContainerRecord,當調用到ContainerRecord的onCreate()方法,可以看到最後還是通過mProxy執行了create()方法:


最終交給MethodChannelProxy代理類來調用與Flutter端通信的方法,MethodChannelProxy是ContainerRecord的內部類。以上步驟中就是執行了proxy的create()方法。可以看到這裡是調用了invokeChannelUnsafe方法,最終通過FlutterBoost.instance().channel().invokeMethod調用Plugin層的方法與原生進行交互。

後面MethodChannel的調用流程不細述,我們可以追著代碼看到原生端的方法是如何被調用的。

Flutter端加載流程:

簡單來說,從Flutter側執行FlutterBoost.open方法打開頁面到FlutterBoost容器打開這個過程,主要經歷了以下階段:

單引擎模式

《已開源|碼上用它開始Flutter混合開發——FlutterBoost》 文中講到Flutter Boost主要解決的一個痛點就是在混合棧模式下多頁面跳轉時,Flutter底層會創建多個引擎從而導致內存暴增的問題。因此Flutter Boost解決該問題的思路為:

閒魚目前採用的混合方案是共享同一個引擎的方案。這個方案基於這樣一個事實:任何時候我們最多只能看到一個頁面,當然有些特定的場景你可以看到多個ViewController,但是這些特殊場景我們這裡不討論。我們可以這樣簡單去理解這個方案:我們把共享的Flutter View當成一個畫布,然後用一個Native的容器作為邏輯的頁面。每次在打開一個容器的時候我們通過通信機制通知Flutter View繪製成當前的邏輯頁面,然後將Flutter View放到當前容器裡面。

其實看到這裡,我們大概也能猜到Flutter Boost的實際就是在實現一個類似於WebContainer的容器,所有Flutter的頁面都在該容器中進行渲染展示。

最後

我們已經梳理了Flutter Boost的基本架構和核心流程,但是由於文章篇幅的原因,無法在一篇文章中詳細地整理所有源碼的內容,只能列出幾個核心的關鍵方法,大家可以嘗試自己看著源碼再梳理一遍流程,理解其原理,其實最重要的是了解該框架的設計思路。
在寫這篇文章之前,我是剛開始接觸到Flutter混合項目的開發才了解到Flutter Boost這個框架,剛開始使用這個框架的時候官方文檔並沒有完善,很多時候都得靠自己去閱讀源碼尋找問題解決的方法,並苦於各種奇奇怪怪的問題導致項目中四處碰壁,因此我對於Flutter Boost這個框架一直抱以比較排斥的態度。幾天前看到官方發布了3.0的版本,我對這個框架又恢復了一些信心,至少可以看到阿里對於這個開源庫的態度是真心地想要發展起來並以此來解決大部分的混合棧場景的。

v3.0-beta.1
1.flutter sdk升級不需要升級boost
2.簡化架構
3.簡化接口
4.雙端接口設計統一
5.解決了top issue
6.android不需要區分androidx 和support

但是我們真的需要Flutter Boost嗎?剛開始我選擇Flutter Boost的初衷是為了解決多引擎模式下導致的內存問題,可是在使用的過程中遇到的種種問題,最終不得不放棄該框架。
其實為了解決多引擎模式下多Engine導致的內存問題,官方是有提供解決方案的:使用緩存的 FlutterEngine  https://flutter.cn/docs/development/add-to-app/android/add-flutter-screen?tab=cached-engine-activity-launch-kotlin-tab#step-3-optional-use-a-cached-flutterengine

每一個 FlutterActivity 默認會創建它自己的 FlutterEngine。每一個 FlutterEngine 會有一個明顯的預熱時間。這意味著加載一個標準的 FlutterActivity 時,在你的 Flutter 交互頁面可見之前會有一個短暫的延遲。想要最小化這個延遲時間,你可以在抵達你的 FlutterActivity 之前,初始化一個 FlutterEngine,然後使用這個已經預熱好的 FlutterEngine。

在1.26版本之後,官方還提供了FlutterEngineGroup這個API來創建Flutter Engine:多個 Flutter 頁面或視圖  https://flutter.cn/docs/development/add-to-app/multiple-flutters

目前在 Android 和 iOS 上,除了第一個 Flutter 實例以外,其他每一個實例的內存佔用量大約為 180kB。

Flutter官方一直在傾聽開發者的訴求(針對混合棧開發的問題,官方開了一個問題集:issues#72009 https://github.com/flutter/flutter/issues/72009 ),這一點是我堅持學習Flutter的原因,也正因如此我對Flutter的未來是充滿信心的。

至此,探索Flutter Boost框架到此就告一段落了,我欣賞該框架的設計思路,但由於種種問題,我可能並不會在項目中選擇使用Flutter Boost,而會考慮基於Flutter自身的框架去實現混合棧架構,因為其相較於自主實現View容器的Flutter boost穩定得多。

相關焦點

  • 已開源|碼上用它開始Flutter混合開發——FlutterBoost
    每次在打開一個容器的時候我們通過通信機制通知Flutter View繪製成當前的邏輯頁面,然後將Flutter View放到當前容器裡面。這個方案無法支持同時存在多個平級邏輯頁面的情況,因為你在頁面切換的時候必須從棧頂去操作,無法再保持狀態的同時進行平級切換。舉個例子:有兩個頁面A,B,當前B在棧頂。
  • FlutterBoost1.0到2.0,我一共做了這幾件事...
    頁面白屏或黑屏FlutterBoost1.0受限於Flutter的架構,出於節省內存的考慮,全局只有一個FlutterViewController。同時在混合頁面滑動切換的時候,為了快速顯示上一個頁面並實現原生頁面切換的效果,採用CPU截圖的方式為每個頁面保存了打底圖。打底圖通過文件和內存二級緩存的方式避免持有多張圖片的內存問題。
  • Flutter 原理及美團實踐
    Flutter 是Google開發的一套全新的跨平臺、開源UI框架,支持iOS、Android系統開發,並且是未來新作業系統Fuchsia的默認開發套件。在Flutter誕生之前,已經有許多跨平臺UI框架的方案,比如基於WebView的Cordova、AppCan等,還有使用HTML+JavaScript渲染成原生控制項的React Native、Weex等。
  • Flutter 完整開發實戰詳解 (Flutter 畫面渲染的全面解析) | 開發者說·DTalk
    ,深入剖析 Flutter 中構成 Layer 後的繪製流程,讓開發者對 Flutter 的渲染原理和實現邏輯有更清晰的認知。先回顧下,我們知道在 Flutter 中的控制項會經歷 Widget -> Element -> RenderObject -> Layer 這樣的變化過程,而其中 Layer 的組成由 RenderObject 中的 isRepaintBoundary 標誌位決定。
  • Flutter 開發從 0 到 1(六)Markdown 與代碼高亮
    《Fluuter 開發從 0 到 1》博客詳情是 Markdown,今天就來說說 Flutter Markdown 如何實現的。先劇透下,今天的主角是 flutter_markdown,可以實現從使用簡單的 Markdown 標記格式化的純文本數據創建富文本輸出,包括文本樣式,表格,連結等。
  • 愛奇藝開播助手Flutter跨平臺Hybrid實踐
    如果你對 HotReload 原理感興趣,可以移步 Flutter 官網進一步了解 HotReload:,'flutter_liveshow/.android/include_flutter.groovy'))使用aar接入Android使用aar接入Flutter十分的簡單,只用下面兩步就可以順利的將使用Flutter開發的界面接入原生的工程。
  • flutter逆向演練
    目前來說的話,flutter app的逆向一直是個比較困難的問題,在app的lib目錄下會有個libapp.so文件,裡面存放的即是app運行的核心代碼,用ida來看看Data和Instructions,Flutter編譯運行在app上分為JIT和AOT模式(編譯模式)JIT模式:即Just-in-time,動態(即時)編譯,邊運行邊編譯;安卓在2.2版本引入此技術,主要是用來提高程序的執行效率的。對於會多次執行到的代碼(可以理解為多次調用到的函數),JIT會將其編譯成機器碼。下次再執行此代碼時就直接調用機器碼,提升執行效率。
  • Flutter - 不聽話的 Container
    前言在閱讀本文之前我們先來回顧下在 Flutter 開發過程中,是不是經常會遇到以下問題:•Container 設置了寬高無效•Column
  • 半小時帶你入門 Flutter
    國慶後面兩天在家學習整理了一波flutter,基本把能擼過能看到的代碼都過了一遍,此文篇幅較長,建議保存(star)再看。Questions tagged [flutter]img本文我們從介紹flutter基本概念到梳理常用Widget到常用app demos編寫到~放棄~,希望可以幫助每一個像我一樣的初學者。有誤地方還望大神不吝賜教~
  • Flutter項目實戰:編寫一個非常精美的Flutter Todo-List項目
    下面就我來帶領各位參觀參觀這個項目的內部構造第三方庫項目中使用了一些非常優秀的第三方庫,也特別感謝這些開發者們,讓我的發量保持健康下面就是這些控制項的信息控制項說明dio網絡請求shared_preferences本地存儲provider狀態管理test單元測試carousel_slider滑動控制項circle_list環形列表intlintl語言包sqflite本地資料庫flutter_colorpicker
  • Flutter竟然還有這種高端用法?
    https://juejin.im/user/2840793776393847首先,有很多的文章在說flutter bloc模式的應用,但是百分之八九十的文章都是在說,使用StreamController+StreamBuilder搭建bloc,提升性能的會加上InheritedWidget,這些文章看了很多,真正寫使用bloc作者開發的flutter_bloc卻少之又少。
  • 編寫一個非常精美的Flutter Todo-List項目
    下面就我來帶領各位參觀參觀這個項目的內部構造第三方庫項目中使用了一些非常優秀的第三方庫,也特別感謝這些開發者們,讓我的發量保持健康下面就是這些控制項的信息控制項說明dio網絡請求shared_preferences本地存儲provider狀態管理test單元測試carousel_slider滑動控制項circle_list環形列表intlintl語言包sqflite本地資料庫flutter_colorpicker
  • 用前端最舒服的躺姿 "搞定" Flutter
    當下最火的跨端技術,當屬於 Flutter ,應該沒人質疑吧。一個新的技術的趨勢,最明顯的特徵,就是它一定想把「前浪」拍死在沙灘上。
  • 深入理解Flutter的圖形圖像繪製原理——圖形庫skia剖析
    Skia支持多種軟硬體平臺,既支持ARM和x86指令集,也支持OpenGL、Metal和Vulkan低級圖形接口。skia GPU渲染流程如下:1)發起繪圖,先調用SKCanvas的繪圖函數drawRect,傳入左上角和右下角頂點坐標。
  • Flutter Widget - Container 布局詳解
    介紹Container 初用起來很簡單,但是裡面的邏輯又有些複雜,我也不敢說完全吃透,所以本文還是以總結網上各種文章為主,再加上自己的理解,如果有不對的地方,請一定指出在 Flutter 中,所有的功能都被分散成單一功能的 Widget,比如居中有 Center,邊框有 Padding,文字是 Text,手勢是 GestureDetector,他們各自維護一個功能,但是我們商業
  • 2020年20個Flutter最漂亮的UI庫和項目
    flutter_swiper 地址:https://github.com/best-flutter/flutter_swiperflutter-ui-nice 地址:https://github.com/nb312/flutter-ui-nice
  • flutter實現簡單的旋轉動畫
    前言flutter實現簡單的旋轉動畫,和大家一起學習探討。
  • APP 開發從 0 到 1(一)需求與準備
    APP 開發有個特點,技術更新太快,後面新出來的 Kotlin、Flutter 我都有試水,但都沒有實際項目操作,現在大家是不是都在用 Flutter 開發 APP 了吧?從零開發 APP 本想還用 Java 開發,這似乎沒什麼挑戰性,還是用 Flutter 玩下吧。需求既然是從零開發 APP,問題來了,要做成什麼樣子的 APP 呢?好的,產品經理即刻上身,現在開發者社區質量愈發下降,好的技術文章愈發的少,做個 APP,每天精選一篇優秀文章,樣式布局跟公眾號一樣就好。
  • 通過與React的簡單對比來入門Flutter
    作者 | ELab.lijianye出品 | ELab團隊(ID:gh_b1857b91fe44)Flutter簡介Flutter是谷歌開源的移動端應用開發框架,採用Dart語言作為開發語言,主要的特點是跨平臺,高性能,高保真。
  • 從Container尺寸之謎看Flutter的渲染規則
    在不設置Container寬高的前提下,如果Container沒有Child,那麼它的尺寸是多少?在不設置Container寬高的前提下,如果Container有Child,那麼它的尺寸又是多少?如果Container有Child,且設置了Alignment,那麼它的尺寸又是多少?