飛豬Flutter技術演進及業務改造的實踐與思考總結

飛豬前端團隊發表於2021-03-08

本文作者飛豬@旅鶴,負責飛豬安卓端 架構和大交通業務團隊,在客戶端工程化體系、效能優化、穩定性治理、音視訊、移動安全等方向有豐富經驗;

當前飛豬技術部 2022 屆校園招聘開始啦,歡迎前往 掘金詳細瞭解

本文結合飛豬近半年來在 Flutter 技術實踐中的突破和探索,重點介紹跨端標準容器建設、元件庫的沉澱、效能優化的經驗,以及面對存量業務做 Flutter 改造的新思路。

一、飛豬客戶端架構演進

發展歷程

客戶端架構 1.0
 2013 年,隨著阿里巴巴 All in Mobile,阿里旅行也有了獨立的 App。最初業務比較簡單,PC 頁面簡單改造成 H5 執行在 App 端,以資訊展示為主,Native 業務承接機票交易,整個 App 的構建釋出不成體系。發渠道包都在單臺 Jenkis 伺服器上現拉原始碼編譯,測試驗證後直接發應用市場,沒有體系化的研發構建平臺,也缺乏完善的灰度機制。 當時 Android 手機山寨機橫行,主流廠商各種定製 ROM,相容性、適配問題搞的焦頭爛額,所以我們主要精力在解決穩定性問題,同時夯實基礎功能,支撐業務穩定上線。這個階段 Android、iOS 得到獨立發展,只在頁面跳轉協議和事件匯流排協議上保持一致。

客戶端架構2.0
隨著支付寶和手淘快速成長為航母級應用,無線基礎設施趨於完善,飛豬也搭上了順風車,支撐了業務快速迭代。我們在端研發框架上對接過無線研發協作平臺,有力保障了多人並行開發,業務迭代最快做到按周交付。同時基本建立了完善的灰度釋出體系,Crash 率從千分之 5 降低到萬分之 2,其它基礎功能(網路庫/圖片庫/Push 通道)也逐步從自建方案迴歸到依賴中臺基礎能力,研發效率大幅提升。 但受限於應用渠道更新效率,在 Android 端,新版本升級覆蓋慢的問題長期存在,分發效率低的問題不得不提上日程。因此我們開始投入做相關技術的改造:

  • 看 Native 自身,各種動態化技術層出不窮。飛豬也積極參與了動態更新技術共建,迴歸頭看,在非航母級應用上,動態釋出能力主要還是修 bug,真正推業務的情況並不多見。為了進一步提升業務對 Native 動態性需求,飛豬也與手淘共建了 DX 動態模板容器,通過統一動態模板 DSL,建立了完善的搭建平臺和模板管理倉庫,現已廣泛應用於業務中,但只限於簡單業務邏輯。
  • 看前端,H5 因為開發效率高,且具備完備的動態化能力,開始大量承接業務。我們很早就成立了跨棧虛擬小組,通過離線包、預載入、預渲染、新SSR技術來優化 H5 效能。飛豬前端同學也積極參與了Weex業務落地,當時國際機票核心主鏈路也由Weex承接,實現接近原生的體驗。

挑戰與新機會

隨著業務需求迭代,App 變的越來越臃腫,技術改造帶來研發效率/效能體驗提升的同時,也增加了維護的複雜度。旅行業務域邏輯非常複雜,對有些大的需求,在需求評審上經常需要反覆對焦,但在實際交付上還是存在兩端開發理解偏差引發的線上問題,我們印象中就發生過幾起機票交易鏈路因為漏測引發線上故障。 技術側複雜度增加也容易出現紕漏,一次 H5 離線包在 Android 端由於沒加好保護導致線上大面積客訴,經過超過 24 小時排查才最終定位到問題。很多基礎線的改造也很難評估具體影響面,給穩定性帶來新的挑戰。從目前的技術方案上看,因為兩端的具體實現依賴原生能力,系統平臺層的差異性帶來的業務表現差異問題,很大程度是需要更底層的技術方案來解決的。

