一 方案介紹
為了解決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, 達到了替換的效果。

基于這樣的原理,DexPatch具有以下特征:
- 支援範圍上:是基于類級别的替換,是以隻支援Java子產品的patch,不支援非Java子產品的patch,比如so子產品
- 相容性上:由于是代理了系統的ClassLoader,使用的黑科技較少,是以整體方案相容性較好
- 生效時效性上:隻能在下載下傳patch後重新開機後才能生效,不支援實時生效
- 成功率上:由于下載下傳是使用的獨立程序,減少了啟動階段主程序閃退對patch下載下傳的影響,提升了下載下傳的成功比例
二 使用介紹
以下介紹下在mPaas下使用DexPatch子產品的主要步驟以及問題排查思路,友善開發者日常開發。
1. 觸發patch拉取
啟動階段調用MPHotpatch.init(), 主要觸發Patch資訊的RPC請求,如果命中釋出Patch釋出規則,RPC會傳回Patch的jar包下載下傳位址,用戶端去觸發下載下傳,下載下傳後儲存在用戶端私有目錄/data/user/0/包名/dexpatch/patch/ 下。

2. 代碼操作示範
以元件化模式接入為例,介紹下Patch釋出的主要流程。
1. 代碼改動前

需要儲存改動前的建構産物,友善後續做Patch生成,位址在:build/intermediates/bundle/xxxx-raw.jar
2. 代碼改動後

重新編譯,儲存建構産物,産物位址: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。

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

5. 生成patch
① 通過mPaas自帶的ide工具,點選熱修複,進入修複頁面。

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

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

6. 生成patch産物
生成patch産物如下:

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

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

7. 上傳釋出
① 選擇上一步的産物jar包進行上傳

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

8. 驗證下載下傳
白名單釋出後,啟動用戶端,搜尋關鍵字:DynamicRelease,可以看到在tool程序有觸發下載下傳的日志打出。這裡需要說明的是,這裡觸發patch的下載下傳是在tool程序,不在主程序的主要原因是怕由于主程序由于啟動導緻重複閃退,導緻patch不能下載下傳成功,單獨在tool程序實作下載下傳,盡量提高patch的下載下傳成功比例。

然後去下載下傳目錄檢視,是否下載下傳儲存成功,下載下傳目錄在:/data/user/0/包名/dexpatch/patch/[email protected]

9. 殺程序啟動
确認下載下傳儲存成功後,殺掉App,重新開機檢視是否生效,重新開機可以搜尋關鍵字:DexPatchManager,檢視patch生效的日志,日志會列印目前是否存在patch以及patch是否加載的日志。

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

三 常見問題
1. aar模式內建後patch沒生效
aar模式內建的時候,需要繼承架構的QuinoxlessApplication,指定Application為架構的實作類才能實作dexpatch的加載。QuinoxlessApplication内主要封裝了dexpatch子產品的初始化和加載。
2. 使用加強後不生效
需要使用加強前的apk生成patch,不能用加強後的包生成patch。 然後還需要驗證在不同加強廠商下的相容表現。
3. 使用熱修複後,和 RPC 有關的調用發生 apache http 相關的 crash。
現象:使用patch後, rpcService擷取為空。
請使用 Android 官網上的方式引入 apache http client,禁止使用導入 jar 包或者 gradle implementation/compile 的方式導入 http client,否則會引起 classloader 加載類混亂。
建議方式:
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
如果直接引入會導緻apache 相關的類進入到 apk 裡面去,熱修複的時候 classloader 加載的時候因為有和系統重複的類,是以出問題了。