自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Flutter實(shí)現(xiàn)原理及在馬蜂窩的跨平臺開發(fā)實(shí)踐

開發(fā) 開發(fā)工具
在馬蜂窩旅游 App 很多業(yè)務(wù)場景里,我們嘗試過一些主流的跨平臺開發(fā)解決方案, 比如WebView 和 React Native,來提升開發(fā)效率和用戶體驗(yàn)。但這兩種方式也帶來了新的問題。

一直以來,跨平臺開發(fā)都是困擾移動(dòng)客戶端開發(fā)的難題。

在馬蜂窩旅游 App 很多業(yè)務(wù)場景里,我們嘗試過一些主流的跨平臺開發(fā)解決方案, 比如WebView 和 React Native,來提升開發(fā)效率和用戶體驗(yàn)。但這兩種方式也帶來了新的問題。

比如使用 WebView 跨平臺方式,優(yōu)點(diǎn)確實(shí)非常明顯?;?WebView 的框架集成了當(dāng)下 Web 開發(fā)的諸多優(yōu)勢:豐富的控件庫、動(dòng)態(tài)化、良好的技術(shù)社區(qū)、測試自動(dòng)化等等。但是缺點(diǎn)也同樣明顯:渲染效率和 JavaScript 的執(zhí)行能力都比較差,使頁面的加載速度和用戶體驗(yàn)都不盡如人意。

而使用以 React Native(簡稱 RN)為代表的框架時(shí),維護(hù)又成了大難題。RN 使用類 HTML+JS 的 UI 創(chuàng)建邏輯,生成對應(yīng)的原生頁面,將頁面的渲染工作交給了系統(tǒng),所以渲染效率有很大的優(yōu)勢。但由于 RN 代碼是通過 JS 橋接的方式轉(zhuǎn)換為原生的控件,所以受各個(gè)系統(tǒng)間的差異影響非常大,雖然可以開發(fā)一套代碼,但對各個(gè)平臺的適配卻非常的繁瑣和麻煩。

為什么是 Flutter

2018 年 12 月初,Google 正式發(fā)布了開源跨平臺 UI 框架 Flutter 1.0 Release 版本,馬蜂窩電商客戶端團(tuán)隊(duì)進(jìn)行了調(diào)研與實(shí)踐,發(fā)現(xiàn)Flutter能很好的幫助我們解決開發(fā)中遇到的問題。

  1. 跨平臺開發(fā),針對 Android 與 iOS 的風(fēng)格設(shè)計(jì)了兩套設(shè)計(jì)語言的控件實(shí)現(xiàn)(Material & Cupertino)。這樣不但能夠節(jié)約人力成本,而且在用戶體驗(yàn)上更好的適配 App 運(yùn)行的平臺。
  2. 重寫了一套跨平臺的 UI 框架,渲染引擎是依靠 Skia 圖形庫實(shí)現(xiàn)。Flutter 中的控件樹直接由渲染引擎和高性能本地 ARM 代碼直接繪制,不需要通過中間對象(Web 應(yīng)用中的虛擬 DOM 和真實(shí) DOM,原生 App 中的虛擬控件和平臺控件)來繪制,使它有接近原生頁面的性能,幫助我們提供更好的用戶體驗(yàn)。
  3. 同時(shí)支持 JIT 和 AOT 編譯。JIT編譯方式使其在開發(fā)階段有個(gè)備受歡迎的功能——熱重載(HotReload),這樣在開發(fā)時(shí)可以省去構(gòu)建的過程,提高開發(fā)效率。而在 Release 運(yùn)行階段采用 AOT 的編譯方式,使執(zhí)行效率非常高,讓 Release 版本發(fā)揮更好的性能。

于是,電商客戶端團(tuán)隊(duì)決定探索 Flutter 在跨平臺開發(fā)中的新可能,并率先應(yīng)用于商家端 App 中。在本文中,我們將結(jié)合 Flutter 在馬蜂窩商家端 App 中的應(yīng)用實(shí)踐,探討 Flutter 架構(gòu)的實(shí)現(xiàn)原理,有何優(yōu)勢,以及如何幫助我們解決問題。