自渲染與Flutter
自渲染技術並不是新概念,從很早以前的 QT 到現在的 Flutter,它的優勢在於具備非常好的跨端能力,能解決長尾問題。對比原生渲染方案,具體到 WebView,在 Android 上版本碎片化問題非常多,給前端適配帶來很大的難度,我們利用12MB包大小內建U4來解決在WebView在Android端的適配問題;看 Native 原生業務,之前提到的由於溝通上理解上偏差出現交付上差異,最終由測試兜底也是不可持續的。 Flutter 在全球超過 200 萬開發者,月活開發者 50 萬。據 GitHub 統計,Flutter 是全球第二快增長的開源專案。Google Play 釋出了超過 11 萬 Flutter 應用,國內大廠基本都使用 Flutter,集團內非常多 BU 也積極參與生態建設。對比 QT,同是自渲染技術,它在開發體驗上和生態建設上都有很大優勢,也因此收穫了很多開發者。對比其他的技術方案,Flutter 除了因為政策原因捨棄了動態性,其他方面表現都非常優秀。

客戶端架構Flutter演進方向

2019 年,飛豬開始在商家版 EBK 改造專案上試水 Flutter,在研發效率和使用者體驗上都有不錯的收益。隨著 Flutter 混合技術棧的完善,我們決定 2020 年 6 月份在飛豬 C 端做 Flutter 專項改造,寄希望於推動飛豬技術架構升級,完成客戶端技術體系向大前端技術體系演進,建立統一移動端研發模式,摸高 Flutter 的效能極限。具體到幾個核心專案,包括跨端標準容器、研發工程體系、元件化建設、自動化測試領域尋求突破,並沉澱最佳實踐。 通過引入 Flutter 技術,上層業務開發可以無縫對接 Android、iOS,中間的 Flutter 容器非常薄,平臺差異性對接工作主要通過 Flutter SDK 實現,解決 Native 體驗的一致性問題,提升可維護性。 正如官方描述所說,Flutter 是 UI Tool Kit,最初定位是服務全新 App 開發,在實際中很多功能滿足不了存量業務開發需求。集團基礎建設主要圍繞完善 Flutter 混合技術棧開發、高可用監控預警、研發支撐平臺,以及最核心的效能優化建設,飛豬主要聚焦在業務層面的落地,用好Flutter新技術能力。

二、飛豬 Flutter 技術沉澱

經過半年的沉澱,我們在相關關鍵領域有了比較大的突破,希望和大家深入交流,分享不一樣的 Flutter 實踐經驗。

1. Web on Flutter

背景介紹

Android 端內建 UC WebView,基本解決了 WebView 碎片化問題,適配壓力驟減。但在 2020 年雙 11 會場頁面開發中,還是存在一些 UI 展示低階缺陷問題,主要表現在字型顯示上(上面暴露的問題,近期UC WebView 4.0已經解決),這些問題雖然不嚴重,但比較影響使用者體驗,拉低我們對品質的追求。另一方面,Weex 1.0 依賴原生元件,兩端渲染一致性問題非常難解決,實現原理類似的 RN 也遇到類似的挑戰。 隨著 Flutter 技術熱度興起,前端同學在探索 Web on Flutter 的可能,對比之前 Weex 是 Web on Native。底層渲染技術用 Flutter 替換後,會帶來效能上新的機會,一致性的表現將能更完美地解決。

技術選型與落地

  • 方案①:JS 封裝與 Widget API 接近的介面,實現 Flutter 動態能力,該方案脫離了前端生態;
  • 方案②:Web 與 Widget 對接,ROI 高,完成對映後效能基本接近 Flutter 原生,效能方面也有很高的想象空間;
  • 方案③:Web 與 RenderObject 對接,需要自己寫佈局相關邏輯,效能上沒想象的高,擴充套件視訊、地圖元件有一定改造成本,Flutter 版本升級有一定成本;
  • 方案④:用 C++重寫 Framework,拋棄 Dart Rumtime,開發成本非常高。

