天天看點

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

方案介紹

為了解決 Native 子產品上線後的問題,mPaaS 提供了熱修複功能,實作不釋出用戶端 apk 場景下的熱修複。目前 Android 端熱修複主要包括 andfix 和 dexpatch,考慮到 andfix 的版本相容性,目前主要推薦使用 DexPatch。

DexPatch 修複原理比較簡單,就是在啟動後通過 RPC 拉取目前需要下發的 jar 包位址,然後通過獨立程序去下載下傳 jar 封包件,下載下傳完成後儲存。在二次啟動的時候 hook 系統的 classLoader,修改 DexPathList,在其數組的最前面加入一個有修改過的 class 的 dex 檔案,使其攔截住數組後面的 dex 檔案中同名的 class 的加載。

如下圖所示,classloader 就會優先加載 Patch.dex 中的 Ding.class,而忽略 Classes.dex 中的 Ding.class,達到了替換的效果。

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

基于這樣的原理,DexPatch 具有以下特征:

  1. 支援範圍上:是基于類級别的替換,是以隻支援 Java 子產品的 patch,不支援非 Java 子產品的 patch,比如 so 子產品;
  2. 相容性上:由于是代理了系統的 ClassLoader,使用的黑科技較少,是以整體方案相容性較好;
  3. 生效時效性上:隻能在下載下傳 patch 後重新開機後才能生效,不支援實時生效;
  4. 成功率上:由于下載下傳是使用的獨立程序,減少了啟動階段主程序閃退對 patch 下載下傳的影響,提升了下載下傳的成功比例。

操作說明

以下是關于在 mPaaS 下使用 DexPatch 子產品的主要步驟以及問題排查思路,友善開發者日常開發。

1. 觸發 patch 拉取

啟動階段調用 MPHotpatch.init(),主要觸發 Patch 資訊的 RPC 請求,如果命中釋出 Patch 釋出規則,RPC 會傳回 Patch 的 jar 包下載下傳位址,用戶端去觸發下載下傳,下載下傳後儲存在用戶端私有目錄​

​/data/user/0/​

​​包名​

​/dexpatch/patch/​

​下。

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

2. 代碼操作示範

以元件化模式接入為例,介紹下 Patch 釋出的主要流程。

(1)代碼改動前
技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

需要儲存改動前的建構産物,友善後續做 Patch 生成,位址在:​

​build/intermediates/bundle/xxxx-raw.jar​

(2)代碼改動後
技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

重新編譯,儲存建構産物,産物位址:​

​build/intermediates/bundle/xxxx-raw.jar​

(3)生成白名單配置

主要用于熱修複包時用于指定修複的類,配置檔案為 .txt 格式,該配置檔案應包含并按順序包含以下資訊:

需要 Patch 的類。以 L 開頭,後跟以混淆後真實類名。如果多個類,每行隻可寫一個。示例:​

​Lxxx.xxx.clazzX​

​​設定 Patch 類型為 dexpatch。示例:​

​PatchType: dexpatch​

設定是否是靜态 Bundle。預設為 false,如果是靜态連結的 Bundle,需要顯式設定為 true。示例:​

​HostDex: true​

​(*目前 mPaaS 用戶端的子產品一般都在靜态連結裡,一般寫 true)

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch
(4)檢視簽名

生成 patch 需要用到項目的打包秘鑰,需要提前準備好,可以在打包腳步下找到對應的配置

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch
(5)生成 patch

① 通過 mPaaS 自帶的 IDE 工具,點選熱修複,進入修複頁面。

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

② 按照頁面提示,填入之前準備的修複前和修複後的 jar 包位址,還有白名單配置檔案,勾選 dexPatch,進入到下一步

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

③ 下一步主要選擇打包的配置檔案,最近點選完成生成 patch 檔案

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch
(6)生成 patch 産物

生成 patch 産物如下:

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

檢視産物,可以使用 dex2jar 工具反解 diff.dex 檔案,用 jd-gui 檔案檢視反解産物是否符合預期

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

反解後可以看到修改的子產品:

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch
(7)上傳釋出

① 選擇上一步的産物 jar 包進行上傳

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

② 上傳後可以通過白名單進行釋出,驗證 patch 的穩定性

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch
(8)驗證下載下傳

白名單釋出後,啟動用戶端,搜尋關鍵字:DynamicRelease,可以看到在 tool 程序有觸發下載下傳的日志打出。

這裡需要說明的是,這裡觸發 patch 的下載下傳是在 tool 程序,不在主程序的主要原因是怕由于主程序由于啟動導緻重複閃退,導緻 patch 不能下載下傳成功,單獨在 tool 程序實作下載下傳,盡量提高 patch 的下載下傳成功比例。

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

然後去下載下傳目錄檢視,是否下載下傳儲存成功,下載下傳目錄在:​

​/data/user/0/​

​​包名​

​/dexpatch/patch/[email protected]

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch
(9)殺程序啟動

确認下載下傳儲存成功後,殺掉 App,重新開機檢視是否生效,重新開機可以搜尋關鍵字

DexPatchManager,檢視 patch 生效的日志,日志會列印目前是否存在 patch 以及 patch 是否加載的日志。

技術幹貨 | 深度解構 Android 應用面臨緊急發版時的救星方案:mPaaS 熱修複——DexPatch

同時我們也可以就實際業務場景進行驗證,檢視是否生效。

常見問題

1. aar 模式內建後 patch 沒生效

aar 模式內建的時候,需要繼承架構的 QuinoxlessApplication,指定 Application 為架構的實作類才能實作 dexpatch 的加載。QuinoxlessApplication 内主要封裝了 dexpatch 子產品的初始化和加載。

2. 使用加強後不生效

需要使用加強前的 apk 生成 patch,不能用加強後的包生成 patch。然後還需要驗證在不同加強廠商下的相容表現。

3. 使用熱修複後,和 RPC 有關的調用發生 apache http 相關的 crash。

請使用 Android 官網上的方式引入 apache http client,禁止使用導入 jar 包或者 gradle implementation/compile 的方式導入 http client。否則會引起 classloader 加載類混亂。

<uses-library android:name="org.apache.http.legacy" android:required="false"/>      

繼續閱讀