汽車之家主機廠離線化 H5 Hybrid 實踐

1.背景

H5 頁面做秒開優化是業務的常規操作,一般正常通過網絡請求的 H5 頁面,我們都是圍繞資源加載速度優化展開。優化手段主要分兩個方向,一個是提升網絡速度,一個是減少資源大小。

提升網絡速度,一般的手段有 DNS 預解析、多域名、升級 HTTP2、使用 CDN、SSR。而即使有靜態資源的網絡緩存,HTML 也只能用協商緩存,需要消耗一次網絡請求。這也註定了無法避免因網絡問題導致的頁面白屏時間較長的問題,在我們真實的數據中也能得到印證,無論怎麼優化,頁面的 1.5 秒開穩定在 90% 以上非常困難。

因此,如果想實現 95% 以上甚至 99% 以上秒開,離線化 H5 是必然的選擇。同時根據歷史經驗,隨着 iOS 和 Android 手機的性能不斷提升,Webview 的渲染性能也不斷提升,目前大部分手機的 H5 離線化渲染都可以實現無白屏體驗,無限接近原生的交互體驗。

 

2.收益

在實踐過程中,我們分兩個場景構建離線化 H5 基座,一個是由 H5 開發的新 APP,一個是汽車之家 APP。

主機廠內部有一個應用,第一版是 Native 和 H5 的混合開發,會通過網絡請求資源,雖然有網絡緩存,但是第一次打開也很慢,非常影響用戶體驗,內部性能監控平臺顯示首屏平均耗時 1s。後面全面改造成內置離線 H5 應用,Native 只提供橋功能,首屏平均耗時減少到 237ms,加載速度提升 4 倍,大部分情況下實現無白屏體驗。業內曾經做過人眼識別白屏的最小時間測試,當降到 200ms 左右時,人眼幾乎無法識別白屏。

新 APP 我們主要使用 H5 開發,而不是用 Flutter 或者 RN 等技術,最主要的原因是人才儲備不足,在業務場景並沒有特別複雜的原生體驗情況下,我們發現業務迭代,對客戶端的依賴大大減少,溝通成本降低,迭代效率有明顯提高,團隊不需要面對複雜的 Flutter 和 RN 引擎,也不需要熟悉客戶端的開發模式。

汽車之家 APP 中,由於歷史原因,不能預置離線包 H5,所以只能有選擇性地進行動態預加載,而這會導致在開屏等特殊場景下,訪問速度仍然不高。整體上首屏時間從 1240.4ms 縮短爲 505.4ms,加載速度提升一倍。

 

3.技術架構

圖片

 離線化 H5 Hybrid 架構上,主要分成四大模塊:H5 離線包管理工具、APP 開發工具、Native 運行時和 Webview 運行時。

 

4.離線包管理工具

H5 離線包管理工具包含:離線包管理平臺、之家雲打包腳本。離線包管理平臺包含:APP 應用管理、H5 應用管理、發佈回滾、開關控制四大功能。通過和之家雲發佈流水線聯動,可以實現網絡版和離線版 H5 的版本同步,發佈操作也實現同步,由於之家雲功能限制,回滾目前還不支持聯動。

管理的物料包括:H5 離線包(H5 代碼、離線包配置文件)、APP 離線包配置文件。APP 配置文件,在沒有預置離線包的情況下,下載資源是阻塞性的。爲了提升下載速度和可用性,APP 配置文件也被維護成了一個 CDN 上的 JSON 文件。

4.1

離線包發佈流程

在之家雲發佈平臺,使用離線包管理 CLI 工具,執行上傳離線包命令,並配置一個離線包發佈的 Webhook,即可實現自動化離線包發佈。離線管理平臺會同步之家雲平臺的離線包版本號。

圖片

4.2

離線包設計

和普通的 H5 打包文件相比,離線包新增了一個專屬的離線包配置文件 config.json,同時會把資源打包成 gzip 壓縮包,從而提升整體資源的下載速度。

資源目錄

h5id
├── js/
├── css/
├── img/
├── pages
│   ├── index.html
│   └── list.html
└── config.json(配置文件)

配置文件

