轉轉Hybrid體系建設

前言

目前轉轉 App 是一個典型的 Hybrid App,採用的是業內主流的作法: 客戶端內有大量業務頁面使用 WebView 加載 H5 頁面承載。html

其優勢是顯而易見的,即:前端

  1. Web 頁面上線頻度知足快速迭代的業務需求,不受客戶端審覈和發版的時間限制
  2. 能夠將各個業務線的開發工做分攤到各個業務的前端團隊上,使得個業務線能夠並行開發。

其存在的問題也是很明顯的,好比加載性能問題,白屏問題,界面展現的侷限性、操做的侷限性,沒法使用系統功能等。node

轉轉 Hybrid App 架構

轉轉 Hybrid 架構設計以下圖 image imagewebpack

轉轉整個 Hybrid 容器架構設計分爲四層web

  1. 原生 Web 頁面 這塊就是你們常見的 Web 開發環境,能夠經過 Vue、React 等實現。
  2. Web 加強 包括像離線包和 Web 頁面容器等。
  3. 中間件層 中間件層使 Web 頁面容器和轉轉底層框架有機結合起來,同時還提供各類生命週期機制、事件機制、擴展插件等內容。中間件層經過 JSBridge 將客戶端以及中間件層提供的各類能力和 Web 前端代碼進行聯通。
  4. 轉轉基礎架構 主要包含 native 相關的能力架構

通訊模塊 - JSBridge

JSBridge 是 WebView 容器的基石,橋接了 JS 環境與 Native,實現了 Native 代碼和瀏覽器環境的雙向通訊。ajax

Native 代碼能夠經過調用瀏覽器提供的接口運行 JS,從而實現調用 JS 函數、傳遞參數到 JS 環境等。算法

而瀏覽器到 JS 環境的通訊是經過 Native 攔截瀏覽器的請求來實現。npm

經過 JSBridge 咱們就解決了 WebView 界面展現的侷限性、操做的侷限性和沒法使用系統功能等問題。後端

JSBridge 原理以下圖 image瀏覽器

預加載模塊 - 離線包系統

爲了作到良好的用戶體驗,咱們在容器中引入了離線包機制。經過離線包機制,咱們將原有從線上加載的 Web 頁面,提早下發到本地,經過讀取 IO 或者內存來進行頁面的渲染,達到接近原生的用戶體驗。

經過發佈平臺,咱們能夠將不一樣的 Web 頁面離線包,以單獨應用的形式,進行不一樣維度的下發,使原來 Native 發佈模式,改成各業務線自行定製發佈計劃,自行制定發佈標準,自行發佈的並行發佈形式,來知足業務的快速迭代。

Web 應用資源離線系統方案圖 image

下面咱們從前端構建、測試、發佈和 APP 端策略 兩個方向分別來分別闡述:

前端構建、測試和發佈

咱們採用騰訊 Alloy 團隊出品的 Webpack 離線包插件:Ak-webpack-plugin,其能夠根據配置,將 Webpack 的構建出的靜態資源,壓縮成映射了靜態資源在 CDN 路徑 URL 的 ZIP 壓縮包。

同時在配置的過程當中,也能夠選擇排除掉部份文件(好比圖片,並非全部構建出的圖片都是用獲得的)。其生成的壓縮結構以下:

image

在此過程當中,咱們不須要關注資源之間加載的依賴關係,更不須要關注具體的業務邏輯。只須要關注 Webpack 構建後生成的資源文件夾的結構。

把生成和上傳離線資源包的過程封裝成在npm run build中,經過腳手架生成項目可讓業務方無感接入。

生成的離線資源如何上傳呢? 咱們利用持續集成和發佈工具 Beetle(轉轉自研的 CI 系統,能夠理解爲 Jenkins)來自動發佈。

在本團隊的發佈與上線流程中,Bettle 代替 Fe 工程師構建與部署前端項目。使前端項目也像傳統的 App 與後端項目同樣作到了開發與構建部署分離,提升了團隊的效率。

