一 方案介紹
為了解決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 加載的時候因為有和系統重複的類,所以出問題了。