Flutter 架構(gòu)和實(shí)現(xiàn)原理

Flutter 使用 Dart 語言開發(fā),主要有以下幾點(diǎn)原因:

  • Dart 一般情況下是運(yùn)行 DartVM 上,但是也可以編譯為 ARM 代碼直接運(yùn)行在硬件上。
  • Dart 同時(shí)支持 AOT 和 JIT 兩種編譯方式,可以更好的提高開發(fā)以及 App 的執(zhí)行效率。
  • Dart 可以利用獨(dú)特的隔離區(qū)(Isolate)實(shí)現(xiàn)多線程。而且不共享內(nèi)存,可以實(shí)現(xiàn)無鎖快速分配。
  • 分代垃圾回收,非常適合 UI 框架中常見的大量 Widgets 對象創(chuàng)建和銷毀的優(yōu)化。
  • 在為創(chuàng)建的對象分配內(nèi)存時(shí),Dart 是在現(xiàn)有的堆上移動(dòng)指針,保證內(nèi)存的增長是程線性的,于是就省了查找可用內(nèi)存的過程。

Dart 主要由 Google 負(fù)責(zé)開發(fā)和維護(hù)。目前 Dart 新版本已經(jīng)是 2.2,針對 App 和 Web 開發(fā)做了很多優(yōu)化。并且對于大多數(shù)的開發(fā)者而言,Dart 的學(xué)習(xí)成本非常低。

Flutter 架構(gòu)也是采用的分層設(shè)計(jì)。從下到上依次為:Embedder(嵌入器)、Engine、Framework。

圖1: Flutter 分層架構(gòu)圖

Embedder 是嵌入層,做好這一層的適配 Flutter 基本可以嵌入到任何平臺上去;

Engine 層主要包含 Skia、Dart 和 Text。Skia 是開源的二位圖形庫;Dart 部分主要包括 runtime、Garbage Collection、編譯模式支持等;Text 是文本渲染。

Framework 在最上層。我們的應(yīng)用圍繞 Framework 層來構(gòu)建,因此也是本文要介紹的重點(diǎn)。

Framework

1.【Foundation】在底層,主要定義底層工具類和方法,以提供給其他層使用。

2.【Animation】是動(dòng)畫相關(guān)的類,可以基于此創(chuàng)建補(bǔ)間動(dòng)畫(Tween Animation)和物理原理動(dòng)畫(Physics-based Animation),類似 Android 的 ValueAnimator 和 iOS 的 Core Animation。

3.【Painting】封裝了 Flutter Engine 提供的繪制接口,例如繪制縮放圖像、插值生成陰影、繪制盒模型邊框等。

4.【Gesture】提供處理手勢識別和交互的功能。

5.【Rendering】是框架中的渲染庫??丶匿秩局饕ㄈ齻€(gè)階段:布局(Layout)、繪制(Paint)、合成(Composite)。

從下圖可以看到,F(xiàn)lutter 流水線包括 7 個(gè)步驟。

圖2: Flutter 流水線

首先是獲取到用戶的操作,然后你的應(yīng)用會因此顯示一些動(dòng)畫,接著 Flutter 開始構(gòu)建 Widget 對象。

Widget 對象構(gòu)建完成后進(jìn)入渲染階段,這個(gè)階段主要包括三步:

  • 布局元素:決定頁面元素在屏幕上的位置和大小;
  • 繪制階段:將頁面元素繪制成它們應(yīng)有的樣式;
  • 合成階段:按照繪制規(guī)則將之前兩個(gè)步驟的產(chǎn)物組合在一起。

末尾的光柵化由 Engine 層來完成。

在渲染階段,控件樹(widget)會轉(zhuǎn)換成對應(yīng)的渲染對象(RenderObject)樹,在 Rendering 層進(jìn)行布局和繪制。

