乾貨|Flutter 原理與閒魚深度實踐

王康(正物)—— Flutter 官方成員 阿里巴巴技術專家,以前主要負責 Flutter 在閒魚中的混合開發體系,目前重點關注 Flutter 深刻度以及生態相關的工做。本文將分享三方面內容, Flutter 的原理、 Flutter 在閒魚中的應用,最後介紹咱們在深度方面的一些探索。

0一、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 是開源項目,其整個的開發,工做流都是徹底遵循開源項目的運做來完成的。gradle

0二、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 業務的研發。

0三、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 的佈局推導,樹的構建優化與最終代碼轉化。

0四、總結 & 展望

回顧一下,本文咱們分享了跨平臺方案與 Flutter 的原理。在 Flutter 的業務落地中如何去調研問題,如何完成混合開發體系和能力擴展,如何去解決關鍵問題和保證線上質量;也展開介紹了咱們在 AOP 和 UI To Code 等領域作得一些深刻性工做。

展望將來,咱們談談 Flutter 的一些將來的趨勢。

首先 Flutter 原理很天然地支持了 Mobile 和 Desktop ,以及神祕的 Fuchsia 系統。針對 Flutter For Web ,我最近也寫了一點分析,這是一個實驗性的項目,從原理上來講能夠支持 Flutter 代碼無成本地運行在 Web 上,但可能存在性能的損失。固然若是業務不是很複雜,或不是很高的性能要求的話,能夠考慮嘗試下。

除了咱們自身的實踐外,咱們也但願一些大的應用,能夠更多地進來。更復雜的應用場景和生態鏈的支持可讓 Flutter 的社羣更加完善。

目前咱們如今也在作一些 Flutter China 的工做,核心目標就是完善國內的生態下降你們的開發門檻,讓更多的團隊可以受益。最後,你們若是有什麼問題能夠在下方評論區進行交流。

精彩回顧


本文做者:王康(正物)

閱讀原文

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索