康(正物)—— Flutter 官方成員 阿里巴巴技術專家,之前主要負責 Flutter 在閑魚中的混合開發體系,目前重點關注 Flutter 深入度以及生態相關的工作。本文將分享三方面內容, Flutter 的原理、 Flutter 在閑魚中的應用,最后介紹我們在深度方面的一些探索。
當我們談到跨平臺框架時,可能會想到很多備選方案。包括早期的 HTML 和 Cordova , 后來的 React Native , Weex ,以及這兩年很是流行的 Flutter ,它們都在不同階段不同程度上解決了我們對跨平臺的訴求。如果我們從一些關鍵指標包括動態性、性能來觀察,他們的區別還比較明顯。
HTML 和 Cordova 具有最好的動態性,但他們的性能卻是最差的,RN / Weex 具有良好的動態性。Flutter 則是一個純原生的設計,其設計使它天生具有很好的性能與跨端一致性。
Flutter 是如何實現優秀的性能和跨端一致性的呢?從設計上可以看出 Flutter 在操作系統之上包含了三個層次。最下面是平臺相關的嵌入層,其向上提供一個 Surface 用以繪制,建立了相關的線程模型和事件循環機制。在此之上則是一個平臺無關的引擎,包括用于繪制的 Skia ;Dart 的運行時,開發模式下包括一個解釋器;還有一部分是文本繪制相關內容。最上面就是用 Dart 語言編寫的 Flutter 框架,也是我們最常接觸到的內容。Flutter 框架包含一個完整分層的 UI 框架,從基礎的 Foundation 庫,到動畫手勢,再到渲染,之上又提供了各種豐富的 Widget 庫。為了方便開發者使用, Flutter 還提供了兩套不同風格的組件庫,針對安卓的 Material Design 的組件庫和針對 iOS 的 Cupertino 風格的組件庫。
從這個設計可以看出,Flutter 和平臺相關的內容,其實只提供 Surface 和線程/事件循環模型的嵌入層部分。這種類似用游戲引擎的方式來開發應用的設計很好解釋了為什么它具有優秀的跨端一致性。
我們常常說 Flutter 具有這樣的幾個特點:
豐富的 Widget 庫、 Material Design 和 Cupertino 風格的系統庫、組合式的 API 、像素級的控制力可以使開發者便捷地構建精美的應用。
Dart 語言是為數不多同時支持 JIT 和 AOT 編譯的語言。開發期使用 JIT 編譯,支持了廣受歡迎的熱重載功能,開發者可以像 PS 圖片一樣來開發應用,開發效率高。發布后 Flutter 使用 AOT 編譯, Dart 代碼最終被編譯成 ARM 匯編指令,運行快速。
Flutter 是開源項目,其整個的開發,工作流都是完全遵循開源項目的運作來完成的。
說完 Flutter 原理,我們來看 Flutter 在閑魚中的應用。在我們的研發中有幾個核心關注的問題。
閑魚技術是一個相對較小的團隊,但業務需求比較重,開發人員少需求多,這種情況下效率就非常重要。還有部分原因是 iOS 安卓兩端開發資源不均衡的問題,
我們的設計要求我們具有很好的跨端一致性,其設計也是同一套風格。
不管是復雜的交互還是動畫,都要求其具有不錯的性能。
Flutter 的設計很好地滿足了閑魚業務研發關注的這些問題,這也是我們采用它的原因。
我們怎么樣讓 Flutter 從無到有地在閑魚中落地與上線?這里面包括前期的調研,研發期的混合開發體系,以及如何保質保量在線上運行。
2017 年,我們去接觸和調研 Flutter ,其當時還處在 Alpha 階段。
我們需要去了解它的原理,看它是如何具有所宣稱的諸多優勢;對其性能做測試,看能否滿足要求;包大小的增加怎么樣,這個量是否可承受;音視頻調的出發點在于業務場景,我們的詳情和發布頁面包括了很多圖片和視頻;工具鏈上 Flutter的開發體驗如何;我們甚至做了一個 MVP Demo ,這個產品中我們實現了包括發布,詳情、我的頁面等主要設計與邏輯;此外我們還很關注其社區的成熟度,確保在遇到問題時,可以通過自己對原理的理解或者社區去解決問題。
要使用 Flutter 我們就會面臨一個混合研發體系的問題。其最開始的設計是面向純 Flutter 開發的應用。而我們的應用是在原生項目中嵌入 Flutter ,也就是 Add2App 。事實上在國內,即便是一個純 Flutter 的應用,很多時候,因為二方、三方庫的原因,也會成為一個混合工程。通過我們的實踐與影響, Add2App 也變成了 Flutter 演進的重要方向。
工程層面上,我們的團隊中存在兩個視角。一個是傳統的 Native 開發的視角,一個是 Flutter 視角。我們并沒有直接使用 Github 上的 Flutter 項目,主要是因為可控性的問題。因為國內的安卓碎片化以及 ROM 中 opengl 的實現不規范,使我們不得不存在一些針對性的處理邏輯,也就是引擎定制。其產物通過定制的 Flutter 最終被 fwn 工程所使用。fwn 工程包含了實際 Flutter 業務,其 Flutter 代碼通過產物集成的方式,通過 pod( iOS ) ,和 gradle ( Android ),最終集成到原生項目中。
混合開發不僅包括工程體系,也包括頁面側的邏輯。我們一開始就涉及到了混合頁面體系,以 Android 為例簡要介紹下原理。每個 Flutter 頁面對應了一個原生的 BoostFlutterActivity , BoostFlutterActivity 通過各自的 BoostFlutterView 去綁定單例的 FlutterEngine 。當 Flutter 頁面在做切換時 BoostFlutterActivity 也會同步切換,將 FlutterEngine 動態地 Detach 和 Attach 。Native 和 Flutter 之間可以互相關閉和打開頁面, Native 的生命周期也會同步到 Flutter 側。
Flutter 支持 UI 構建以及邏輯實現,但可能我們還需要去獲取 wifi 狀態或電量等系統狀態。
面對這樣的場景, Flutter 提供了很多機制去擴展應用。以獲取電量為例, Flutter 提供了 Channel 機制用于同 Native 之間的雙向通信。Dart 代碼在 Release 下會變成匯編代碼,直接調用到 Engine ( C++ ),再調用到 OC (直接)或 JAVA (通過 JNI 間接),這種設計下的性能是原生體驗。
Flutter 不僅在邏輯側提供了 Channel 機制去擴展應用,在渲染相關也提供了一些機制去做更多。我們寫的 Flutter 視圖布局最終會通過 DartRuntime 調用到 Engine 中的 LayerTree->Paint 方法。在這個渲染管線中, LayerTree 會調用到 SkCanva->Draw ,最終通過 PresentRenderBuffer / SwapBuffer 將內容繪制到 GPU 上。LayerTree 中,包含很多種 Layer ,其中有一個特殊的 TextureLayer 可用于擴展。
以 Android 為例, TextureLayer 可以在 SurfaceTexture 的幫助下,同一個 Surface 相關聯?;?Surface 可以將視頻播放的內容傳入并完成渲染,或者結合 VirtualDisplay 和 Presentation ,完成 NativeView 的嵌入。需要注意的是,因為 VirtualDisplay API 的限制,此部分的邏輯需要 API Level 在 20 及其以上。
也就是說 Flutter 提供了 Channel 機制用來擴展系統特性相關的邏輯,通過 Texture 機制來支持視頻播放器等場景和原生視圖的嵌入。
在開發過程中我們其實也遇到很多問題,不管是混合棧,或者是視頻嵌入, iOS 兼容等,很多今天已經不再是問題, 但我還是想和大家分享下其中的一些思路。首先了解各層面原理是很重要的, Flutter 本身是一整套龐大完整的內容,針對不同層次團隊中都應該有相關的同學有一定理解;要有能力識別出關鍵問題;可以復現和定位問題,提供最小化的 Demo 用于復現它,在通過社區解決問題的場景下,最小的可復現的 Demo 是尤其重要的;還有就是要同社區有緊密的聯系與合作。
我們不僅要關注技術本身,也一定要保證業務穩定。這里有一些手段來和大家分享。用灰度來發現那些容易發現的問題,用分桶和降級策略逐漸增加 Flutter 的業務比例,通過線上 APM 去監控質量,這些手段來保障質量。
總的來看,目前我們有 20 多個頁面來使用 Flutter 構建, Crash 水平在萬分之一的數量級,詳情頁等幀率在 52 幀以上,可交互的頁面加載時長是 300 毫秒。
這些是我們目前使用 Flutter 開發的部分頁面,包括詳情發布、我的等。涉及到的設計元素較多,包括視頻、圖片、聊天、評論、拍攝等比較完備的內容。我們最早使用詳情和發布來驗證 Flutter ,也是要看 Flutter 能否支撐業務場景最復雜的情況,此外也需要分桶與降級的機制來保障最壞情況下的業務可用性。背后的演進并不容易,也是個逐漸改善解決的過程,但這并不是原理上的大問題,很多是細節上的問題,典型如安卓上面的碎片化問題。
除了業務落地外,我們也做了一些體系化的建設,這里面很多內容都同 Native 側。就 Flutter 而言,從下往上,包括一些針對 Flutter 的 SDK ,像其特有的 APM 采集;大量 SDK 的橋接;在其上,構建用于 Flutter 開發的編程框架,如 Fish Redux , FlutterBoost 等,最終去支撐各個 Flutter 業務的研發。
分享完 Flutter 在閑魚中的應用,接下來介紹我們的一些深度實踐。
在 Engine 側,主要解決 Android 碎片化所帶來的問題以及 iOS 上的內存優化。
在 Dart 側的工作主要圍繞著 Dill 展開,我們開發了一個基于 Dill 編織的 AOP 框架,提供了一種新的方式來實現中間語言層面的代碼編織?;诖耍覀円舱谧?JSON 轉換,輕量級反射等部分的內容。
在 Flutter 側,我們的工作包括 APM , FlutterBoost , FishRedux 等面向業務研發的開發框架。
在 UI 部分,我們也在做一些圖片轉代碼部分的工作。
簡單介紹下 AOP 框架和 UI To Code 兩部分的工作。
如果想去解決 AOP For Flutter 的問題,有哪些問題需要解決呢?首先我們要描述清楚這段代碼,是想對哪個庫、哪個類的哪個方法去做怎么樣的操作;要讓 AOP 代碼沒有侵入性,使原生代碼和 AOP 代碼可以分開編寫,并最終在合適層面進行編織;我們還需要一種機制,去提取散落各處的注解形式的切面邏輯,并將其應用到目標方法中去。
在 AspectD 的設計中,通過提供面向 Dart 的 Aspect 設計,我們解決了描述切面的問題;通過提供基于 Kernel to Kernel Transform的Transformer ,我們解決了提取注解和編織的問題。
相對于傳統 AOP 框架所提供的 Call 和 Execute 的語法, AspectD 還提供了 Inject 的語法,這主要是因為 Flutter 禁止反射造成的。
目前還有一個問題就是對于構建過程的侵入性。Flutter 的構建過程( flutter tools )和我們以前的習慣有區別,并沒有提供太多的擴展點。目前 AspectD 本身有一點對于構建流程的修改,用于攔截原始的 Dill 構建,并用操作過的 Dill 文件替換原始 Dill 文件,這一侵入性同 AOP 本身沒有什么關系,我們正在和 Flutter 團隊去解決這一問題。
還有就是我們在做的 UI To Code 。即通過 UI 去分析版面,識別組件屬性和布局,生成中間的 DSL 描述。后端基于此,完成針對 Flutter 的布局推導,樹的構建優化與最終代碼轉化。
回顧一下,本文我們分享了跨平臺方案與 Flutter 的原理。在 Flutter 的業務落地中如何去調研問題,如何完成混合開發體系和能力擴展,如何去解決關鍵問題和保證線上質量;也展開介紹了我們在 AOP 和 UI To Code 等領域做得一些深入性工作。
展望未來,我們談談 Flutter 的一些未來的趨勢。
首先 Flutter 原理很自然地支持了 Mobile 和 Desktop ,以及神秘的 Fuchsia 系統。針對 Flutter For Web ,我最近也寫了一點分析,這是一個實驗性的項目,從原理上來說可以支持 Flutter 代碼無成本地運行在 Web 上,但可能存在性能的損失。當然如果業務不是很復雜,或不是很高的性能要求的話,可以考慮嘗試下。
除了我們自身的實踐外,我們也希望一些大的應用,可以更多地進來。更復雜的應用場景和生態鏈的支持可以讓 Flutter 的社群更加完善。
目前我們現在也在做一些 Flutter China 的工作,核心目標就是完善國內的生態降低大家的開發門檻,讓更多的團隊能夠受益。最后,大家如果有什么問題可以在下方評論區進行交流。
精彩回顧
作者:王康(正物)
常關注 GMTC 全球大前端技術大會的同學應該會發現,今年的 GMTC 沒有單獨策劃 Flutter 和小程序相關的專題了,跟跨端這一主題相關的,只保留了一個跨端技術專題,關注 React Native 新架構的落地,也關注 Kotlin、WebAssembly 如何在跨端中發揮作用,以及其他跨端的新思路。
看到這里,你也許會有幾個問題想要問我們。
第一個問題,為什么沒有 Flutter、小程序了?是它們不火了嗎?不,是它們暫時沒有大的更新了。
Google 近期的動作,大多是對之前的 Flutter 生態做補齊,比如 Flutter for Web。此外,包大小也導致了 Fultter 在很多超級 App 上落地艱難,它需要找到更適合的場景。
那小程序專題為什么也消失了?與 Flutter 相似,小程序的發展也進入了一個平臺期,大家的方案大同小異,從聽眾的收益來看,我們決定暫時不專門劃分一個分會場來討論它了。
第二個問題,為什么是 Kotlin、WebAssembly?
Kotlin 語言不僅可以應用于 Android 端,還可以通過 Kotlin Multiplatform 支持服務端、移動端的應用及中間件開發,同時呢,通過 Kotlin 到 JavaScript 的轉換和互操作,你還可以使用 Kotlin 開發 Web 應用。具備現代、簡潔和安全等特點的 Kotlin 語言,自然成為了未來跨平臺研發模式的一種新選擇,我們十分看好這門語言的發展。
WebAssembly 性能好,分發能力強,前端對它的呼聲日漸高漲。所以,我們想看看,你們前端天天喊 WebAssembly,實際到底做得怎么樣了。
以上就是今年的 GMTC 北京站對于「跨端技術」專題的思考,我們邀請了字節跳動 Flutter Infra 團隊負責人董巖擔任出品人,為專題質量把關。他在跨端領域有多年實踐經驗,去年的 GMTC 北京站上,也貢獻過高質量演講。
目前專題已確認兩個議題,分別是 Weex2.0(是的,你沒看錯,Weex 今年將推出 2.0 版本,這一版本他們內部打磨了很久,是真的帶著誠意來的),和來自騰訊 PCG 的 DSL 跨平臺動態化方案(探討差異化的應用,在不同場景下如何解決不同的問題)。
本次大會中,還有低代碼、大前端 DevOps、前端框架新體驗、大前端監控、移動端性能與效率優化等專題。同時,我們也關注大前端破圈的有效姿勢,首次聚焦 B 端研發效能、IoT 動態應用開發、TypeScript、云研發實踐、大前端技術融合與跨界等,并邀請 winter 等大咖前來參與“師兄幫幫忙”晚場交流活動,與你討論“前端如何有效增值”的話題。
了解更多軟件開發與相關領域知識,點擊訪問 InfoQ 官網:https://www.infoq.cn/,獲取更多精彩內容!
源:https://www.jianshu.com/p/983818251079
*請認真填寫需求信息,我們會在24小時內與您取得聯系。