在布局時(shí) Flutter 深度優(yōu)先遍歷渲染對象樹。數(shù)據(jù)流的傳遞方式是從上到下傳遞約束,從下到上傳遞大小。也就是說,父節(jié)點(diǎn)會將自己的約束傳遞給子節(jié)點(diǎn),子節(jié)點(diǎn)根據(jù)接收到的約束來計(jì)算自己的大小,然后將自己的尺寸返回給父節(jié)點(diǎn)。整個(gè)過程中,位置信息由父節(jié)點(diǎn)來控制,子節(jié)點(diǎn)并不關(guān)心自己所在的位置,而父節(jié)點(diǎn)也不關(guān)心子節(jié)點(diǎn)具體長什么樣子。

圖3: 數(shù)據(jù)流傳遞方式

為了防止因子節(jié)點(diǎn)發(fā)生變化而導(dǎo)致的整個(gè)控件樹重繪,F(xiàn)lutter 加入了一個(gè)機(jī)制——Relayout Boundary,在一些特定的情形下Relayout Boundary會被自動(dòng)創(chuàng)建,不需要開發(fā)者手動(dòng)添加。

例如,控件被設(shè)置了固定大小(tight constraint)、控件忽略所有子視圖尺寸對自己的影響、控件自動(dòng)占滿父控件所提供的空間等等。很好理解,就是控件大小不會影響其他控件時(shí),就沒必要重新布局整個(gè)控件樹。有了這個(gè)機(jī)制后,無論子樹發(fā)生什么樣的變化,處理范圍都只在子樹上。

圖4: Relayout Boundary 機(jī)制

在確定每個(gè)空間的位置和大小之后,就進(jìn)入繪制階段。繪制節(jié)點(diǎn)的時(shí)候也是深度遍歷繪制節(jié)點(diǎn)樹,然后把不同的 RenderObject 繪制到不同的圖層上。

這時(shí)有可能出現(xiàn)一種特殊情況,如下圖所示節(jié)點(diǎn) 2 在繪制子節(jié)點(diǎn) 4 時(shí),由于其節(jié)點(diǎn)4需要單獨(dú)繪制到一個(gè)圖層上(如 video),因此綠色的圖層上面多了個(gè)黃顏色的圖層。之后再需要繪制其他內(nèi)容(標(biāo)記 5)就需要再增加一個(gè)圖層(紅色)。再接下來要繪制節(jié)點(diǎn) 1 的右子樹(標(biāo)記 6),也會被繪制到紅色的圖層上。所以如果 2 號節(jié)點(diǎn)發(fā)生改變就會改變紅色的圖層上的內(nèi)容,因此也影響到了毫不相干的 6 號節(jié)點(diǎn)。

圖5: 繪制節(jié)點(diǎn)與圖層的關(guān)系

為了避免這種情況,F(xiàn)lutter 的設(shè)計(jì)者這里基于 Relayout Boundary 的思想增加了 Repaint Boundary。在繪制頁面時(shí)候如果遇見 Repaint Boundary 就會強(qiáng)制切換圖層。

如下圖所示,在從上到下遍歷控件樹遇到 Repaint Boundary 會重新繪制到新的圖層(深藍(lán)色),在從下到上返回的時(shí)候又遇到 Repaint Boundary,于是又增加一個(gè)新的圖層(淺藍(lán)色)。

圖6: Repaint Boundary 機(jī)制

這樣,即使發(fā)生重繪也不會對其他子樹產(chǎn)生影響。比如在 Scrollview 上,當(dāng)滾動(dòng)的時(shí)候發(fā)生內(nèi)容重繪,如果在 Scrollview 以外的地方不需要重繪就可以使用 Repaint Boundary。Repaint Boundary 并不會像 Relayout Boundary 一樣自動(dòng)生成,而是需要我們自己來加入到控件樹中。