而咱們生成和部署離線包的操做,也交由 Bettle 替咱們完成。當部署到測試環境時,Bettle 會把離線包發佈到測試版的離線包環境中,當正式線上時,還會發布到正式環境。這樣整個測試流程也能夠測試離線包。避免離線包形成的一些問題。

APP 端策略

在客戶端每次啓動或從新打開一個 Webview 的時候,都會經過接口讀取一份最新的各業務線的離線包與版本號的配置表。App 根據本地的配置文件和線上的作對比,下載須要更新的離線包資源。

資源包加載的優化

增量的資源更新(bsdiff/bspatch)

客戶端內置(或者在 WIFI 環境下載)了各業務全量包的基礎上,爲了減小每次下載更新的資源包的體積,咱們採用了增量更新策略。 該策略具體爲:每次發佈版本的時候,若是此業務線以前已有離線包,則經過離線系統生成差分包放在 CDN

增量更新的策略使用的是基於 node 的 bsdiff/bspatch 二進制差量算法工具 npm 包 bsdp。客戶端下載差分包後使用 Bspatch 合成更新包。

單獨控制各個業務線 Web 應用是否使用離線機制

爲了更好的監控離線包服務端和客戶端的運行狀況,而且下降使用離線資源帶來的不可預料的風險,將隱患作到可控。 咱們在每個業務上都加入了使用離線資源的開關和灰度放量的控制。

數據一致性校驗與數據安全性

爲了防止客戶端下載離線資源時數據在傳輸過程當中出現竄擾,致使下載的離線包沒法解壓,咱們在服務端經過接口中將資源包的 md5 值告知客戶端,客戶端下載後經過計算獲得的資源包的 md5 值,與之比較,能夠保證數據的一致性。

同時爲了保證傳輸過程當中,資源文件不被篡改,咱們將上述的 md5 值經過 RSA 加密算法進行加密。在服務端和客戶端分別使用一對非對稱的密鑰進行加解密。

離線包批量下載

在啓動 App 時,App 會集中批量的下載各個業務線的離線包資源,咱們在存放離線包資源的 CDN 中使用了 HTTP/2 協議,這樣客戶端與 CDN 只須要創建一次鏈接,就能夠並行下載全部的資源。

在須要下載離線包個數較多的狀況下,能夠比傳統的 HTTP1 有更快的傳輸速度。 同時,客戶端只須要運行一次下載器。減小屢次運行下載時對手機 CPU 的消耗。

基礎包包自動更新

當增量包的體積達到基本包的 60% 以上。咱們就認爲須要更換基礎包。

離線包回退機制

在實際狀況中,爲了不用戶下載離線資源或者解壓資源失敗等問題,致使沒法加載相應的離線資源,咱們設計了回退機制,在

  • 本地內置的 Base 包(ZIP 文件)解壓失敗的時候
  • 離線系統接口超時
  • 下載離線資源失敗
  • 增量的離線資源合併失敗等狀況下

遇到上述狀況時,咱們會轉而請求線上文件。

WKWebView 離線包實現

iOS 系統存在兩種 Webview 類型分別是 WKWebViewUIWebViewUIWebViewiOS 2.0 就有,而 WKWebViewiOS 8.0 纔有,毫無疑問 WKWebView 將逐步取代笨重的UIWebView

UIWebView 有不少問題,好比佔用過多內存等。 WKWebView 提高是在多方面的, 好比網頁加載速度有很大的提高,內存提高也很是明顯,支持更多的 HTML5 的特性等。

轉轉在很早的時候就切換到 WKWebView。可是WKWebView 不能像安卓同樣, 直接攔截請求。WKWebView 中實現離線包一共有三種方案,分別是

  • 私有 API 方案
  • 自定義協議方案
  • LocalWebServer 方案