Flugy 由飛豬自研,支援前端跨端標準子集,目前在技術層面也和其他團隊共建中。 從架構圖看,Flugy 是一個 Widget Plugin,可以和 Flutter 生態打通,主要程式碼用 Dart 開發,對接的是 Flutter Widget(不需要定製引擎),從前端視角看就是個精簡的 WebView, H5 不用改造就能執行起來,近期瞭解到高德開發了Flutter版地圖,作為擴充套件能力接入Flugy也是非常方便的。 渲染指令說明:對應的是 DOM API 的一些操作指令,包括 createElement,AppendChildren,removeChildren,replaceChildren,insertBefore...

Flugy 標準容器關鍵突破口

image.png 基於之前的架構設計,容器要做的核心事情是要打通 Web 和 Flutter,雖然 Flutter 核心開發來自 Chrome 維護者,但從設計理念上更接近原生。前端開發只需要通過屬性賦值設定想要的結果,不用具體到要用什麼元件來實現,WebView 把這部分邏輯都消化掉,而原生開發需要關注更多的細節,元件的封裝和組織關係,這也是 Native 頁面效能更高,但開發效率不如前端的原因。

回到標準容器專案上看,需要 Flugy 容器把 WebView 之前處理的頁面佈局、樣式的邏輯實現好。與 WebView 不同之處在於我們對接的是 W3C 的子集,沒有歷史包袱。這裡列舉了幾個屬性對映有代表性難題。比如 Overflow:display 和 Position。

  • Position 屬性的實現:
    • 通常原生開發是從整個頁面大的結構入手,然後具體到各子模組的拆分。在 Web on Flutter 上,JS 是在執行過程中建立 DOM,是以流的方式傳送渲染指令到容器側,是個實時解析的過程,我們在解析過程中構建 Widget 物件。但前端的定位屬性非常靈活會有脫離常規流情況,這就需要反覆修改之前構建的 Widget 物件,也是技術突破口。
    • 對元素狀態做了一層抽象把問題簡化,首先在解析新增元素 A 時,遇到 position 為sticky/fixed/absolute 元素時,在建立元素 A 的時候會同時建立一個它的副本 A'(副本會被標記為逃逸元素,即 escape 為 true),隨後 A 元素原身將會留在其父容器中佔位(不做渲染展示),繼續走正常的佈局流,以確保其它同級元素位置的正確性。而它的副本 A'將會通過內部的通訊機制向上尋找能夠接納它的更高層級的父級容器,然後在目標父級容器中按照 web 的規則做渲染展示。
    • 得益於 Flutter 有狀態 Widget 的設計和 Flugy 內部有效的通訊機制,每一步操作都被控制到了一個最小範圍內,僅進行區域性更新,而不會觸發整顆樹的更新,使得效能得到保證。
  • 其他很多屬性在 Flutter 都有具體實現,實現的複雜度基本可控。對齊標準是個比較細緻的工作,也容易出現理解不到位導致實現效果不符合標準要求,前端同學正在牽頭做標準容器單測事項,通過 XRay 實現各標準容器與 H5 渲染表現對齊。

結果展示

 Flugy純渲染效能Flugy完整業務展示
描述直接載入(把 JS Bundle執行過程的DOM/CSS指令快取到本地)快取的指令,圖片載入走線上請求,頁面展示直出載入快取到本地的JS Bundle,看不到白屏,直接顯示藍色背景圖片,網路載入後更新資料,Tab切換和滑動都非常流暢
結果展示視訊點選檢視>>>視訊點選檢視>>>

2. 單工程構建優化

3. 元件庫建設

多屏適配元件

我們自己計算 1dp 到底應該佔裝置螢幕上的多少畫素,而不是使用系統預設好的值。將計算好的這個比例設定到專案的環境中,這樣就可以以很低的成本達到按照實際解析度適配出同樣的視覺效果,在開發時也會免去很多換算單位的麻煩。最近我們還支援 Flutter 字型大小不受系統設定影響的方案。UI 一致性完美支援後,UI 自動化測試也能從中受益,只需要維護一套測試程式碼,就可以在多裝置下執行,降低適配成本。

 開源UI通用元件

