移動動態化方案在蜂鳥的架構演進(含React Native與Weex對比)

當下,移動動態化已經成爲各大公司都回避不了的問題,產品的快速迭代對技術提出了更高的要求,而移動端的動態化方案也是層出不窮:Hypid、結構化 Native View、React Native、Weex,什麼樣的方案纔是適合自己團隊的呢?本文將分享餓了麼蜂鳥團隊在過去兩年多業務快速增長過程中,移動動態化方面的實踐和探索。

什麼是移動動態化?

移動指的是移動端,包括安卓、iOS。動態化則是動態部署和邏輯下發到客戶端的能力。移動動態最好的狀態就是讓移動應用和 Web 一樣,想發就發!

爲什麼移動端要強調動態化的能力?

原因有如下三大點:

  •     業務迭代太快。當下大部分團隊都是敏捷開發的模式,即使兩週做一次迭代,產品週期還是會覺得長,有些應用不能及時上線。

  •     應用市場審覈慢。安卓基本當天發應用市場,當天就能夠有更新。但 iOS 需要約 3-4 天來審覈。假設有些功能需要定時上線,iOS 審覈時間必須要考慮進去。

  •     用戶升級週期長。統計表明,每一個安卓版本發佈,一週內會有 70% 的用戶更新,一個月其餘用戶才能陸續完成更新。

移動動態化方案共性,有如下三點:

  •     跨平臺。

  •     佈局。約定 DSL,保證渲染性能。

  •     邏輯。Android 和 iOS 必須共用解釋器。

蜂鳥團隊的現狀與業務特點

蜂鳥團隊現狀

蜂鳥團隊於 2014 年成立,初衷是爲了承接餓了麼的物流業務。隨着時間推移,訂單量從每日幾千單到百萬單,配速員也達到百萬數量,服務品類涉及外賣、商超、鮮花、蛋糕、文件等,蜂鳥提供全時段配送,配送服務覆蓋全國 1200 多個城市。

蜂鳥團隊的業務特點

蜂鳥團隊的業務主要有離散性和突發性兩大特點,如下圖:

從業務曲線可以看到兩個很明顯的波峯,這是午、晚用餐時間。同時,如果運營方面配置一些活動,會導致這兩個波峯徒增。所以,動態方案要想把這兩個時間段服務好,必須要考慮流量陡增下的性能壓力。

蜂鳥團隊的技術特點和挑戰

蜂鳥團隊的技術特點和挑戰,我主要分享重度依賴、網絡環境複雜、重度使用和 28 定律這四個方面。

重度依賴

當前蜂鳥有衆包、團隊和送送三部分業務,右側是一些功能展示,如下圖:

這樣的工具型應用,需要對 APP 有更強的控制、監控等能力。必要時還要做到強制更新。

對應到動態方案的話,控制能力就需要動態方案必須具備動態降級的能力、監控能力,實時的性能監控和業務埋點監控。強制更新方面,動態方案必須做到用戶無感知的熱更新。

網絡環境複雜

餓了麼小哥,每天穿梭在大街小巷、地下商超,他們的網絡環境非常不穩定。據統計,有近 25% 的用戶請求還來自非 4G 環境。

整體來說的網絡環境複雜、信號差和 DNS 污染,那麼動態方案就要解決 DNS 攔截、弱網環境下資源下發等問題。

重度使用

無論是下雨、下雪,還是發洪水大家都會叫餓了麼。

配送員在高峯期的運動曲線,如下圖:

面對這樣爭分奪秒的準時達壓力,如果動態方案不給力,會導致應用出現崩潰或卡頓,騎手必定不會有好的體驗,甚至影響送餐時間。所以我們的動態方案一定要保證性能和穩定性。

28定律

相信很多公司的應用都符合類似 28 定律,蜂鳥也不例外。

如下圖,蜂鳥的 28 定律

可以從圖中看出,大部分騎手日常使用的主流層面,可以採用 Native 來開發,這部分重度使用的佔比約 20%,其餘 80% 的功能都可以考慮動態化方案(H5)。

蜂鳥團隊的動態化架構演進

蜂鳥的動態方案經過 Hypid、React Native 和 Weex 三個主要階段。

第一階段:Hypid

在 Hypid 方案上,以 H5 的動態性爲基礎,通過 Jspidge 做橋樑,與 Native 進行通信,之後通過 URL Router 進行跳轉,架構如下圖:

