幫助我們更好地優化 mPaaS,獲取此次分享 PPT 原稿:t.cn/EZVx3bx
背景
結合上週分享的《模組化與解耦式開發在螞蟻金服 mPaaS 深度實踐探討》,我們已經對支付寶在移動端開發架構的設計思路有了初步瞭解。本文將結合在 iWeb 武漢站的分享,帶領大家進一步瞭解 mPaaS 在移動端動態化方案設計。
首先,分享內容將分為以下三個方面:
- 支付寶動態化方案的探索;
- Nebula 框架淺析;
- mPaaS 科技架構與助力
1. 支付寶動態化方案的探索
任何一種技術方案都是在業務的發展和架構的演化中逐漸探索出來的,因此我們來看一下支付寶架構的演進:

支付寶從最開始的工具型應用,逐漸發展成平臺型應用,一直到現在,已經成為了一個超級 App,它擁有多應用的生態,更加開放和動態化,並且保持著高可用,高效能,高靈敏的強大特性。 隨著 App 的逐漸龐大,整個應用的架構也在進行不斷的調整,來適應各種特性。現在的支付寶客戶端的架構如圖所示:

整體架構分為五層:容器層、元件層、框架層、服務層、應用層。
客戶端整體採用統一的框架開發,模組化的開發模式,完全外掛式的容器,支援模組獨立釋出,方便大規模團隊的並行開發。
在這樣的框架結構中,同樣包括了我們的動態化方案。支付寶中的動態化方案主要有兩種框架:Nebula 和小程式。

這兩種方案不僅解決了需求迭代速度和發版週期之間的矛盾、跨平臺開發、實時釋出等一些普適問題,而且有效地保證了釋出質量,對線上問題進行緊急止血,同時也有助於建立良好的開放生態。
Nebula 是支付寶移動端 Hybrid 解決方案,它提供了良好的外部擴充套件功能,擁有功能外掛化、事件機制、JSApi 定製和 H5App 推送更新管理能力。

主要功能包括:
- 接入 H5App 後臺,方便管理離線或者線上 H5App,實現 H5 應用的推送、更新。
- 載入 H5 頁面,並按照 Session 的概念進行管理各個頁面。
- Android 使用 UCWebView,擁有解決系統級 Webview Crash 的能力,記憶體管理更合理,網路載入提升更快,相容性更好。徹底告別了在Android下相容不同 Webview 的問題。
- 支援自定義網路庫,自定義網路通道;支援自定義鍵盤,自定義 Native View替換 H5 標籤。
- 提供豐富的內建 JSAPI,實現譬如頁面 push、pop,標題設定等功能;支援使用者自定義 JSAPI 和外掛功能,擴充套件業務需求。
- 自帶埋點功能,接入 H5 監控平臺,能夠實時看到頁面載入的效能、錯誤報警和監控。
還有一種動態化方案就是支付寶小程式:

支付寶小程式是一種全新的開發模式,融合了 H5 的易開發性、跨平臺性、Native 效能,讓開發者可以快速開發高效能的頁面,提供優異的使用者體驗。通過使用支付寶小程式,開發者為支付寶開發了大量優質的小程式,豐富了支付寶生態能力。小程式開放給開發者更多的 JSAPI 和 OpenAPI 能力,通過小程式可以為使用者提供多樣化便捷服務。
2. Nebula 框架淺析
Nebula 的架構如圖所示,從上至下依次為 H5 應用層、服務層、原生框架層:

- H5 應用層:基於 HTML 和 JavaScript 技術開發,在 H5 容器上執行的手機應用,它擁有跨平臺的特性,配合離線包的使用可以完成實時熱修復的功能。
- 服務層:為開發者提供了高階語言的 API 來使用手機系統資源,包括:
- 視窗系統,開發者可以使用它來創造應用 UI,包括文字,圖片,按鍵及定製 View
- 資源管理,通過它開發者可以方便的訪問如多語言文字,圖片和佈局等非程式碼資源
- 應用生命週期管理,它決定應用在手機系統裡的開始,結束以及強制關閉的時機
- H5 容器
- 原生框架層:是手機系統的基礎層,它提供了標準 API 來讓高階語言(比如 Java 和 Object-C)使用底層的硬體,幷包含了許多為硬體訪問的專有軟體庫。當上層呼叫某個框架 API 來訪問硬體時,手機系統將載入相應的軟體庫。
整個 Nebula 框架的核心部分就是 H5 容器,下面看一下 H5 容器的結構:

