深入解讀-微信小程式SDK

美團點評點餐發表於2017-06-29

前言

  這篇文章主要是對小程式官方文件做部分深入解讀;讓大家瞭解小程式實現背後的機制原理。
由於筆者沒有獲取到微信官方提供的小程式實現原理圖,很多內容都是通過閱讀文件資料反推和理解所得,如有誤解之處,望指正。
本文建議閱讀時間: 5min

目錄

  • 小程式SDK
    • 定義
    • JS-SDK
      • 小程式基礎庫與JS-SDK的共同點
      • 小程式基礎庫與JS-SDK的不同點
    • 小程式基礎庫檢視方法
    • 小程式基礎庫與客戶端之間的關係
    • 小程式基礎庫更新機制
    • 微信版本分佈
    • 微信版本和基礎庫版本
    • 開發者工具切換基礎庫版本
    • wx物件
  • JsBridge
    • webview與客戶端的關係
    • 兩種JsBridge實現思路
    • 微信關於JsBridge的實現
  • 通訊機制
    • 架構介紹
    • 執行環境
    • 事件
    • 生命週期事件
    • UI事件
    • Page.prototype.setData
  • 總結

小程式SDK

官方文件稱其為“基礎庫”。

  這是一個很寬泛的名詞,只是覺得很重要,但說不好它具體有什麼作用。我總結了小程式5月帶給我的驚喜,它支援的功能也越來越豐富,體驗也越變越好,而這些動作如果用專業一點的術語概括就是“升級基礎庫”。
微信從開放內測到現在,微信基礎庫已經從的 v1.0.0 升級到了 v1.3.0
那麼,“基礎庫”到底是什麼東西?

小程式基礎庫提供豐富的微信原生API,可以方便的調起微信提供的能力,如獲取使用者資訊,本地儲存,支付功能等。

  這是官方對於“基礎庫”的定義。我們知道小程式的開發十分類似於現在的移動web開發,而移動web能使用到手機系統功能,app特色功能是非常有限的,而“基礎庫”的作用就是為了擴充小程式這方面能力,讓其功能與表現更接近原生app。

JS-SDK

我們發現“基礎庫”的功能和微信的 JS-SDK 十分類似,順便再回顧下微信 JS-SDK 又是做什麼的呢?

  微信 JS-SDK 是微信公眾平臺面向網頁開發者提供的基於微信內的網頁開發工具包。通過使用微信 JS-SDK ,網頁開發者可藉助微信高效地使用拍照、選取圖片、語音、位置等手機系統的能力,同時可以直接使用微信分享、掃一掃、卡券、支付等微信特色功能,為微信使用者提供更優質的網頁體驗。

小程式基礎庫與JS-SDK的共同點

  • 為當前應用調起手機系統能力和微信能力;
  • 都需要基礎庫的支援;

小程式基礎庫與JS-SDK的不同點

  • 支援的API:小程式基礎庫對系統能力和微信能力做了更全面的封裝,包括網路請求、儲存等,而網頁版JS-SDK相應的功能直接呼叫window能力;
  • 引入方式:小程式基礎庫直接整合到微信的不同版本中,JS-SDK是以一個js檔案的形式被引入專案裡;

小程式基礎庫檢視方法

官方API : getSystemInfogetSystemInfoSync

wx.getSystemInfo({
    success: function(obj) {
        obj = obj || {};
        console.log('SDKVersion: ', obj.SDKVersion);
    },
    fail: function() {
        console.error('[error]: getSystemInfo failed.');
    }
});複製程式碼

返回物件中SDKVersion的值就是該微信版本攜帶的小程式基礎庫的版本號。
注意:該屬性在小程式版本 v1.1.0 才開始支援。

小程式基礎庫與客戶端之間的關係

小程式的能力需要微信客戶端來支撐,每一個基礎庫都只能在對應的客戶端版本上執行,高版本的基礎庫無法相容低版本的微信客戶端。

官方的這種說法存在一些問題。現在基礎庫版本和客戶端版本並不是一一對應關係。客戶端可以主動升級小程式基礎庫版本達到灰度上線新版的目的,所以必然存在一個客戶端版本對應多個基礎庫版本的情況。

小程式基礎庫更新時機