6.【W(wǎng)idget】控件層。所有控件的基類都是 Widget,Widget 的數(shù)據(jù)都是只讀的, 不能改變。所以每次需要更新頁面時(shí)都需要重新創(chuàng)建一個(gè)新的控件樹。每一個(gè) Widget 會通過一個(gè) RenderObjectElement 對應(yīng)到一個(gè)渲染節(jié)點(diǎn)(RenderObject),可以簡單理解為 Widget 中只存儲了頁面元素的信息,而真正負(fù)責(zé)布局、渲染的是 RenderObject。

在頁面更新重新生成控件樹時(shí),RenderObjectElement 樹會盡量保持重用。由于 RenderObjectElement 持有對應(yīng)的 RenderObject,所有 RenderObject 樹也會盡可能的被重用。如圖所示就是三棵樹之間的關(guān)系。在這張圖里我們把形狀當(dāng)做渲染節(jié)點(diǎn)的類型,顏色是它的屬性,即形狀不同就是不同的渲染節(jié)點(diǎn),而顏色不同只是同一對象的屬性的不同。

圖7: Widget、Element 和 Render 之間的關(guān)系

如果想把方形的顏色換成黃顏色,將圓形的顏色變成紅色,由于控件是不能被修改的,需要重新生成兩個(gè)新的控件 Rectangle yellow 和 Circle red。由于只是修改了顏色屬性,所以 Element 和 RenderObject 都被重用,而之前的控件樹會被釋放回收。

圖8: 示例

那么如果把紅色圓形變成三角形又會怎樣呢?由于這里發(fā)生變化的是類型,所以對應(yīng)的 Element 節(jié)點(diǎn)和 RenderObject 節(jié)點(diǎn)都需要重新創(chuàng)建。但是由于黃顏色方形沒有發(fā)生改變,所以其對應(yīng)的 Element 節(jié)點(diǎn)和 RenderObject 節(jié)點(diǎn)沒有發(fā)生變化。

圖9: 示例

7. 然后是【Material】 & 【Cupertino】,這是在 Widget 層之上框架為開發(fā)者提供的基于兩套設(shè)計(jì)語言實(shí)現(xiàn)的 UI 控件,可以幫助我們的 App 在不同平臺上提供接近原生的用戶體驗(yàn)。

Flutter 在馬蜂窩商家端

App 中的應(yīng)用實(shí)踐

圖10: 馬蜂窩商家端使用 Flutter 開發(fā)的頁面

開發(fā)方式:Flutter + Native

由于商家端已經(jīng)是一款成熟的 App,不可能創(chuàng)建一個(gè)新的 Flutter 工程全部重新開發(fā),因此我們選擇 Native 與 Flutter 混編的方案來實(shí)現(xiàn)。

在了解 Native 與 Flutter 混編方案前,首先我們需要了解在 Flutter 工程中,通常有以下 4 種工程類型:

1. Flutter Application

標(biāo)準(zhǔn)的 Flutter App 工程,包含標(biāo)準(zhǔn)的 Dart 層與 Native 平臺層。

2. Flutter Module

Flutter 組件工程,僅包含 Dart 層實(shí)現(xiàn),Native 平臺層子工程為通過 Flutter 自動(dòng)生成的隱藏工程(.ios / .android)。

3. Flutter Plugin

Flutter 平臺插件工程,包含 Dart 層與 Native 平臺層的實(shí)現(xiàn)。

4. Flutter Package

Flutter 純 Dart 插件工程,僅包含 Dart 層的實(shí)現(xiàn),往往定義一些公共 Widget。

了解了 Flutter 工程類型后,我們來看下官方提供的一種混編方案(https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps),即在現(xiàn)有工程下創(chuàng)建 Flutter Module 工程,以本地依賴的方式集成到現(xiàn)有的 Native 工程中。

官方集成方案(以 iOS 為例)

a. 在工程目錄創(chuàng)建 FlutterModule,創(chuàng)建后,工程目錄大致如下:

b. 在 Podfile 文件中添加以下代碼:

  1. flutter_application_path = '../flutter_Moudule/'  
  2. eval(File.read(File.join(flutter_application_path, '.ios''Flutter''podhelper.rb')), binding) 

該腳本主要負(fù)責(zé):

  • pod 引入 Flutter.Framework 以及 FlutterPluginRegistrant 注冊入口
  • pod 引入 Flutter 第三方 plugin
  • 在每一個(gè) pod 庫的配置文件中寫入對 Generated.xcconfig 文件的導(dǎo)入
  • 修改 pod 庫的 ENABLE_BITCODE = NO(因?yàn)?Flutter 現(xiàn)在不支持 bitcode)

c. 在 iOS 構(gòu)建階段 Build Phases 中注入構(gòu)建時(shí)需要執(zhí)行的 xcode_backend.sh (位于 FlutterSDK/packages/flutter_tools/bin) 腳本:

  1. "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build 
  2. "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed 

該腳本主要負(fù)責(zé):

  • 構(gòu)建 App.framework 以及 Flutter.framework 產(chǎn)物
  • 根據(jù)編譯模式(debug/profile/release)導(dǎo)入對應(yīng)的產(chǎn)物
  • 編譯 flutter_asset 資源
  • 把以上產(chǎn)物 copy 到對應(yīng)的構(gòu)建產(chǎn)物中

d. 與 Native 通信

  • 方案一:改造 AppDelegate 繼承自 FlutterAppDelegate
  • 方案二:AppDelegate 實(shí)現(xiàn) FlutterAppLifeCycleProvider 協(xié)議,生命周期由 FlutterPluginAppLifeCycleDelegate 傳遞給 Flutter

以上就是官方提供的集成方案。我們最終沒有選擇此方案的原因,是它直接依賴于 FlutterModule 工程以及 Flutter 環(huán)境,使 Native 開發(fā)同學(xué)無法脫離 Flutter 環(huán)境開發(fā),影響正常的開發(fā)流程,團(tuán)隊(duì)合作成本較大;而且會影響正常的打包流程。(目前 Flutter 團(tuán)隊(duì)正在重構(gòu)嵌入 Native 工程的方式)

最終我們選擇另一種方案來解決以上的問題:遠(yuǎn)端依賴產(chǎn)物。

圖11 :遠(yuǎn)端依賴產(chǎn)物

iOS 集成方案

通過對官方混編方案的研究,我們了解到 iOS 工程最終依賴的其實(shí)是 FlutterModule 工程構(gòu)建出的產(chǎn)物(Framework,Asset,Plugin),只需將產(chǎn)物導(dǎo)出并 push 到遠(yuǎn)端倉庫,iOS 工程通過遠(yuǎn)端依賴產(chǎn)物即可。

依賴產(chǎn)物目錄結(jié)構(gòu)如下:

  • App.framework : Flutter 工程產(chǎn)物(包含 Flutter 工程的代碼,Debug 模式下它是個(gè)空殼,代碼在 flutter_assets 中)。
  • Flutter.framework: Flutter 引擎庫。與編譯模式(debug/profile/release)以及 CPU 架構(gòu)(arm*, i386, x86_64)相匹配。
  • lib*.a & .h 頭文件 : FlutterPlugin 靜態(tài)庫(包含在 iOS 端的實(shí)現(xiàn))。
  • flutter_assets: 包含 Flutter 工程字體,圖片等資源。在 Flutter1.2 版本中,被打包到 App.framework 中。

Android 集成方案

Android Nativite 集成是通過 Gradle 遠(yuǎn)程依賴 Flutter 工程產(chǎn)物的方式完成的,以下是具體的集成流程。

a.創(chuàng)建 Flutter 標(biāo)準(zhǔn)工程

  1. $ flutter create flutter_demo 

默認(rèn)使用 Java 代碼,如果增加 Kotlin 支持,使用如下命令:

  1. $ flutter create -a kotlin flutter_demo 

