今天小編給大家分享一下Flutter混合開(kāi)發(fā)的方法是什么的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來(lái)了解一下吧。
為什么要混合方案
具有一定規(guī)模的App通常有一套成熟通用的基礎(chǔ)庫(kù),尤其是阿里系A(chǔ)pp,一般需要依賴很多體系內(nèi)的基礎(chǔ)庫(kù)。那么使用Flutter重新從頭開(kāi)發(fā)App的成本和風(fēng)險(xiǎn)都較高。所以在Native App進(jìn)行漸進(jìn)式遷移是Flutter技術(shù)在現(xiàn)有Native App進(jìn)行應(yīng)用的穩(wěn)健型方式。
閑魚(yú)在實(shí)踐中沉淀出一套自己的混合技術(shù)方案。在此過(guò)程中,我們跟Google Flutter團(tuán)隊(duì)進(jìn)行著密切的溝通,聽(tīng)取了官方的一些建議,同時(shí)也針對(duì)我們業(yè)務(wù)具體情況進(jìn)行方案的選型以及具體的實(shí)現(xiàn)。
官方提出的混合方案
1 基本原理Flutter技術(shù)鏈主要由C++實(shí)現(xiàn)的Flutter Engine和Dart實(shí)現(xiàn)的Framework組成(其配套的編譯和構(gòu)建工具我們這里不參與討論)。Flutter Engine負(fù)責(zé)線程管理,Dart VM狀態(tài)管理和Dart代碼加載等工作。而Dart代碼所實(shí)現(xiàn)的Framework則是業(yè)務(wù)接觸到的主要API,諸如Widget等概念就是在Dart層面Framework內(nèi)容。
一個(gè)進(jìn)程里面最多只會(huì)初始化一個(gè)Dart VM。然而一個(gè)進(jìn)程可以有多個(gè)Flutter Engine,多個(gè)Engine實(shí)例共享同一個(gè)Dart VM。
我們來(lái)看具體實(shí)現(xiàn),在iOS上面每初始化一個(gè)FlutterViewController就會(huì)有一個(gè)引擎隨之初始化,也就意味著會(huì)有新的線程(理論上線程可以復(fù)用)去跑Dart代碼。Android類似的Activity也會(huì)有類似的效果。如果你啟動(dòng)多個(gè)引擎實(shí)例,注意此時(shí)Dart VM依然是共享的,只是不同Engine實(shí)例加載的代碼跑在各自獨(dú)立的Isolate。
2 官方建議引擎深度共享
在混合方案方面,我們跟Google討論了可能的一些方案。Flutter官方給出的建議是從長(zhǎng)期來(lái)看,我們應(yīng)該支持在同一個(gè)引擎支持多窗口繪制的能力,至少在邏輯上做到FlutterViewController是共享同一個(gè)引擎的資源的。換句話說(shuō),我們希望所有繪制窗口共享同一個(gè)主Isolate。
但官方給出的長(zhǎng)期建議目前來(lái)說(shuō)沒(méi)有很好的支持。
多引擎模式
我們?cè)诨旌戏桨钢薪鉀Q的主要問(wèn)題是如何去處理交替出現(xiàn)的Flutter和Native頁(yè)面。Google工程師給出了一個(gè)Keep It Simple的方案:對(duì)于連續(xù)的Flutter頁(yè)面(Widget)只需要在當(dāng)前FlutterViewController打開(kāi)即可,對(duì)于間隔的Flutter頁(yè)面我們初始化新的引擎。
例如,我們進(jìn)行下面一組導(dǎo)航操作:
Flutter Page1 -> Flutter Page2 -> Native Page1 -> Flutter Page3
我們只需要在Flutter Page1和Flutter Page3創(chuàng)建不同的Flutter實(shí)例即可。
這個(gè)方案的好處就是簡(jiǎn)單易懂,邏輯清晰,但是也有潛在的問(wèn)題。如果一個(gè)Native頁(yè)面一個(gè)Flutter 頁(yè)面一直交替進(jìn)行的話,F(xiàn)lutter Engine的數(shù)量會(huì)線性增加,而Flutter Engine本身是一個(gè)比較重的對(duì)象。
多引擎模式的問(wèn)題
冗余的資源問(wèn)題.多引擎模式下每個(gè)引擎之間的Isolate是相互獨(dú)立的。在邏輯上這并沒(méi)有什么壞處,但是引擎底層其實(shí)是維護(hù)了圖片緩存等比較消耗內(nèi)存的對(duì)象。想象一下,每個(gè)引擎都維護(hù)自己一份圖片緩存,內(nèi)存壓力將會(huì)非常大。
插件注冊(cè)的問(wèn)題。插件依賴Messenger去傳遞消息,而目前Messenger是由FlutterViewController(Activity)去實(shí)現(xiàn)的。如果你有多個(gè)FlutterViewController,插件的注冊(cè)和通信將會(huì)變得混亂難以維護(hù),消息的傳遞的源頭和目標(biāo)也變得不可控。
Flutter Widget和Native的頁(yè)面差異化問(wèn)題。Flutter的頁(yè)面是Widget,Native的頁(yè)面是VC。邏輯上來(lái)說(shuō)我們希望消除Flutter頁(yè)面與Naitve頁(yè)面的差異,否則在進(jìn)行頁(yè)面埋點(diǎn)和其它一些統(tǒng)一操作的時(shí)候都會(huì)遇到額外的復(fù)雜度。
增加頁(yè)面之間通信的復(fù)雜度。如果所有Dart代碼都運(yùn)行在同一個(gè)引擎實(shí)例,它們共享一個(gè)Isolate,可以用統(tǒng)一的編程框架進(jìn)行Widget之間的通信,多引擎實(shí)例也讓這件事情更加復(fù)雜。
因此,綜合多方面考慮,我們沒(méi)有采用多引擎混合方案。
現(xiàn)狀及思考
前面我們提到多引擎存在一些實(shí)際問(wèn)題,所以閑魚(yú)目前采用的混合方案是共享同一個(gè)引擎的方案。這個(gè)方案基于這樣一個(gè)事實(shí):任何時(shí)候我們最多只能看到一個(gè)頁(yè)面,當(dāng)然有些特定的場(chǎng)景你可以看到多個(gè)ViewController,但是這些特殊場(chǎng)景我們這里不討論。
我們可以這樣簡(jiǎn)單去理解這個(gè)方案:我們把共享的Flutter View當(dāng)成一個(gè)畫(huà)布,然后用一個(gè)Native的容器作為邏輯的頁(yè)面。每次在打開(kāi)一個(gè)容器的時(shí)候我們通過(guò)通信機(jī)制通知Flutter View繪制成當(dāng)前的邏輯頁(yè)面,然后將Flutter View放到當(dāng)前容器里面。
這個(gè)方案無(wú)法支持同時(shí)存在多個(gè)平級(jí)邏輯頁(yè)面的情況,因?yàn)槟阍陧?yè)面切換的時(shí)候必須從棧頂去操作,無(wú)法再保持狀態(tài)的同時(shí)進(jìn)行平級(jí)切換。舉個(gè)例子:有兩個(gè)頁(yè)面A,B,當(dāng)前B在棧頂。切換到A需要把B從棧頂Pop出去,此時(shí)B的狀態(tài)丟失,如果想切回B,我們只能重新打開(kāi)B之前頁(yè)面的狀態(tài)無(wú)法維持住。
如在pop的過(guò)程當(dāng)中,可能會(huì)把Flutter 官方的Dialog進(jìn)行誤殺。而且基于棧的操作我們依賴對(duì)Flutter框架的一個(gè)屬性修改,這讓這個(gè)方案具有了侵入性的特點(diǎn)。
新一代混合技術(shù)方案 FlutterBoost
1 重構(gòu)計(jì)劃在閑魚(yú)推進(jìn)Flutter化過(guò)程當(dāng)中,更加復(fù)雜的頁(yè)面場(chǎng)景逐漸暴露了老方案的局限性和一些問(wèn)題。所以我們啟動(dòng)了代號(hào)FlutterBoost(向C++ Boost庫(kù)致敬)的新混合技術(shù)方案。這次新的混合方案我們的主要目標(biāo)有:
可復(fù)用通用型混合方案
支持更加復(fù)雜的混合模式,比如支持主頁(yè)Tab這種情況
無(wú)侵入性方案:不再依賴修改Flutter的方案
支持通用頁(yè)面生命周期
統(tǒng)一明確的設(shè)計(jì)概念
跟老方案類似,新的方案還是采用共享引擎的模式實(shí)現(xiàn)。主要思路是由Native容器Container通過(guò)消息驅(qū)動(dòng)Flutter頁(yè)面容器Container,從而達(dá)到Native Container與Flutter Container的同步目的。我們希望做到Flutter渲染的內(nèi)容是由Naitve容器去驅(qū)動(dòng)的。
簡(jiǎn)單的理解,我們想做到把Flutter容器做成瀏覽器的感覺(jué)。填寫(xiě)一個(gè)頁(yè)面地址,然后由容器去管理頁(yè)面的繪制。在Native側(cè)我們只需要關(guān)心如果初始化容器,然后設(shè)置容器對(duì)應(yīng)的頁(yè)面標(biāo)志即可。
2 主要概念3 Native層概念Container:Native容器,平臺(tái)Controller,Activity,ViewController
Container Manager:容器的管理者
Adaptor:Flutter是適配層
Messaging:基于Channel的消息通信
Container:Flutter用來(lái)容納Widget的容器,具體實(shí)現(xiàn)為Navigator的派生類-
Container Manager:Flutter容器的管理,提供show,remove等Api
Coordinator: 協(xié)調(diào)器,接受Messaging消息,負(fù)責(zé)調(diào)用Container Manager的狀態(tài)管理。
Messaging:基于Channel的消息通信
在Native和Flutter表示頁(yè)面的對(duì)象和概念是不一致的。在Native,我們對(duì)于頁(yè)面的概念一般是ViewController,Activity。而對(duì)于Flutter我們對(duì)于頁(yè)面的概念是Widget。我們希望可統(tǒng)一頁(yè)面的概念,或者說(shuō)弱化抽象掉Flutter本身的Widget對(duì)應(yīng)的頁(yè)面概念。換句話說(shuō),當(dāng)一個(gè)Native的頁(yè)面容器存在的時(shí)候,F(xiàn)lutteBoost保證一定會(huì)有一個(gè)Widget作為容器的內(nèi)容。所以我們?cè)诶斫夂瓦M(jìn)行路由操作的時(shí)候都應(yīng)該以Native的容器為準(zhǔn),F(xiàn)lutter Widget依賴于Native頁(yè)面容器的狀態(tài)。
那么在FlutterBoost的概念里說(shuō)到頁(yè)面的時(shí)候,我們指的是Native容器和它所附屬的Widget。所有頁(yè)面路由操作,打開(kāi)或者關(guān)閉頁(yè)面,實(shí)際上都是對(duì)Native頁(yè)面容器的直接操作。無(wú)論路由請(qǐng)求來(lái)自何方,最終都會(huì)轉(zhuǎn)發(fā)給Native去實(shí)現(xiàn)路由操作。這也是接入FlutterBoost的時(shí)候需要實(shí)現(xiàn)Platform協(xié)議的原因。
另一方面,我們無(wú)法控制業(yè)務(wù)代碼通過(guò)Flutter本身的Navigator去push新的Widget。對(duì)于業(yè)務(wù)不通過(guò)FlutterBoost而直接使用Navigator操作Widget的情況,包括Dialog這種非全屏Widget,我們建議是業(yè)務(wù)自己負(fù)責(zé)管理其狀態(tài)。這種類型Widget不屬于FlutterBoost所定義的頁(yè)面概念。
理解這里的頁(yè)面概念,對(duì)于理解和使用FlutterBoost至關(guān)重要。
6 與老方案主要差別前面我們提到老方案在Dart層維護(hù)單個(gè)Navigator棧結(jié)構(gòu)用于Widget的切換。而新的方案則是在Dart側(cè)引入了Container的概念,不再用棧的結(jié)構(gòu)去維護(hù)現(xiàn)有的頁(yè)面,而是通過(guò)扁平化key-value映射的形式去維護(hù)當(dāng)前所有的頁(yè)面,每個(gè)頁(yè)面擁有一個(gè)唯一的id。這種結(jié)構(gòu)很自然的支持了頁(yè)面的查找和切換,不再受制于棧頂操作的問(wèn)題,之前的一些由于pop導(dǎo)致的問(wèn)題迎刃而解。也不需要依賴修改Flutter源碼的形式去進(jìn)行頁(yè)面棧操作,去掉了實(shí)現(xiàn)的侵入性。
實(shí)際上我們引入的Container就是Navigator的,也就是說(shuō)一個(gè)Native的容器對(duì)應(yīng)了一個(gè)Navigator。那這是如何做到的呢?
7 多Navigator的實(shí)現(xiàn)Flutter在底層提供了讓你自定義Navigator的接口,我們自己實(shí)現(xiàn)了一個(gè)管理多個(gè)Navigator的對(duì)象。當(dāng)前最多只會(huì)有一個(gè)可見(jiàn)的Flutter Navigator,這個(gè)Navigator所包含的頁(yè)面也就是我們當(dāng)前可見(jiàn)容器所對(duì)應(yīng)的頁(yè)面。
Native容器與Flutter容器(Navigator)是一一對(duì)應(yīng)的,生命周期也是同步的。當(dāng)一個(gè)Native容器被創(chuàng)建的時(shí)候,F(xiàn)lutter的一個(gè)容器也被創(chuàng)建,它們通過(guò)相同的id關(guān)聯(lián)起來(lái)。當(dāng)Native的容器被銷毀的時(shí)候,F(xiàn)lutter的容器也被銷毀。Flutter容器的狀態(tài)是跟隨Native容器,這也就是我們說(shuō)的Native驅(qū)動(dòng)。由Manager統(tǒng)一管理切換當(dāng)前在屏幕上展示的容器。
我們用一個(gè)簡(jiǎn)單的例子描述一個(gè)新頁(yè)面創(chuàng)建的過(guò)程:
創(chuàng)建Native容器(iOS ViewController,Android Activity or Fragment)。
Native容器通過(guò)消息機(jī)制通知Flutter Coordinator新的容器被創(chuàng)建。
Flutter Container Manager進(jìn)而得到通知,負(fù)責(zé)創(chuàng)建出對(duì)應(yīng)的Flutter容器,并且在其中裝載對(duì)應(yīng)的Widget頁(yè)面。
當(dāng)Native容器展示到屏幕上時(shí),容器發(fā)消息給Flutter Coordinator通知要展示頁(yè)面的id.
Flutter Container Manager找到對(duì)應(yīng)id的Flutter Container并將其設(shè)置為前臺(tái)可見(jiàn)容器。
這就是一個(gè)新頁(yè)面創(chuàng)建的主要邏輯,銷毀和進(jìn)入后臺(tái)等操作也類似有Native容器事件去進(jìn)行驅(qū)動(dòng)。
總結(jié)
目前FlutterBoost已經(jīng)在生產(chǎn)環(huán)境支撐著在閑魚(yú)客戶端中所有的基于Flutter開(kāi)發(fā)業(yè)務(wù),為更加負(fù)復(fù)雜的混合場(chǎng)景提供了支持,穩(wěn)定為億級(jí)用戶提供服務(wù)。
我們?cè)陧?xiàng)目啟動(dòng)之初就希望FlutterBoost能夠解決Native App混合模式接入Flutter這個(gè)通用問(wèn)題。所以我們把它做成了一個(gè)可復(fù)用的Flutter插件,希望吸引更多感興趣的朋友參與到Flutter社區(qū)的建設(shè)。在有限篇幅中,我們分享了閑魚(yú)在Flutter混合技術(shù)方案中積累的經(jīng)驗(yàn)和代碼。歡迎興趣的同學(xué)能夠積極與我們一起交流學(xué)習(xí)。
擴(kuò)展補(bǔ)充
在兩個(gè)Flutter頁(yè)面進(jìn)行切換的時(shí)候,因?yàn)槲覀冎挥幸粋€(gè)Flutter View所以需要對(duì)上一個(gè)頁(yè)面進(jìn)行截圖保存,如果Flutter頁(yè)面多截圖會(huì)占用大量?jī)?nèi)存。這里我們采用文件內(nèi)存二級(jí)緩存策略,在內(nèi)存中最多只保存2-3個(gè)截圖,其余的寫(xiě)入文件按需加載。這樣我們可以在保證用戶體驗(yàn)的同時(shí)在內(nèi)存方面也保持一個(gè)較為穩(wěn)定的水平。
頁(yè)面渲染性能方面,F(xiàn)lutter的AOT優(yōu)勢(shì)展露無(wú)遺。在頁(yè)面快速切換的時(shí)候,F(xiàn)lutter能夠很靈敏的相應(yīng)頁(yè)面的切換,在邏輯上創(chuàng)造出一種Flutter多個(gè)頁(yè)面的感覺(jué)。
2 Release1.0的支持項(xiàng)目開(kāi)始的時(shí)候我們基于閑魚(yú)目前使用的Flutter版本進(jìn)行開(kāi)發(fā),而后進(jìn)行了Release 1.0兼容升級(jí)測(cè)試目前沒(méi)有發(fā)現(xiàn)問(wèn)題。
3 接入只要是集成了Flutter的項(xiàng)目都可以用官方依賴的方式非常方便的以插件形式引入FlutterBoost,只需要對(duì)工程進(jìn)行少量代碼接入即可完成接入。以上就是“Flutter混合開(kāi)發(fā)的方法是什么”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道。
網(wǎng)站題目:Flutter混合開(kāi)發(fā)的方法是什么-創(chuàng)新互聯(lián)
分享URL:http://www.rwnh.cn/article32/dohgsc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動(dòng)態(tài)網(wǎng)站、自適應(yīng)網(wǎng)站、用戶體驗(yàn)、網(wǎng)站建設(shè)、網(wǎng)站改版、云服務(wù)器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)