當下,移動動態化已經成爲各大公司都回避不了的問題,產品的快速迭代對技術提出了更高的要求,而移動端的動態化方案也是層出不窮:Hypid、結構化 Native View、React Native、Weex,什麼樣的方案纔是適合本身團隊的呢?本文將分享餓了麼蜂鳥團隊在過去兩年多業務快速增加過程當中,移動動態化方面的實踐和探索。前端
移動指的是移動端,包括安卓、iOS。動態化則是動態部署和邏輯下發到客戶端的能力。移動動態最好的狀態就是讓移動應用和 Web 同樣,想發就發!性能優化
爲何移動端要強調動態化的能力?網絡
緣由有以下三大點:架構
業務迭代太快。當下大部分團隊都是敏捷開發的模式,即便兩週作一次迭代,產品週期仍是會以爲長,有些應用不能及時上線。框架
應用市場審覈慢。安卓基本當天發應用市場,當天就可以有更新。但 iOS 須要約 3-4 天來審覈。假設有些功能須要定時上線,iOS 審覈時間必需要考慮進去。ide
用戶升級週期長。統計代表,每個安卓版本發佈,一週內會有 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 上遷移,雖然它如今還有不足,有些輪子仍是要本身去作。
憑藉以前 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。目前關注的技術方向爲移動跨平臺技術方案、移動端架構、移動端性能優化等。