b. 修改工程的默認(rèn)配置

  • 修改 app module 工程的 build.gradle 配置 apply plugin: 'com.android.application' => apply plugin: 'com.android.library',并移除 applicationId 配置
  • 修改 root 工程的 build.gradle 配置

在集成過程中 Flutter 依賴了三方 Plugins 后,遇到 Plugins 的代碼沒有被打進(jìn) Library 中的問題。通過以下配置解決(這種方式略顯粗暴,后續(xù)的優(yōu)化方案正在調(diào)研)。

  1. subprojects { 
  2.    project.buildDir = "${rootProject.buildDir}/app" 
  • app module 增加 maven 打包配置

c. 生成 Android Flutter 產(chǎn)物

  1. $ cd android 
  2. $ ./gradlew uploadArchives 

官方默認(rèn)的構(gòu)建腳本在 Flutter 1.0.0 版本存在 Bug——最終的產(chǎn)物中會缺少 flutter_shared/icudtl.dat 文件,導(dǎo)致 App Crash。目前的解決方式是將這個(gè)文件復(fù)制到工程的 assets 下( 在 Flutter 最新 1.2.1 版本中這個(gè) Bug 已被修復(fù),但是 1.2.1 版本又出現(xiàn)了一個(gè) UI 渲染的問題,所以只能繼續(xù)使用 1.0.0 版本)。

d. Android Native 平臺工程集成,增加下面依賴配置即可,不會影響 Native 平臺開發(fā)的同學(xué)

  1. implementation 'com.mfw.app:MerchantFlutter:0.0.5-beta' 

Flutter 和 iOS、Android 的交互

使用平臺通道(Platform Channels)在 Flutter 工程和宿主(Native 工程)之間傳遞消息,主要是通過 MethodChannel 進(jìn)行方法的調(diào)用,如下圖所示:

圖12 :Flutter與iOS、Android交互

為了確保用戶界面不會掛起,消息和響應(yīng)是異步傳遞的,需要用 async 修飾方法,await 修飾調(diào)用語句。Flutter 工程和宿主工程通過在 Channel 構(gòu)造函數(shù)中傳遞 Channel 名稱進(jìn)行關(guān)聯(lián)。單個(gè)應(yīng)用中使用的所有 Channel 名稱必須是唯一的; 可以在 Channel 名稱前加一個(gè)唯一的「域名前綴」。

Flutter 與 Native 性能對比

我們分別使用 Native 和 Flutter 開發(fā)了兩個(gè)列表頁,以下是頁面效果和性能對比:

iOS 對比(機(jī)型 6P 系統(tǒng) 10.3.3):

Flutter 頁面:

iOS Native 頁面:

可以看到,從使用和直觀感受都沒有太大的差別。于是我們采集了一些其他方面的數(shù)據(jù)。

Flutter 頁面:

iOS Native 頁面:

另外我們還對比了商家端接入 Flutter 前后包體積的大小:39Mb → 44MB

在 iOS 機(jī)型上,流暢度上沒有什么差異。從數(shù)值上來看,F(xiàn)lutter 在 內(nèi)存跟 GPU/CPU 使用率上比原生略高。 Demo 中并沒有對 Flutter 做更多的優(yōu)化,可以看出 Flutter 整體來說還是可以做出接近于原生的頁面。

下面是 Flutter 與 Android 的性能對比。

Flutter 頁面:

Android Native 頁面:

從以上兩張對比圖可以看出,不考慮其他因素,單純從性能角度來說, 原生要優(yōu)于 Flutter,但是差距并不大,而且 Flutter 具有的跨平臺開發(fā)和熱重載等特點(diǎn)極大地節(jié)省了開發(fā)效率。并且,未來的熱修復(fù)特性更是值得期待。

混合棧管理

首先先介紹下 Flutter 路由的管理:

  • Flutter 管理頁面有兩個(gè)概念:Route 和 Navigator。
  • Navigator 是一個(gè)路由管理的 Widget(Flutter 中萬物皆 Widget),它通過一個(gè)棧來管理一個(gè)路由 Widget 集合。通常當(dāng)前屏幕顯示的頁面就是棧頂?shù)穆酚伞?/li>
  • 路由 (Route) 在移動(dòng)開發(fā)中通常指頁面(Page),這跟 web 開發(fā)中單頁應(yīng)用的 Route 概念意義是相同的,Route 在 Android 中通常指一個(gè) Activity,在 iOS 中指一個(gè) ViewController。所謂路由管理,就是管理頁面之間如何跳轉(zhuǎn),通常也可被稱為導(dǎo)航管理。這和原生開發(fā)類似,無論是 Android 還是 iOS,導(dǎo)航管理都會維護(hù)一個(gè)路由棧,路由入棧 (push) 操作對應(yīng)打開一個(gè)新頁面,路由出棧 (pop) 操作對應(yīng)頁面關(guān)閉操作,而路由管理主要是指如何來管理路由棧。