為了避免新版本的基礎庫給線上小程式帶來未知的影響,微信客戶端都是攜帶 上一個穩定版 的基礎庫釋出的。
在新版本客戶端釋出後,我們再通過後臺灰度新版本基礎庫,灰度時長一般為 12 小時,在灰度結束後,使用者裝置上才會有新版本的基礎庫。

以微信 6.5.8 為例,客戶端在釋出時攜帶的是 1.1.1 基礎庫(6.5.7上已全量的穩定版)釋出,在 6.5.8 釋出後,我們再通過後臺灰度 1.2.0 基礎庫。

筆者使用的IOS裝置更新到v6.5.8時對應的 SDKVersion 是 1.2.0, 但截止發稿日,該值已經變成了 1.2.4。
“細思恐極”,如果我們已經完成一臺裝有 6.5.4 版本微信的Oppo手機對小程式的相容測試,很有可能過幾天這臺Oppo手機將小程式基礎庫更新到新版本導致小程式不可用。
建議:瞭解產品的使用者手機微信版本分佈,確定迴歸覆蓋範圍,完成迴歸測試。

微信版本分佈

IOS 裝置微信版本分佈 (資料截止 2017-06-16)
IOS 裝置微信版本分佈 (資料截止 2017-06-16)

Android 裝置微信版本分佈 (資料截止 2017-06-16)
Android 裝置微信版本分佈 (資料截止 2017-06-16)

這是我們點餐小程式中使用者各版本微信的佔比圖。通過這兩張圖我們能夠清晰的得出目前使用者使用的微信版本分佈,就能夠制定針對性的測試覆蓋方案。

微信版本和基礎庫版本

基礎庫更新時機 那小結我們提到,小程式的基礎庫和微信版本並不是一一對應關係,且隨著基礎庫和微信的不斷升級,它們的對應關係在時刻發生著變化。
下面是我整理的小程式基礎庫和微信版本對應表。

微信版本和基礎庫版本對應關係 (統計時間:2017-06-10)
微信版本和基礎庫版本對應關係 (統計時間:2017-06-10)

開發者工具切換基礎庫版本

微信web開發者工具
微信web開發者工具

在使用新API、新特性的時候,可以通過切換基礎庫版本完成相容性測試。

wx物件

小程式基礎庫的所有功能全部封裝在 wx 全域性物件中,開發者可以在小程式邏輯層程式碼的任何地方呼叫該物件的方法。

看到 wx 物件,使用過 JS-SDK 的朋友表示很熟悉。我們在前面章節 小程式基礎庫與JS-SDK 對它們做了簡單的比較,下面深入學習它們出於同源的技術:JsBridge
下一節,我們詳細講解一下JsBridge的原理和實現。

JsBridge

  Native層需要暴露一些方法給js呼叫,比如,彈Toast提醒,彈Dialog,分享等等,有時候甚至把h5的網路請求放著native去完成。原因很簡單,Native有更好的效能,更一致的表現和體驗。這就是 JsBridge 技術。

webview與客戶端的關係

webview是客戶端的一個可呼叫的元件,且客戶端可以對webview做函式,事件的封裝,可以攔截webview的請求做統一控制,也可以向webview注入方法供JS呼叫等。

兩種JsBridge實現思路

  • 通過重寫 JavascriptInterface介面;
  • 在客戶端攔截所有WebView的Url請求;

通過這些方式能夠實現JS和客戶端通訊,調起客戶端以及手機系統能力。

微信小程式JsBridge的實現

  wx 就是客戶端暴露給小程式的JsBridge介面。而這個封裝的JsBridge非常強大,它不僅僅支援toast,彈框等簡單功能,甚至包括網路request請求,快取操作,手機硬體裝置藍芽、重力感應等。下一個章節,我們介紹微信如何使用 JsBridge、檢視層、邏輯層互動操作。

通訊機制

架構介紹

邏輯層、檢視層、JsBridge互動關係圖
邏輯層、檢視層、JsBridge互動關係圖

這張圖展示了檢視層、邏輯層之間通訊方式,以及JsBridge起到紐帶的作用。我們可以做以下幾點總結:

  • 檢視層和邏輯層分開在兩個執行緒中執行;
  • 檢視層、邏輯層通過事件完成通訊;
  • JsBridge一方面傳遞基礎功能,另一方面做檢視層和邏輯層的資料傳遞工作;