interface HybridConfig {
  // 離線 H5 APP ID
  h5id: string;
  // 匹配頁面和靜態資源的規則
  mapping: {
    [env: string]: {
      pages: Resource[];
      resources: Resource[];
    }
  };
  package: {
    // 離線包資源目錄路徑,根目錄相對路徑
    file: string;
    // 包含的文件,和 excludes 互斥,只能同時有一個
    includes: {
      ext: string[];
      file: string[];
    };
    // 不包含的文件
    excludes: {
      ext: string[];
      file: string[];
    };
    // Native APP 版本適配
    appRules: {
      // 離線包管理平臺的應用 ID
      [appid: string]: {
        // [最小版本,最大版本]
        ios: [string, string];
        android: [string, string];
      }
    };
  }
}

interface Resource {
  // 攔截到的請求 url 的規則,不提供 http 或者 https,支持單個文件和文件目錄。
  // 例如:example.com/page,example.com/static/img.png
  remoteUrl: string;
  // 和 downloadUrl 必須有一個存在,相對離線包所在目錄的文件路徑。
  // 「path」值會替換掉請求 url 中的「remoteUrl」字符串。
  path?: string;
  // 和 path 必須有一個存在,指定下載資源的 url,
  // 下載後存放在離線包的 vendor 目錄下。
  // 並把存儲 path 同步到配置文件的 path 字段。
  downloadUrl?: string;
  // 可選的 mime type,如果不提供,通過文件名後綴自動補償
  contentType?: string;
}

 

4.3 

打包命令行工具

  1.  打包發佈腳本發佈到之傢俬有源,以腳手架命令形式調用,提供打包、上傳命令;

  2. 業務方結合自身編譯上線流程進行調用,上傳完成則自動進行發佈;

  3.  前端靜態資源按照頁面/工程緯度打包成zip;

  4. zip包含js/css/img/pages/config.json配置文件;

// 腳本安裝
npm i @auto/dt-fe-cli

// 編譯上傳
// 指定腳本的配置文件,打包並上傳至服務器,默認配置文件爲 config.json,可以使用 --config 指定配置文件
dt-fe-cli offline --config hybrid-config.json

 

4.4 

管理平臺

爲了更好管理離線包,我們提供了一個簡潔的管理後臺,用來管理 H5 應用和 APP 應用的關係,記錄之家雲編譯好的離線包,同時提供 APP 配置給客戶端查詢。爲了提高 APP 配置下載速度和可靠性,我們用 CDN 上的 JSON 文件來存儲 APP 配置。

►4.4.1 APP 配置

interface APPConfig {

  appid: string;
  version: string;
  updateTime: string;
  isIosEnable: boolean;
  isAndroidEnable: boolean;
  H5Apps: H5App[];
}

interface H5App {
  // H5 應用的 APP ID
  h5Id: string;
  versions: H5Config[];
  lastVerison: {};
  latestUrl: string;
}

interface H5Config {
  version: string;
  // true,開啓離線化
  isEnable: boolean;
  // true,開啓 iOS APP 離線化
  isIosEnable: boolean;
  // true,開啓 Android APP 離線化
  isAndroidEnable: boolean;
  // true,需要預先加載
  isPreLoad: boolean;
  pages: Resource[];
  appRules: AppRules;
  downloadUrl: string;
}

interface Resource {
  // 攔截到的請求 url 的規則,支持單個文件和文件目錄。例如:/page,/static/img.png
  remoteUrl: string;
  // 和 downloadUrl 必須有一個存在,相對離線包所在目錄的文件路徑。
  // path 會替換掉請求 URL 中的「remoteUrl」字符串
  path?: string;
  // 和 path 必須有一個存在,指定下載下載資源的 url,下載後存放在離線包的 vendor 目錄下。
  // 並把存儲 path 同步到配置文件的 path 字段。
  // 下載失敗,則該匹配規則失效自動訪問網絡資源
  downloadUrl?: string;
  // 可選的 mime type,如果不提供,通過文件名後綴自動補償
  contentType?: string;
}

interface AppRules {
  // ios APP 的開始和結束版本,最大版本可設置 infinite
  ios: [string,string];
  android: [string,string];
}

 

4.4.2 管理平臺截圖

圖片
圖片
圖片

5.客戶端設計

作爲整體 Hybrid 離線包應用架構中的重要一環,端內 Hybrid 離線包 SDK 包括 Webview 管理、離線包管理、Bridge 三個模塊。

圖片

5.1 

Webview管理

  1. 定製 Hybrid 瀏覽器,設置可通過特定 Scheme 協議打開;

  2. 如果沒有離線資源,可以降級 HTTP 請求,也可以選擇阻塞下載;

  3. 通過 H5 應用映射表匹配當前頁面 Url 和緩存資源,存在緩存資源時,Hybrid 瀏覽器攔截 H5 所有資源請求,執行本地緩存邏輯:命中緩存時直接返回本地資源;未命中緩存則交還給WebView進行默認處理;

  4. 關閉 Hybrid 瀏覽器時觸發離線包管理邏輯,進行資源更新。