這套動態方案的優點顯而易見,這裏主要介紹開發效率、更新體驗和跨平臺三方面:

  •     開發效率。Web 經過多年的應用實踐,已經擁有完整的開發流程和開發工具,開發一個 H5 頁面非常快速。開發效率這一因素不能忽略,因爲初期產品的想法和落地速度會直接影響產品的命運。

  •     如蜂鳥送送,初期沒有原生的資源去支撐,就用原生包殼,內部全部用 H5,這樣的情況堅持了兩月左右,爲蜂鳥送送前期的方案驗證做了很大的貢獻。

  •     更新體驗。因 H5 和原生耦合只有擴展的 Native API,只要把這些 API 維護足夠全,開發的業務功能就可以在完全不用更新 APK 的情況下,做到熱更新。且用戶下一次打開應用是最新的,這和 Native 的升級體驗相比簡直是一天一地。

  • 跨平臺。之前安卓和 iOS 代碼需要開發兩次,現在一個功能決定用 H5 後,由一個工程師來開發一套代碼即可。

這套動態方案很大的缺點就是用戶體驗差,當用 H5 做一些複雜的功能或動畫時,可能會卡頓的和 PPT 一樣。因爲 H5 的體驗問題,蜂鳥的原則是經常更新的且功能不復雜的頁面會選擇用 H5。

第二階段:React Native

這個動態方案完全脫離了以 H5 爲基礎的 Hypid 方案,通過自定義 DSL 將 UI 渲染成原生控件,這樣一來, RN 的頁面就保證了原生的體驗和 Web 的效率。

除了上一點,還有組件化開發、複用率高、Android 和 iOS 95% 的代碼共用和測試效率高等優點。

鑑於這些優點,蜂鳥在 React Native 上做了很多事情,如 Crash 優化、基礎控件沉澱、Bundle+ 圖片熱更新、首屏加載優化和 Redux 單項數據流等。

正當享受 React Native 帶來的開發體驗和應用體驗提升時,蜂鳥遇到 RN 的一些痛點,如 ScrollView 性能、Bundle 包過大、很多優化都需要修改源碼和 peaking change 等。

第三階段:WEEX

面對如上這些痛點,不知如何應對時,WEEX 來了。官方宣傳的輕量、可擴展和高性能等特點,讓蜂鳥團隊眼前一亮。

經深入研究後,蜂鳥發現 WEEX 和 React Native 如出一轍,那麼爲什麼要選擇類似的方案呢?

我們隊 WEEX 和 React Native 兩者基於 JS 引擎、語法、數據流、性能、開發體驗及熱更新等維度進行了對比。

如下圖,是 WEEX 和 React Native JS 引擎對比

React Native 在安卓和 iOS 使用的都是 JsCore,WEEX 在安卓端使用的是 UC 精簡版 V8。如上圖中的圖表可以看出,V8 相比 JsCore 要勝一籌。

WEEX 和 React Native 語法對比。語法方面,React Native 使用的是 React,WEEX 使用的是 Vue。雖然兩套方案都實現瞭如響應式,組件化、狀態管理等功能。

如下圖,是兩者簡單 Demo 的實踐:

實踐發現,WEEX 相比 React Native 要優雅一些,是因爲 Vue 有很多自定義標籤,當在做一些 UI 和邏輯交雜在一起時,會讓代碼簡潔很多。

 WEEX 和 React Native 的數據流對比,React Native 使用 Redux,而 WEEX 使用 Vuex,不是 WEEX 不能使用 Redux,而是 Vuex 更適合 WEEX。

如下圖,是兩者的數據流,大同小異:

但 Vuex 在實現一些計算屬性時,能在更細的顆粒度去更新 UI,而 Redux 只能實現到組件的級別,這樣的點很多的話會帶來性能上的差異。

如下圖,是 WEEX 和 React Native 的性能對比,左側是 WEEX 官方給出的與 React Native 在性能方面的對比圖:

在渲染時間和內存佔用方面 WEEX 要優於 React Native,在 CPU 佔用方面兩者相差不大,FPS 上 WEEX 要稍遜於 React Native。

在 ListView Android 方面,React Native 目前採用 ScrollView,WEEX 使用 Recyclerview 實現,性能稍好。

同時 WEEX 在增強開發、指定線程、首屏渲染和性能監控等方面也做了優化。

如下圖,是 WEEX 和 React Native 的開發體驗對比

和 React Native 相比,WEEX 在打包、監控性能、跨平臺等方面都有一定優勢。總體來說,React Native 更像是一個技術框架,WEEX 更像是一個業務框架。

如下圖,是 WEEX 和 React Native 的熱更新對比:

React Native 與 WEEX 官方都表示支持熱更新,但他們的實現方式不同。在 React Native 上可通過把圖片打包下發到本地來實現更新。

WEEX 有兩個方法,一是選擇本地資源加載,二是像網頁一樣直接加載頁面。