執行環境

三端的js執行環境以及用於渲染非原生元件的環境是各不相同的:

  • 在 iOS 上,小程式的 javascript 程式碼是執行在 JavaScriptCore 中,是由 WKWebView 來渲染的;
  • 在 Android 上,小程式的 javascript 程式碼是通過 X5 JSCore來解析,是由 X5 基於 Mobile Chrome 53 核心來渲染的;
  • 在 開發工具上, 小程式的 javascript 程式碼是執行在 nwjs 中,是由 Chrome Webview 來渲染的;

這是官方關於檢視層和邏輯層執行環境的介紹。

  檢視層(不包括Native元件)在webview元件中渲染;邏輯層的js程式碼則通過js容器來執行。js程式碼執行過程中可以通過JsBridge調起微信、系統的能力,也可以將資料通過setData()函式傳遞給檢視層做渲染。檢視層在渲染和互動過程中可以通過事件與客戶端進行通訊。

檢視層向邏輯層的通訊由事件來完成,而邏輯層資料向檢視層傳送渲染指令是通過PagesetData函式。下面我們詳細說明他們的細節原理;

事件

小程式頁面生命週期
小程式頁面生命週期

  這張生命週期圖非常詳盡的描述了一個頁面從建立入棧、資料互動、銷燬出棧的整個過程。在頁面渲染和使用過程中會出現大量的事件,而這些事件會被JsBridge捕獲到,並傳遞給邏輯層處理,主要包括:生命週期事件、UI事件。

生命週期事件

檢視程式在完成階段性工作後,需要向邏輯層同步其當前狀態以便邏輯層做出應對策略。主要包括:onLoadonReadyonShowonHideonUnloadonPullDownRefreshonReachBottomonShareAppMessage等。

UI事件

檢視層向邏輯層的通訊方式。

這類事件繫結在元件上,觸發則可以將使用者的行為反饋到邏輯層對應的註冊函式,如bindtapbindinputbindconfirmbindfocusbindsubmitbindchangebindlinechange

Page.prototype.setData()

邏輯層向檢視層傳送渲染指令的方式。

setData 函式用於將資料從邏輯層傳送到檢視層,同時改變對應的 this.data 的值。
注意:data 將會以 JSON 的形式由邏輯層傳至渲染層,所以其資料必須是可以轉成 JSON 的格式:字串,數字,布林值,物件,陣列。

從效能角度考慮,UI渲染是比較耗時的,一方面儘量減少頁面渲染操作,另一方面其會對data的內容做深層次diff,儘量控制data的大小和資料結構的深度(官方限制data資料量最大為1024K。

筆者在做小程式效能監控的時候,遇到的一個問題就是無法準確統計到頁面渲染完成的時間。原因是 setData函式只負責傳送資料和渲染指令,但並沒有對應的反饋通知。

通過仔細分析,微信其實是可以提供這樣的能力的,在檢視層完成渲染後通過某種方式再告知邏輯層渲染狀態,我想出了兩個解決方案:

  1. 提供一個頁面渲染的事件,在渲染完成後將相關結果通過事件丟擲;
  2. 擴充setData函式,提供一個回撥函式,將渲染結果返回。

在和騰訊的同事提出該建議後,他們給出否定答案。原因是:回撥函式會增加一次渲染層到邏輯層的通訊開銷,而這個開銷相對而已比較重,目前他們官方是做了一些資料取樣,下圖是他們發給我們的渲染結果。

平均渲染耗時
平均渲染耗時

總結

本文通過對小程式基礎庫的介紹、擴充 JsBridge到融會貫通,介紹基礎庫、檢視層、邏輯層的執行機制,就是希望大家能夠建立對小程式架構理解,瞭解各模組在框架中所處位置和功用。

以上均為個人理解所得,由於沒有一些系統學習客戶端開發webview的經驗,所以關於 JsBridge 的一些講解比較淺顯,如有不當言論,望指出,謝謝。

-作者介紹-
J文,美團點評點餐終端團隊C端組成員,負責大眾點評雲餐廳微信小程式開發。

相關文章