5.2 

離線包管理

  1.  APP 預置:APP 打包時可以使用命令行工具批量下載需要預置的離線包,並集成到 APP 中;

  2. 預加載:有時候出於 APP 體積的考慮,我們不能預置所有離線包,爲了提高離線包的加載體驗,可以開啓預加載,在 APP 啓動後的空閒時間主動進行離線包下載;

  3. 更新:根據唯一性原則,同一個 H5 應用同時只保留一份離線資源;

  4. 磁盤空間管理:及時刪除下載失敗或已解壓完成的 ZIP 包;清理舊版本離線資源;結合 LRU 算法進行離線包緩存上限管理。

  5. 環境隔離

5.3 

環境區分及降級處理

  1. H5 應用區分測試、生產環境,不同環境匹配不同離線資源;

  2. 通過預支的字段開關可以控制是否啓用離線包邏輯,開關關閉時直接使用線上資源。

5.4 

Hybrid 離線包方案的下一步規劃

Hybrid 方案在預加載模式下取得了較好的效果,有效的提升了 H5 頁面的秒開率,後續將在以下幾個方面繼續提升 Hybrid 方案的能力,更好的爲主機廠相關業務助力。

  • 增加並完善預置離線包能力:在 APP 大小可控的前提下,在 APP 內預置關鍵頁面的離線包,彌補預加載邏輯在第一次打開時命中率低的不足。APP接入預置離線包後,頁面第一次打開時預計資源命中率提高到100%。完成相關方案如下:

圖片
  • 增加 One Shot 能力(類小程序):支持在 Hybrid 瀏覽器首次訪問 H5 應用時,實時下載離線資源包並匹配離線資源。APP接入One Shot 能力後,頁面第二次打開時預計資源命中率提高到100%。相關方案如下:

圖片

6.踩過的坑

6.1 

Post 請求丟失 Body

 iOS 系統,瀏覽器攔截協議有 NSURLProtocol 和 WKURLSchemeHandler 兩種,並且都存在 Post 請求丟失 Body 的問題,針對 Post 請求都需專門處理。

開始時使用的是 NSURLProtocol 協議,優點是可挑選處理請求,不需要處理的可拋回瀏覽器,但是在特殊場景下出現問題:NSURLProtocol 是全局攔截,打開後所有瀏覽器都會進行攔截,所以在多個瀏覽器同時存在,並且非Hybrid瀏覽器還有發送 Post 請求時,Post 請求 Body 會丟失,導致請求失敗。NSURLProtocol 的全局攔截問題無法解決,於是又將目光移向 WKURLSchemeHandler,開始了完全自己實現Http請求。

6.2 

無侵入式攔截

 WKURLSchemeHandler 需要解決的問題有很多,包括Cookies,重定向,Post請求支持等。最開始沿用了NSURLProtocol Post 請求處理方法,業務方將Post請求通過橋的方式,扔給Native進行請求,但緊接着就遇到另一個問題:需要業務方配合改造。作爲一個通用平臺,接入成本過高是一個致命問題,直接影響業務方接入的意願。

實現無侵入式攔截,是我們必須要解決的問題,最終通過多次實驗,採用了JS注入攔截的方式,具體流程主要爲以下幾點:

  • 若命中離線,加載網頁時開啓Handler攔截,注入 Fetch /  XMLHttpRequest 攔截請求腳本;

  • 發送請求時,Post請求通過Bridge發送給Native,Get請求又傳遞給原生應用進行存儲處理WKURLSchemeHandler;

  • Handler攔截的請求若命中離線,走本地資源匹配,匹配到後模擬請求返回H5,未命中時Native發送請求;

  • Post請求,Native通過橋拿到url和Body信息,通過原生請求發送,結果透傳給H5。

圖片

 

7.總結

隨着移動設備整體性能的持續提升,離線化 H5 Hybrid技術架構在加載和交互體驗方面取得了顯著改善。在許多標準應用場景中,它能夠提供接近原生應用的用戶體驗。此外,它的跨平臺、低成本、充足的人才資源、豐富的生態系統和動態更新等優勢,使其在與其他跨平臺解決方案的比較中脫穎而出。

 

作者| 主機廠BU-技術部

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章