根據公開的 2018 年移動互聯網行業分析報告,目前支付寶的月活躍用戶已經超過 QQ ,成為國內第二大 App。
支付寶一開始僅僅只是一個單體應用的工具型 App,讓用戶可以在手機完成支付寶相關的業務查詢和操作。2013 年後,支付寶逐步轉型為平臺型 App, 平臺型 App 具有服務化、模塊化、工具組件化的特點。這個時候支付寶的業務不僅僅是支付,還需要給客戶提供很多生活相關的服務,例如餘額寶、繳電費等。2015 年後支付寶成長為超級 App,此時支付寶裡面需要支持大量複雜的業務,同時開放自己的商業能力,用自己流量助力合作伙伴,因此整個 App 面臨開放、動態化、高可用的挑戰,面對這些挑戰,我們把它總結為以下三點:
如何應對複雜的業務協同?
如何滿足業務快速迭代的需求?
如何構建面向未來的開放生態?
利用 Hybrid App 架構,應對複雜的業務協同
App 的業務越來越複雜,不僅僅是內部業務,還包含了大量外部的合作伙伴。如果採用傳統的 App 開發方式很難應對日趨複雜的業務場景。
1.1 Hybrid 技術方案選型
在 Hybrid 技術方案選型方面,我們通過“開發成本、用戶體驗、動態性、複雜業務支持能力、研發難度”五個方面綜合考量。我們篩選出 HTML5、ReactNative/Weex、Flutter 作為備選,並將原生開發作為基準線完成對比。(考慮到近期 Flutter 的熱度持續走高,因此我們納入 Flutter 一併分析。)
首先我們從業務開發成本角度來看:
原生作為最基礎的開發模式,需要雙端都進行開發,無疑成本是最高的;
其次是 ReactNative/Weex,即使是一次開發,同時運行在雙端,但由於是 JS 轉成 Native 組件渲染,實際運行起來仍然存在些許差異,導致開發者在寫業務界面時,部分差異需要通過 Native 端定製開發來解決。整體而言,ReactNative/Weex 已幫助業務方大幅降低開發成本;
接下來是 Flutter,從業務開發的角度來說,Flutter 針對雙端對齊真的下了大功夫。在大多數場景下,Android 端開發完畢之後能無縫跑在 iOS 端,當然這和它自研的引擎有關。只不過 Flutter 需基於 Dart 語言開發,因此對於開發者而言,部分老業務移植的工作量需考慮在內;
最後是 HTML5,帶著成熟的語言,成熟的開發模式,雙端幾乎一樣的表現等特性表明 HTML5 仍然是目前我們能落地的開發成本最低的方案。
接下來我們討論用戶體驗:
首先,原生的體驗毋庸置疑是最好的;
其次是自有渲染引擎的 Flutter,無論是性能還是控件的展現形式,可以說是不亞於原生的體驗;
接下來便是 ReactNative/Weex 方案,通過將前端代碼渲染成本地 Natvie 控件。在早期版本中,由於部分控件優化不到位導致 App 卡頓,因此用戶體驗的表現不足;
最後是 HTML5,完全通過瀏覽器內核進行渲染,藉助預置資源、內核優化等技術,HTML5 可以做到接近原生的體驗,但總體性能仍有差異。
接著是動態性的支持:
在本文第二章節“離線包機制+發佈平臺”,我們會從快速迭代的角度深度分析動態性在支撐高併發業務場景下的重要性。
首先,動態性最優的就是 HTML5 方案:可以訪問在線頁面,服務端即時生效,也可以通過下發資源的方式,進行動態更新;
其次是 ReactNative/Weex 方案,通過一定的定製,開發者可以將前端包熱部署、熱更新。不過相較於 HTML5 具備的“在線+離線”的動態性,該方案仍然存在一定差距;
接下來是原生,Android/iOS 雙端均可以通過一些黑科技手段,進行動態更新,不過由於 iOS 政策禁止,因此在動態性上,原生方案暫時不推薦;
最後是 Flutter,雖然有很強大的熱重載機制,不過由於 Google 的限制,線上版本 iOS 無法做到熱更新,因此在動態性評估中將 Flutter 排在最後。
最後我們聊下各個方案的實現起來的研發難度:
這裡我們暫時將 HTML5 放在第一位,因為做 HTML5 Hybrid 方案,離不開內核優化,內核優化就需要有一定內核研發能力,因此在開發者視角下 HTML5 研發難度最高。如果只是單純的 HTML5 容器,研發難度就會大幅降低;
其次是 Flutter,目前在實際業務應用案例方面,國內較大體量的 App 暫時只有閒魚團隊引用了 Flutter;同時在 Flutter 的 GitHub 中仍然存在大量的 Open Issues 等待解決。而在實戰開發運用過程中,Flutter 的生命週期管理,視圖棧管理,原生頁面切換等問題都需要開發者在前期選型過程中便要重視;
接下來是 ReactNative/Weex,由於這兩個方案開源,且有大量成熟的技術社區支持,方案的研發難度對於開發者而言並不高,同時開源代碼方便修改,更容易上手;
最後是原生方案,如果不考慮做熱修復的話,原生方案無需做任何改動,直接使用即可;若考慮熱修復方案,目前市面也有一些成熟的開源熱修復方案可以直接使用。
綜上所述,我們再考慮了各方的優劣之後,決定採用“HTML5 容器+內核優化”的方式來應對複雜業務的開發問題。接下來我們就介紹下容器的架構。
1.2 容器架構
最上層是原生的 HTML5 代碼,這塊就是大家常見的 Web 開發環境,包括 HTML、CSS、JavaScript等。
下面一層即離線包管理 ,這個我們在第二章節內進行詳細介紹。
再往下是 HTML5 容器層,HTML5 容器作為中間層,將瀏覽器和支付寶底層框架有機結合起來,同時還提供各種生命週期機制、事件機制、擴展插件等內容。
在 HTML5 容器裡面有個非常重要的概念: JSBridge。通過 JSBridge,HTML5 容器將支付寶框架底層以及中間件層提供的各種能力和 HTML5 前端代碼進行聯通,其中包括 RPC(遠程過程調用,用來實現 App 和服務器通信)、支付、掃一掃等。
最下面是支付寶底層框架,提供微應用,微服務等概念。一個 HTML5 應用,也會被框架模擬成一個微應用,通過應用 ID 進行解耦。
1.2.1 JSBridge 介紹
JSBridge 是 HTML5 容器的基石,橋接了 JS 環境與 Native,實現了 Native 代碼和瀏覽器環境的雙向通信,Native 代碼可以通過調用瀏覽器提供的接口運行JS,從而實現調用 JS 函數、傳遞參數到 JS 環境等;而瀏覽器到JS環境的通信是通過 Native 攔截瀏覽器的請求來實現,請求可以是網絡請求或者是一些內部函數的調用。
1.2.2 H5 容器定製化擴展
HTML5 容器提供了 2 種擴展方式:
JSAPI
JSAPI 方式給 HTML5 頁面增加了 Native 功能調用接口,通過實現自定義 JSAPI 類中的 Handler 方式,可以以 Native 的形式實現特定功能,例如調用 Native 加密函數。
事件
HTML5 容器在狀態變化時會發送事件,通過監聽 HTML5 容器特定事件,可以實現對 HTML5 容器生命週期的處理,比如修改加載進度條顏色、修改頁面導航欄等。事件提供了更強的定製性,完全可以滿足對 HTML5 容器的各種自定義需求
1.3 容器穩定性
上面在研發難度中,我們提及到了,HTML5 方式的研發難度是最高的,因為需要定製化內核進行性能及穩定性優化。目前支付寶採用的是阿里集團的 UC 自研內核,並針對支付寶的 HTML5 容器進行了深度優化和定製。如圖所示,UC 內核和系統內核的卡頓卡死率的數據對比效果非常顯著,我們可以直觀地看到 Webview 穩定性的提升。
離線包機制+發佈平臺,滿足業務即時更新
目前支付寶業務的另外一個特點就是需要快速迭代,變化的政策、突發事件都需要我們可以快速把新的業務需求觸達給用戶。但是對於 App 開發者有一個不容忽視的問題,就是應用商店審核。由於審核的存在,App 上開發的業務會有一個統一排期,比如說月底會有新版本,那麼所有的業務進度都得考慮 App 的排期計劃。
2.1 離線包機制
為了做到良好的用戶體驗,我們在容器中引入了離線包機制。通過離線包機制,我們將原有從線上加載的 HTML5 應用,提前下發到本地,通過讀取 IO,或者是內存,進行頁面的渲染,達到接近原生的用戶體驗。
通過發佈平臺,我們可以將不同的 HTML5 離線包,以單獨應用的形式,進行不同維度的下發,使原來 all in 的 Native 發佈模式,改為各業務線自行定製發佈計劃,自行制定發佈標準,自行發佈的並行發佈形式,來滿足業務的快速迭代。
2.1.1 加載機制
通過內存提前加載,定時更新,啟動預加載內存等手段,我們將一個業務包需要用到的資源加載到內存,從而使啟動過程儘量無感知,頁面秒開無白屏。同時,我們還有 Fallback 手段,保證在包損壞或者是未下載完成時,可以通過在線頁面的形式,保證業務的 100% 可用性。
2.1.2 公共資源包機制
所謂公共資源包,即所有 HTML5 離線包都可能會用到的公共資源的集合。公共資源包解決多個 HTML5 應用使用同一資源產生的冗餘問題。如 React 應用使用 ReactJS 框架代碼。您可以將公共資源放入全局資源包,以降低 HTML5 應用體積。
通過公共資源包機制,可有效降低各 HTML5 應用的包體積,從而使更新率提高,頁面開啟速度加快。
2.2 發佈平臺
為了滿足快速迭代的需求,一個強大的發佈平臺也是必不可少的。發佈平臺的核心指標,就是將發佈內容高效、精準的投放到指定的設備上,為了實現這個目標,我們做了如下的努力。
2.2.1 離線包大小管控及差量包機制
HTML5 容器離線包提供了更新機制,以單個離線包作為更新維度。因為單個離線包業務很簡單,所以離線包的大小是可控的,通常小於 500KB。我們通過大量的實踐,總結出來“500KB”這個值,既可以滿足單個業務的內容,也可以更高效地發佈到設備上。500KB,在 4G 的時代,幾乎可以做到用戶無感知更新,即便是 2G/3G 也可以保證一個高的到達率。
上面說的是一個 HTML5 應用的大小。實際上,我們更新的包會更小,發佈平臺會通過 diff 算法,計算出相同 HTML5 應用兩個不同的版本的差量包,差量包通常也就在幾 KB 至幾十 KB 不等,可以做到更高的下載成功率,下載成功率一定程度就意味著實際到達率。
2.2.2 Fallback 機制
在一些極端網絡場景下,新的業務資源包更新失敗,而我們又期望用戶使用的是最新的業務,這個時候 Fallback 訪問機制就會發揮作用。每個離線包資源都會在發佈服平臺上存放一份,在剛剛說到的極端場景下,用戶會訪問服務器的 Fallback 地址獲取資源,從而保障頁面可用。
2.2.3 多維發佈
另外,針對剛開發好的應用,我們可以通過發佈平臺的灰度發佈進行發放,通過外部灰度的形式,對業務指標進行驗證,達到標準後,方可正式發佈,做到可灰度,可回滾。
更優越的 Hybrid 方案:小程序差異化解析
作為超級 App,一個最主要的特徵就是開放。開放就是共享 App 的流量,讓外部夥伴的業務可以通過支付寶觸達用戶,這就面臨一個質量管控的問題。支付寶需要保證這些業務是合法合規的,保障用戶的財產安全。
3.1 離線包 VS 小程序
如果開發一方業務,離線包肯定是非常好的選擇。不過,要是開放給第三方合作伙伴構建生態的話,純 HTML5 頁面就有一些劣勢。
上圖是 HTML5 離線包和小程序的細節對比。總結來說,對於開放給第三方的生態,從應用體驗來講,小程序更加統一,質量有保障;從應用安全角度來講,小程序是訪問我方發佈服務器,不會直接訪問第三方鏈接,安全可控;從研發門檻上來說,小程序是更簡單的前端開發方式,同時也提供了非常豐富的組件。
3.2 小程序解析
小程序其實和離線包本質是類似的,都是一種 Hybrid 應用,但小程序是基於一個定製的 DSL 語言,不是前端的標準,但是類似。在 DSL 規則下業務進行小程序的開發,不支持直接操作 DOM,這種 DSL 規則下的自由可以有效的進行質量管控。
小程序作為一個應用,他擁有完整的生命週期。從開發到關閉,開發者都可以感受到,這點也是 HTML5 所不具備的。另外,每個小程序之間從運行時和持久化上,都是完全隔離的,而且小程序運行在特定進程中,所以和支付寶也是隔離開的。
在渲染性能上,小程序採用雙線程模式將頁面渲染和業務邏輯分別放在兩個單獨的線程中,renderer 運行在 WebView 中,負責渲染界面;小程序業務邏輯運行在單獨的 worker 線程,負責事件處理、API 調用和生命週期管理。兩個線程之間通過 postMessage 以及 onMessage 進行數據交換,數據可以從 worker 線程傳遞到 render 重新渲染界面,同時 renderer 也可以將事件傳遞給對應的 worker 處理。一個 worker 可以對應多個 renderer,方便頁面間數據共享和交互。
在資源加載方面,小程序採用離線化方式加載,也就是說當打開小程序時,小程序離線包必須下載到本地,由於每個版本只下載一次,一方面節省了每次請求的資源開銷,另一方面啟動速度大大提升了。當有新的版本時,發佈平臺自動比對本地安裝的版本和最新版本產生並下發差量包,客戶端不需要下載整個包即可更新小程序至最新版。
3.3 構建生態
通過引入相同的小程序架構,使得小程序,可以作為生態進行多端互投。在支付寶中投放的小程序,可以只經過一些開放接口的適配,即可跑在基於相同小程序架構的 App 中。未來,開發者或第三方服務更多是面向小程序來開發,而 App 則是提供一個統一的架構,真正做到開放生態,用完即走的理念。
關於支付寶自研 HTML5 容器方案
mPaaS 離線包源自於支付寶原生方案,經歷了嚴苛的業務考驗,讓你直接和支付寶使用同一套框架層代碼,擁有統一容器及內核,相對系統內核獲取更低 Crash 率和 ANR 率,適配性強,並具備良好的、彈性的擴展能力,結合具體業務需求定製 JSAPI。
它可以幫助減少 App 白屏、解決 Hybrid App 跨平臺兼容與適配,提升 App 性能並大幅優化原生開發下的包大小。
目前 mPaaS 離線包 Demo 源碼已更新在 GitHub 上,歡迎 Star:
https://github.com/alipay/mpaas-demo
探索 Android 內存優化方法
船長的 2019 ,年報元年
全新的視圖綁定工具 — ViewBinding 使用指南
閱讀更多 程序亦非猿 的文章