在容器裡面有 H5Service、H5Session 和 H5Page 這樣三個概念
H5Service,H5Session 和 H5Page 都是從 H5CoreNode 類擴充套件而來,以 H5Service 為根節點,它與其他類一同形成了樹狀結構構成了頁面流程和導航。在一般情況下,H5Pages 是 H5Session 的子節點,而 H5Sessions 是 H5Service 的子節點,在任何情況下只有一個 H5Service 根節點存在。
-
H5Service:是 Nebula 裡維護 H5 應用全域性狀態的基礎類, 在 H5 應用的生命週期內只有一個 H5Service 的單例全域性例項,H5Service 可以進行的操作包括:
- 建立且開啟一個新的 Web activity
- 建立且開啟一個新的 Web page
- 從共享空間儲存和讀取資料
- 註冊外掛和 Provider
- 監聽應用的生命週期
-
H5Session:一個 H5Session 是由一疊 H5Pages 組成的完整業務流程。例如一個收銀臺的流程包括:一個購物車的小結頁面,一個結賬方式的選擇頁面,和最後一個結賬確認頁面。所有的頁面都可以獨立存在運作, H5Session 在其中的作用是把這些頁面組織起立,按照業務邏輯把它們按序排列來完成業務。當你使用 H5Service 建立且開啟一個新的 Web page 時,如果當前沒有 H5Session 的話,一個新的 H5Session 例項將被建立,併為後續建立的 Web page 共享。你可以從 H5Session 中移除頁面直到頁面疊為空,也可以使用 H5Session 所提供的方法來獲取首頁,以及監聽該 H5Session 的生命週期。
-
H5Page:是使用者看得見,摸得著的頁面,也是應用生命週期中最重要的一部分。你可以通過 URL 來載入內容,用 H5Param 來定製頁面的外觀和行為,甚至可以通過獲取 H5Page 的檢視層次,把 H5Page 檢視和其他原生 UI 部件一起內嵌到同一個佈局中。
下面是 H5 容器的幾個重要組成部分:
-
API 管理器主要管理 JS API:Nebula 中已經提供許多內建的 JS API 供開發者使用,比如操控 UI,顯示對話方塊和 Toast,以及使用網路 RCP 服務等。
-
外掛管理器主要管理 Plugin:如果現有的 JS API 無法滿足你的業務需求,你也可以選擇創造一個新的外掛。你只需把原生程式碼打包在外掛中,在管理器裡註冊該外掛,便可在 Javascript 層使用新的 JS API 了
-
JS Bridge 是連線原生層和 JavaScript 的溝通橋樑:它將 JavaScript 程式碼轉譯成能在系統框架執行的位元組碼,同時也把原生層的資料結構轉成 JavaScript 物件使其能在 JavaScript 層處理。這裡 Nebula 針對JS Bridge 做了一些優化:
-
在 Android 裡,js 呼叫 native 的通訊是通過 console.log 的方式,這個和其他容器實現不一樣,其他容器一般通過 prompt 的方式來實現的,但是使用 prompt 的方式,有兩個弊端:
- 使用 prompt 會阻斷整個瀏覽器的程式,如果 native 處理時間一長,會導致頁面假死。
- prompt 是在 UI 層面上會彈出一個模態視窗,在 native 沒有對其進行捕獲處理的話,會造成一個問題。一旦這個頁面放在非此容器的環境下,就會出現一個很詭異的 prompt 彈窗。在支付寶內,曾經出現過這個問題,天貓頁面在支付寶 app 裡的時候,由於容器機制不同,頁面中 bridge 指令碼沒有判斷環境,導致頁面中 js 呼叫 API 的時候,在頁面上出現了 prompt 的模態對話方塊,嚴重影響了使用者體驗,但是如果使用 console.log 的話,就不會出現這個問題。console 的方式避免了不相容環境的體驗問題和同時也避免了頁面的假死。
-
jsbridge 注入的時機,由於業務邏輯要依賴 bridge,所以業務的所有邏輯都會在 bridge ready 之後才會觸發,而 bridge js 本身執行是要一定的時間的,因此注入的時機對於效能的影響顯得非常的重要。但由於 H5 頁面的生命週期和容器的生命週期是相互獨立的,因此在 H5 生命週期的哪個階段注入這段 bridgejs,對於效能的影響就顯得異常重要。
-
現在在支付寶內使用的方式為監聽 H5 生活週期的事件,比如說當 Webview 設定 title 結束之後,Android 會放出一個 onReceivedTitle、shouldInterceptRequest 等事件,iOS 會嘗試在 webViewDidStartLoad 事件,在監聽到這些事件之後,立即注入 bridgejs,讓其在 H5 生命週期儘早執行。通過這種方式的注入,經過測試,最早能在頁面載入開始後, 50ms 以內就能成功注入 bridgejs。
-
-
Event 機制:Nebula 提供了一套事件機制來管理事件在 H5Page,H5Session 和 H5Service 之間的流通順序。一個 H5Event 可以在 H5Page, H5Session 或 H5Service 任何一層發生,事件派遣分為兩步完成事件攔截。
這個步驟中事件派遣的順序為 H5Service -> H5Session or H5Page。
事件可以在任何節點被攔截 (如果 interceptEvent() 返回 true ),也可以在任何節點被處理 (如果 handleEvent() 返回 true ):如果事件在派遣過程中被攔截或處理,該事件將被視為已被消費且不再繼續流通。如果在派遣過程後事件依舊沒有被攔截或處理,會有錯誤拋給呼叫方處理。
僅僅使用傳統的 H5 技術展示線上頁面,很容易受到網路環境影響,因而降低 H5 頁面的效能。
在 Neblua 中我們使用離線包技術來解決這個問題。離線包是將包括 HTML、Javascript、CSS 等頁面內靜態資源打包到一個壓縮包內,它的目錄結構如圖所示:

使用離線包可以使容器內的 H5 應用具有接近 Native 的體驗,主要優勢如下::
-
減少網路環境對 H5 應用的影響:通過下載離線包到本地,然後在客戶端開啟,把開啟H5頁面的操作從網路 IO,變成磁碟 IO。直接從本地載入離線包,不僅最大程度地擺脫網路環境對 H5 頁面的影響,而且增強了使用者體驗。
-
提升使用者開啟 H5 應用的體驗:通過離線包的方式把頁面內靜態資源嵌入到應用中併發布,當使用者第一次開啟應用的時候,就無需依賴網路環境下載該資源,而是馬上開始使用該應用。
-
實現動態更新:在推出新版本或是緊急釋出的時候,您可以把修改的資源放入離線包,通過更新配置讓應用自動下載更新。因此,您無需通過應用商店稽核,就能讓使用者及早接收更新。
下面介紹一下離線包的渲染過程 當 H5 容器發出資源請求時,其訪問本地資源或線上資源所使用的 URL 是一致的。H5 容器會先截獲該請求,截獲請求後,發生如下情況:
- 如果本地有資源可以滿足該請求的話,H5 容器會使用本地資源。
- 如果沒有可以滿足請求的本地資源,H5 容器會使用線上資源。 因此,無論資源是在本地或者是線上,WebView 都是無感知的。

離線包的下載依賴使用者當前的網路。一般情況下,只有在連線 WIFI 的情況下才會在後臺下載離線包。如果使用者處於行動網路下,不會在後臺下載離線包。如果當前使用者點選 APP,離線包沒有下載好,使用者就要等待離線包下載好才能用。
為了解決離線包不可用的場景,fallback 技術應運而生。每個離線包釋出的時候,都會同步在 CDN 釋出一個對應的線上版本,目錄結構和離線包結構一致。fallback 地址會隨離線包資訊下發到本地。在離線包沒有下載好的場景下,客戶端會攔截頁面請求,轉向對應的 CDN 地址, 實現線上頁面和離線頁面隨時切換。
那麼本地資源如何定址呢,我們設計了獨特的虛擬域名機制,僅對離線應用有效。當頁面儲存在客戶端之後,WebView 如果要訪問的話,是通過 file schema 來從本地載入訪問的。然而,使用者就能在位址列裡直接看到 file 的路徑,這就會導致以下問題:
- 使用者體驗問題:當使用者看到了 file 地址,會對暴露的地址產生不安全感和不自在。
- 安全性問題:由於 file 協議上直接帶上了本地路徑,任何使用者都可以看到這個檔案所在的檔案路徑,會存在一定的安全隱患。 基於如上問題的考慮,採用虛擬域名的機制而不直接使用 file 路徑來訪問。虛擬域名是一個符合 URL Scheme 規範的 HTTPS 域名地址,例如 xxxxxxx.h5app.example.com
Nebula 裡面的 H5 容器和離線包,在傳統的 Hybrid 框架的基礎上進行了極致的優化,使整個 H5 應用具有如下特點:
- 對網路鏈路強依賴的弱化
- 增強對裝置能力的支援
- 增強的使用者體驗
在效能方面,Nebula 在支付寶中經過了億級使用者的考驗,crash 和 anr 以及其他穩定性指標有保障。 Android 平臺基於 UCWebview 深度定製,crash 率和 anr 量遠低於系統webview,擁有解決系統 Webview 問題的能力。 圖中展示的就是在 Android 端,UCWebview 和系統 Webview 之間崩潰率和 ANR 率的對比,穩定性的優勢顯而易見。