如下圖,是 React Native 與 WEEX 的對比總結

React Native 更像一個先驅者,擁有超強的社區人氣,但也因開源社區維護代碼的原因處於一個野蠻生長的狀態。而 WEEX 是站在 React Native 的肩膀上,做了各種微創新,實現更多貼心的小細節。

基於 WEEX 性能、穩定性等方面都比 React Native 高,蜂鳥決定把動態化方案往 WEEX 上遷移,雖然它現在還有不足,有些輪子還是要自己去做。

蜂鳥團隊 WEEX 實踐

憑藉之前 React Native 相關的實踐經驗,基於 WEEX 做了一套更完整的動態方案。涉及以下幾個方面,如下圖:

統一的pidge 

在 Android & iOS 端,約定相同的方法名、參數,在 JS 層抹平平臺差異以及統一分類管理暴露給業務的 API。

把這樣的統一 pidge 方案提供給業務部門,他們只需關心暴露的 API,而不需要關心下一層平臺的兼容,大大提升開發效率。

加載更新策略

加載更新方面,我們約定了一套自有協議,有 Page、URL 和 Tag,通過封裝的 Router,就可以做到頁面級的跳轉。

這樣一來,我們很輕鬆地做到了頁面的跳轉、解耦和頁面的降級。當頁面出現問題,只需要把 URL 改成降級之後的 H5 頁面下發即可,用戶觸及到的就是修復之後的 H5 頁面了。

如下圖,是預加載策略

當 H5 頁面下發到客戶端之後,會對本地資源進行檢查,如果有 JS 文件,就忽略,沒有的話就把頁面下載。當用戶打開頁面,再去看本地,存在資源的話直接加載,不存在的話就即時下載再運行,與傳統的 Web 流程相似。

性能監控

性能監控用來判斷線上服務是否正常,是整套方案最重要的部分。

WEEX 可以很方便地將所有的參數全部拿到且通過反射拿到所有的性能數據傳到雲端。

基於這些數據,我們就可以知道線上有了哪些頁面,它的渲染是否有問題。基於這些問題,就可做相應的優化。

如下圖,是線上的數據情況

監控三個指標,分別是 JS 引擎的初始化時間、頁面打開時間和網絡時間。因大部分 WEEX 頁面都是業務,所以說業務埋點必不可少。餓了麼也實現了一套框架,將業務埋點傳給服務端,然後方便產品去制定一些產品方面的策略。

JS 的錯誤統計

可以捕捉 JS 端拋出的錯誤,如果所處團隊是前端主導,可傳給前端。如果是 Native 主導,可通過蒐集平臺將這些崩潰上傳,在後臺看到這些錯誤之後,找到相應的代碼去修復。

Native 的錯誤

有了 JS 錯誤,Native 錯誤也不能忽略。

如下圖,是 WEEX 動態方案上線一週之後線上拋的錯誤:

從圖中可以看到都是個位數,這一點其實當時也很驚訝,WEEX 確實做得很穩定,這一點超出預料。

共用組件和 API

之前蜂鳥在 React Native 上面的一些實踐,積累了一些很常用的組件和 API。WEEX 和 React Native 都是使用 JS 實現,所以我們很方便的將 RN 的控件轉化爲 WEEX 控件。

如下圖,是實現的組件和 API,幾乎可以滿足中小團隊的日常使用:

調試工具

這方面 WEEX 做的很貼心,雖然沒有整合到整個初始化的項目中,但開源了幾個庫,可把代碼拷貝到業務中進行使用。

WEEX 還可支持 Debug 模式顯示調試工具、支持 hot reload、方便的查看性能指標和 Shell 腳本一鍵打包等功能。

綜上所述,基於這些維度實現的框架,可以方便的讓業務來使用。

如下,是餓了麼和蜂鳥用 WEEX 實現的兩個頁面:

餓了麼的第二個發現頁面,就是基於 WEEX。蜂鳥 APP 可能大家接觸不到,上圖是當前通知的活動界面,還有大量的新功能正在接入。

如果你正在考慮 WEEX 與 React Native 方案,或是正在接入 React Native。看到這篇文章,你可以去調研以下 WEEX 方案,可能你會有另一種選擇。

以上內容根據許錦洋老師在 WOTA2017 “移動端架構演進”專場的演講內容整理。

負責餓了麼蜂鳥 APP 的架構、研發等工作。擁有餓了麼商家、風行者、蜂鳥衆包等多款 APP 開發工作經歷,並從 0 開始架構和開發了整個蜂鳥團隊 APP。目前關注的技術方向爲移動跨平臺技術方案、移動端架構、移動端性能優化等。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章