轉轉在實踐中都作了嘗試,其中遇到了不少問題,這裏就不單獨展開了,你們能夠關注咱們,期待咱們的下一篇文章《WKWebView 離線包實踐》。

離線資源管理平臺

對於接入了離線系統的各個業務線的前端工程生成的不一樣時間版本的離線包,咱們須要有一個直觀明晰的方案來對其進行管理。

因而,咱們開發了離線資源管理平臺,對接離線後臺系統,系統界面以下圖 image

其主要的功能包含有:

  • 查看與管理各個業務線信息及其離線功能的灰度放量的比例。 對於新接入離線系統的前端工程,灰度放量可使得部分用戶先使用其離線的特性,並防止不可預料的問題發生在全體用戶上。

  • 經過業務線,版本號,發佈時間等條件,查詢各個版本的離線資源包的列表及其詳細信息。 如 離線包的類型,體積,上線時間等屬性。

  • 並在此基礎上容許將某版本的離線包下線,以實現離線資源版本的回滾功能。

  • 針對全局的離線功能,提供了離線功能的開關。

公共資源預加載

在離線包系統中,由於咱們是按業務線劃分,因此並無公共資源包。所以,咱們設計了一個利用瀏覽器緩存策略來緩存公共靜態資源的策略。

App 端爲提升 WebView 打開的效率,會使用 WebView 複用池策略。其策略的第一步就是在 App 啓動時會初始化一個備用的 WebView。

咱們正是利用了初始化的 WebView,來加載一些公共的資源,這樣可讓以後的頁面再加載該資源時,可使用 HTTP 緩存。

咱們開發了一個管理平臺,用來實時的管理 App 須要加載的公共資源文件。 image

頁面接口預請求

咱們經過離線包解決了資源加載的問題,可是首頁的接口請求也是一個須要優化的地方。

現有 Web 頁面加載流程能夠簡單歸納以下:先是加載 JS,在生命週期中請求數據,等待數據返回,渲染頁面。

那咱們是否能夠經過客戶端提早幫忙請求接口,而後直接從客戶端把數據取回來?答案是確定。

PS:接口預請求的方案,適合首頁請求了多個接口的項目,若是隻有一兩個接口,效果沒有明顯提高。

如何告訴客戶端咱們須要請求這些接口

咱們經過離線包的配置文件上新建一個ajax字段:

ajax: {
  "mode": "hash",
  "split": "#",
  "routes": [
    {
      "router": "/content/index",
      "requestOffline": true,
      "route":[
        {
          url: '/zzgift/creditandexchangecount',
          key: 'creditandexchangecount',
          des: '獲取星星信息',
          method: 'post',
          isNeedLogin: false,
          params: {}
        }
      ]
    }
  ]
}
複製代碼

首先,用戶點擊打開 Webview,App 請求 Ajax 列表的接口而且把本地的上次請求的數據刪除,同時加載 WebView。

JS 在請求接口時,先經過 JSBridge 取數據,Key 支持多個值一塊兒傳。

若是數據在 JSBridge 請求以前返回,把數據寫入本地對應 Key 的 Value,JSBridge 讀取後返回數據。

如何沒有返回,讀取本地 Key 爲空,直接返回空。

接口返回的數據 App 端不用作任何判斷和處理。若是沒有取到頁面在次經過 JS 發起請求,以後的超時從新請求等策略保持一致。

圖片骨架屏

Hybrid 界面體驗問題有一個很大的問題就是頁面白屏 image

轉轉經過圖片骨架屏來解決頁面白屏的問題,在 WebView 初始化時,客戶端把一張設計師出的的圖片,覆蓋在 WebView 上面。當頁面 WebView 加載完成,或者前端通知客戶端加載完成。客戶端經過漸隱動畫來隱藏圖片,達到完美的過渡效果。

讀取配置文件

客戶端在啓動時讀取圖片骨架屏的配置文件:

// 傳入設備分辨率ratioWidth:400, ratioHeight:500
{
  "code":0, // code 是0 表明請求成功 -1 表明圖片骨架屏功能關閉
  "data":{
    "m.zhuanzhuan.com/enjoy-given/eg/index.html": {
      "rege": '#/content/index'
      "routes":{
        "#/content/index": {
          "downloadUrl": 'https://m.zhuanzhuan.com/pic.png?400*500'
          "imgName": 'pic.png',
          "id": '10001',
        }
      }
    },
  "msg":""
  }
}
複製代碼

客戶端在 App 啓動的時候,讀取接口。

若是是首次使用,遍歷配置文件,創建路徑,下載圖片。

若是是二次使用,則對比兩次的配置文件,若是圖片名稱不一樣,刪除 id 文件夾下面的圖片,下載新的,若是相等,保持不變。

客戶端在內存中創建文件

zzSkeleton/10001/pic.png
複製代碼

解析 url 並展現

當客戶端打開 webview 時,讀取 url

例如:https://m.zhuanzhuan.com/enjoy-given/eg/index.html?__isonshowpro=1&metric=rhtjEzu4TBGu6npSjDyXcQ282171v&fromGiftPage=cateList&fromCateId=0#/content/index?ada=asdad

取出m.zhuanzhuan.com/enjoy-given/eg/index.html(location.host + location.pathname 在接口返回的配置文件中取出

{
  "rege": '#/content/index'
  "routes":{
    "#/content/index": {
      "downloadUrl": 'https://m.zhuanzhuan.com/pic.png?400*500'
      "imgName": 'pic.png',
      "id": '10001',
    }
  }
}
複製代碼

根據 rege 解析出#/content/index路由,而後根據idimgName來從本地取出文件

而後根據 zzSkeleton + 10001 + pic.png 讀取本地的圖片,並展現在 WebView 上

如何解決圖片拉伸的問題

後臺配置圖片的時候,能夠根據不一樣的分辨率來配置不一樣的圖片,相似 App 配置啓動圖的邏輯。在客戶端請求配置文件時,會傳入設備分辨率,接口會根據分辨率返回最接近的圖片。

App 統一跳轉平臺

對於 App 中的每個頁面、或者是每個行爲,咱們都能使用一個 URI 來定義,這個 URI 在轉轉內部叫作統跳。

轉轉的統跳所有由統跳平臺來管理,經過統跳平臺能夠更好的測試、分享和管理這些統跳地址。

image

系統比較簡單,經過動態表單來添加參數。一鍵生成二維碼來快速的測試。

image image

Hybrid 總結與展望

目前轉轉 Hybrid 總體的技術方案,包括離線包、圖片骨架屏等,已經無痛的接入業務中使用,很好的解決了頁面加載性能問題,白屏問題,界面展現的侷限性、操做的侷限性,沒法使用系統功能等問題。

固然技術在不斷的發展。轉轉 Hybrid 建設在追求技術進步的道路上。還有不少的地方須要提高。

  • 提供完整的 SPA 體驗 目前頁面跳轉基本是從新打開一個 WebView,這樣就損失了一些項目的性能。咱們計劃經過前端接管原生的路由的方式,讓端內作到真正的 SPA 體驗。

  • 接口請求和埋點經過客戶端發送 轉轉如今的請求和埋點都是經過前端本身發送的。可是存在埋點丟失等問題。咱們計劃打通客戶端和前端的請求發送。同時前端也能夠利用客戶端的安全鑑權等能力。

福利部分

預告下,接下來咱們會陸續發佈轉轉在微前端、Umi、組件庫等基礎架構和中臺技術相關的實踐與思考,歡迎你們關注,指望與你們多多交流。文章在 「大轉轉FE」 公衆號也會發送,而且公衆號有抽獎活動,本文獎品是轉轉記念T恤一件,歡迎你們關注 ✿✿ヽ(°▽°)ノ✿

相關文章
相關標籤/搜索