最後看一下小程式與 Nebula 支付寶小程式複用 Nebula 容器技術棧,重構了開發方式,對外暴露有限個 jsapi 介面,讓 app 開發更簡單,更加便捷利用支付寶的能力,進而釋出、推廣、運營。小程式本質上是也是一個 H5 App 離線包,但是有一些自己的特點。
- 小程式是為第三方 App 服務的,執行在獨立程式,它的穩定和閃退不會影響到主 App,也支援二方 App 執行在主程式。
- 小程式是支援保活的,極大的提升二次開啟的體驗。
3. mPaaS 技術架構與助力
Nebula 有這麼大優勢,現在不僅在螞蟻金服內部使用,也能夠提供給外部來使用。
首先什麼是 mPaaS 呢,mPaaS 全稱是 Mobile Platform as a Service 。是螞蟻金服獨創的移動研發平臺,它源於支付寶 App 近 10 年的移動技術實踐和思考,為移動開發、測試、運營及運維提供雲到端的一站式解決方案,能有效降低技術門檻、減少研發成本、提升開發效率,協助生態夥伴快速搭建穩定高質量的移動 App。

在 mPaaS 中,我們將 Nebula 的 H5 容器、jsapi 、離線包、小程式這些模組作為一個單獨的元件來進行輸出,在客戶端中進行配置。任何一個 App 通過 mPaaS 外掛,新增對應的模組,整合這些功能,只需要這樣簡單的操作,就可以讓你的應用具有和支付寶一樣強大的動態化能力。

同時 mPaaS 提供的小程式模組,允許使用者把執行在支付寶上的小程式,無縫的遷移到自己的 App 中,做到【跨平臺跨應用】開發,提高程式碼的複用能力 Nebula 元件化輸出,配合 mPaaS 提供的 MDS (移動釋出服務) 來實現動態更新。
mPaaS 提供的 MDS 服務,能夠讓每次釋出更新就像發郵件一樣簡單。


MDS 具有智慧灰度釋出的能力,可以通過內部灰度,外部灰度多重驗證,保證在正式釋出之前,釋出的產品質量有充分的保證,同時提供多種升級策略,包括指定人群地域、機型,系統版本,網路環境等多種規則。對於離線包來說,更新離線包的下載對網路環境要求較高,包的大小越大,更新的成功率越低,在 mPaaS 中,我們採用增量差分的更新能力,減少資料冗餘及裝置頻寬,在行動網路條件下優勢明顯。同時保證更新功能的高可用性,升級介面可用率達 99.99%,線上分鐘級觸達。
下面是 Nebula 的生態基礎,首先在集團內部,我們已經支援了不少產品,同時通過 mPaaS ,我們也與外部客戶合作,將我們的技術能力輸出給他們,典型的幾個案例,包括 12306 客戶端,廣發發現精彩客戶端,上海地鐵,蘇州銀行等。

尤其是 12306,使用 mPaaS 改版之後,客戶端整體的體驗更加優越。12306 整個客戶端絕大部分都是使用的 H5 技術,他們就是使用 Nebula H5 容器 配合離線包來實現,無論是頁面開啟速度,還是UI事件響應,體驗幾乎接近 native。在更新發布方面,12306 的 app 包很少更新,以 AppStore 上的釋出記錄來看,今年只提交了兩個版本,基本上都是通過動態化的方式完成業務的迭代釋出。
總結下來,螞蟻金服 mPaaS 中就是通過「Nebula H5容器 + 離線包 + 小程式 + MDS」這樣的方式來實現移動端的動態化方案。想要上手體驗看看嗎?歡迎下載 Android Demo:

- 注:暫時不支援 iOS 使用者掃碼下載
關於 mPaaS 移動端動態化的具體實踐,如果你有更好的思路或建議,也歡迎一起探討交流。
往期閱讀