我們開源了 11 個 UI 元件(連結地址),都是比較貼合業務場景的元件,上面列舉了幾個在社群受歡迎的元件。最近團隊主要精力在開發 Flugy,後面會加強元件庫維護更新工作。

4. XRay 自動化測試框架

我們做自動化測試框架的初衷,是要解決端渲染技術多樣性帶來的可測性難題。因為原有的測試框架是基於原生方案的,滿足不了未來測試要求。所以我們想設計面向未來的自動化測試方案。 我們從手動測試操作過程找到靈感,基於影像處理演算法定位元素,通過驅動能力操控元素,然後再通過影像處理演算法驗證結果。整個鏈路是零侵入的,所以具備非常強的適應性。目前能非常好地支援 Native、WebView、Flutter、小程式、動態模板等技術,並且也可以支援鴻蒙,以及 FusionOS。 為了提升測試程式碼開發效率,我們基於 IntelliJ 開發了外掛,只要熟悉 Python 就能熟練掌握,2020 年為了方便外包寫 case,還提供了錄製回放功能。 這是整個測試 case 編輯、case 執行情況的流程圖,最核心的部分是元素定位,用到了我們自研的影像結構相識度識別演算法,以及阿里達摩院的讀光 OCR 能力,在元素驅動技術上 Android 使用 adb,iOS 使用自研的方案 Dwarf。 列舉酒店列表和首頁測試執行情況,通過我們自研的影像演算法可識別出列表,測試程式碼編輯只需要 recognize_list,然後操作具體的 item 就可以。實際在 XRay 執行過程看是基於酒店列表生成了個類似 Dom Tree 的結構,在執行過程中操作的不是簡單的座標對映,而是對應到具體的元素模組中,提升了可維護性和執行成功率。 除了 XRay 框架的建設,在實際業務使用場景上還涉及到裝置排程,我們基於手機牆排程系統做簡單改造支援自動化測試裝置排程,支援按系統、品牌、機型維度調配。廣泛應用於持續交付的驗證,為無線質量保駕護航,目前也在和無線測試團隊做智慧 monkey(已經覆蓋80+頁面的自動巡檢)。 Can I Use:為了能更好地支援容器同學和前端同學的研發,便於一目瞭然地瞭解各標準在容器層落地支援的情況,前端提供了 CanIUse 檢索平臺,檢視標準在各容器側的支援情況,通過在真機上自動執行單測指令碼做對比測試,確定容器的支援情況。

三、Flutter效能優化

1. 圓角對效能影響

 

2. 合理減少重繪

3. 開啟 SurfaceView

  image.png 注:SurfaceView開啟對低端手機效能提升明顯,高階手機上優勢不大。

四、業務落地

image.png

  • 2020 年伊始,飛豬 Android 端在機票航變和酒店相關簡單業務做了 Flutter 試水,我們對接的首個版本是 1.12,穩定性和效能都符合預期。對於這種簡單的純展示頁面,是非常適合用 Flutter 的。像機票航班詳情頁最近的新需求完全靠 1 人開發就可以。
  • 經過簡單業務試點,穩定性和效能都符合預期,也建立了對 Flutter 信任感,後面開始在比較複雜的業務上試點,用到了非常多的基礎功能,包括視訊播放功能對接,為後面全面開始 Flutter 建設打好基礎。

結果:從效能表現上看,低端機效能上載入耗時優於 iOS,幀率接近原生,CPU 負載、記憶體消耗接近原生,整體的穩定性非常不錯。

  • 純 Flutter 業務試點同時,我們也在做 Web on Flutter 業務試點,H5 程式碼基本不用改造就能執行在 Flutter 上。3月底的版本我們有次大的效能優化,同時也會上線iOS。

五、面臨挑戰與未來規劃

近期更新:飛豬9.7.2.105版本升級到Hummer Flutter 1.22 版本,在poi詳情頁,平均幀率從 53 提升到 56。 3月4號Flutter 2.0 重要釋出,亮點很多,優化多引擎例項支援,對混合棧應用開發更友好。

相關文章