圖14 :Flutter 路由管理

如果是純 Flutter 工程,頁面棧無需我們進(jìn)行管理,但是引入到 Native 工程內(nèi),就需要考慮如何管理混合棧。并且需要解決以下幾個(gè)問題:

1. 保證 Flutter 頁面與 Native 頁面之間的跳轉(zhuǎn)從用戶體驗(yàn)上沒有任何差異

2. 頁面資源化(馬蜂窩特有的業(yè)務(wù)邏輯)

3. 保證生命周期完整性,處理相關(guān)打點(diǎn)事件上報(bào)

4. 資源性能問題

參考了業(yè)界內(nèi)的解決方法,以及項(xiàng)目自身的實(shí)際場景,我們選擇類似于 H5 在 Navite 中嵌入的方式,統(tǒng)一通過 openURL 跳轉(zhuǎn)到一個(gè) Native 頁面(FlutterContainerVC),Native 頁面通過 addChildViewController 方式添加 FlutterViewController(負(fù)責(zé) Flutter 頁面渲染),同時(shí)通過 channel 同步 Native 頁面與 Flutter 頁面。

  • 每一次的 push/pop 由 Native 發(fā)起,同時(shí)通過 channel 保持 Native 與 Flutter 頁面同步——在 Native 中跳轉(zhuǎn) Flutter 頁面與跳轉(zhuǎn)原生無差異
  • 一個(gè) Flutter 頁面對應(yīng)一個(gè) Native 頁面(FlutterContainerVC) ——解決頁面資源化
  • FlutterContainerVC 通過 addChildViewController 對單例 FlutterViewController 進(jìn)行復(fù)用——保證生命周期完整性,處理相關(guān)打點(diǎn)事件上報(bào)
  • 由于每一個(gè) FlutterViewController(提供 Flutter 視圖的實(shí)現(xiàn))會啟動(dòng)三個(gè)線程,分別是 UI 線程、GPU 線程和 IO 線程,使用單例 FlutterViewController 可以減少對資源的占用——解決資源性能問題

Flutter 應(yīng)用總結(jié)

Flutter 一經(jīng)發(fā)布就很受關(guān)注,除了 iOS 和 Android 的開發(fā)者,很多前端工程師也都非??春?Flutter 未來的發(fā)展前景。相信也有很多公司的團(tuán)隊(duì)已經(jīng)投入到研究和實(shí)踐中了。不過 Flutter 也有很多不足的地方,值得我們注意:

  1. 雖然 1.2 版本已經(jīng)發(fā)布,但是目前沒有達(dá)到完全穩(wěn)定狀態(tài),1.2 發(fā)布完了就出現(xiàn)了控件渲染的問題。加上 Dart 語言生態(tài)小,學(xué)習(xí)資料可能不夠豐富。
  2. 關(guān)于動(dòng)態(tài)化的支持,目前 Flutter 還不支持線上動(dòng)態(tài)性。如果要在 Android 上實(shí)現(xiàn)動(dòng)態(tài)性相對容易些,iOS 由于審核原因要實(shí)現(xiàn)動(dòng)態(tài)性可能成本很高。
  3. Flutter 中目前拿來就用的能力只有 UI 控件和 Dart 本身提供能力,對于平臺級別的能力還需要通過 channel 的方式來擴(kuò)展。
  4. 已有工程遷移比較復(fù)雜,以前沉淀的 UI 控件,需要重新再實(shí)現(xiàn)一套。
  5. 還有一點(diǎn)比較有爭議,F(xiàn)lutter 不會從程序中拆分出額外的模板或布局語言,如 JSX 或 XM L,也不需要單獨(dú)的可視布局工具。有的人認(rèn)為配合 HotReload 功能使用非常方便,但我們發(fā)現(xiàn)這樣代碼會有非常多的嵌套,閱讀起來有些吃力。

目前阿里的閑魚開發(fā)團(tuán)隊(duì)已經(jīng)將 Flutter 用于大型實(shí)踐,并應(yīng)用在了比較重要的場景(如產(chǎn)品詳情頁),為后來者提供了良好的借鑒。馬蜂窩的移動(dòng)客戶端團(tuán)隊(duì)關(guān)于 Flutter 的探索才剛剛起步,前面還有很多的問題需要我們一點(diǎn)一點(diǎn)去解決。不過無論從 Google 對其的重視程度,還是我們從實(shí)踐中看到的這些優(yōu)點(diǎn),都讓我們對 Flutter 充滿信心,也希望在未來我們可以利用它創(chuàng)造更多的價(jià)值和奇跡。

路途雖遠(yuǎn),猶可期許。

參考文獻(xiàn):

Flutter's Layered Design

https://www.youtube.com/watch?v=dkyY9WCGMi0

Flutter's Rendering Pipeline

https://www.youtube.com/watch?v=UUfXWzp0-DU&t=1955s

Flutter原理與美團(tuán)的實(shí)踐https://juejin.im/post/5b6d59476fb9a04fe91aa778#comment

(題圖來源:網(wǎng)絡(luò))

【本文是51CTO專欄作者馬蜂窩技術(shù)的原創(chuàng)文章,作者微信公眾號馬蜂窩技術(shù)(ID:mfwtech)】

戳這里,看該作者更多好文

責(zé)任編輯:武曉燕 來源: 51CTO專欄
相關(guān)推薦

2019-02-18 15:23:21

馬蜂窩MESLambda

2020-03-22 15:49:27

Kafka馬蜂窩大數(shù)據(jù)平臺

2020-01-03 09:53:36

Kafka集群優(yōu)化

2019-06-11 12:19:10

ABTest分流系統(tǒng)

2019-06-11 11:18:40

容災(zāi)緩存設(shè)計(jì)

2019-02-19 15:20:12

消息總線架構(gòu)異步

2019-04-12 14:22:40

馬蜂窩機(jī)票訂單

2019-04-26 15:16:02

馬蜂窩火車票系統(tǒng)

2022-06-20 09:00:00

深度學(xué)習(xí)人工智能研究

2019-02-27 15:24:54

馬蜂窩游搶單系統(tǒng)

2018-10-29 12:27:20

2019-03-29 08:21:51

馬蜂窩Golang并發(fā)代理

2020-02-21 16:20:37

系統(tǒng)驅(qū)動(dòng)項(xiàng)目管理

2023-12-13 13:15:13

平臺開發(fā)實(shí)踐

2018-10-26 16:00:39

程序員爬蟲馬蜂窩

2024-04-02 08:45:08

ChatGPTAI會議人工智能

2023-02-09 07:15:52

開發(fā)FlutterReact

2019-12-17 14:59:27

數(shù)據(jù)中臺數(shù)據(jù)倉庫馬蜂窩

2017-05-25 09:45:35

2018-08-15 08:52:49

爬蟲出行城市數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號