Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android熱補丁動態修復技術(完結篇):自動生成打包帶簽名的補丁,重構項目

Android熱補丁動態修復技術(完結篇):自動生成打包帶簽名的補丁,重構項目

編輯:關於Android編程

一、關於前面四篇博文

Android熱補丁動態修復技術(一):從Dex分包原理到熱補丁
Android熱補丁動態修復技術(二):實戰!CLASS_ISPREVERIFIED問題!
Android熱補丁動態修復技術(三)—— 使用Javassist注入字節碼,完成熱補丁框架雛形(可使用)
Android熱補丁動態修復技術(四):自動化生成補丁——解決混淆問題

前兩篇博文主要是介紹熱補丁修復技術的一些原理和實現方案。
而後面兩篇博文主要是介紹如何使用代碼實現整個熱補丁框架,但是框架寫的真的很糟糕,很多多余的操作。而這很大一部分原因是使用了transform,在混淆的時候transform並不好用。

以下是我在github上重構好的熱補丁框架,求star (??`ω′?)
https://github.com/AItsuki/HotFix
1. 支持混淆
2. 自動生成帶簽名的補丁包
3. 加載補丁包時會進行簽名校驗

這裡寫圖片描述vcq9x+vSxrK9tb08YSBocmVmPQ=="https://github.com/AItsuki/HotFix">github,再說一次:求star (??`ω′?)

二、框架的實現思路

在第四篇博文中,我們發現在混淆的情況下,transform使用起來真的很反人類,因為transform只能在混淆之前對class進行操作,無法將transform添加到混淆之後。
所以以下思路,我放棄了使用transform,而是直接在dextransform這個任務的dofirst中進行操作。

在重構項目之前,我先記錄下了這些思路和流程,然後根據這個流程來實現熱補丁框架,效率真的快了很多。

2.1 定義熱補丁框架的使用方式

release簽名打包作為發布版本,每次release打包都會重新生成hash.txt和mapping.txt(開啟混淆的情況下才有mapping)

每次debug運行的時候(直接運行項目或者buildapk),都會通過校驗hash.txt和mapping.txt生成已簽名補丁包。
直接將補丁包放到sdcard中即可完成熱修復

加載補丁的時候需要進行簽名校驗,防止惡意代碼注入

2.2 代碼流程

拋棄transform,使用純hook的方式實現。
主要hook的task有這幾個:

transformClassesWithDexForRelease transformClassesWithDexForDebug transformClassesAndResourcesWithProguardForRelease transformClassesAndResourcesWithProguardForDebug

不混淆的情況:
transformClassesWithDexForRelease
dofirst —— 遍歷輸入文件,生成md5保存好(hash.txt),然後注入代碼

transformClassesWithDexForDebug
dofirst —— 遍歷輸入文件,生成md5,和hash對比,將改變過的類復制到補丁文件夾,然後注入代碼

混淆的情況:
transformClassesAndResourcesWithProguardForRelease
dolast —— 遍歷輸出文件,生成md5保存好(hash.txt),然後注入代碼,將mapping保存好

transformClassesAndResourcesWithProguardForDebug(需要使用applymapping)
dolast —— 遍歷輸出文件,生成md5,和hash對比,將改變過的類復制到補丁文件夾,然後注入代碼

開啟混淆後task的執行順序是proguard –> dex
因為dex永遠是在最後面執行,所以注入代碼和生成補丁這些操作都只需要hook dex就可以了
但是開啟混淆的時候,dex dofirst需要做的事情還是有點不同的,我們可以通過一個變量來控制 def minify = false

hook proguard,在proguardTransform執行的時候復制minify = true
這樣就可以控制混淆和不混淆兩種情況了。

2.3 實際遇到的問題

1、 不clean項目,第二次運行release打包不會注入代碼
這是因為gradle的增量式構建,up-to-date,task不執行
解決方式:
dexRelease.outputs.upToDateWhen {false} 讓task一直都執行
http://stackoverflow.com/questions/7289874/resetting-the-up-to-date-property-of-gradle-tasks

2、如果有使用到自定義控件,在xml的preView窗口會報空指針異常
這是因為自定義控件已經被注入了代碼,而預覽窗口的時候並沒有加載hack.jar,找不到AntilazyLoad.class,所以報空指針。
解決方式:
使用pluginExtention,在build.gradle中配置變量,控制在debug模式下是否注入代碼。
如圖,這裡添加了兩個Extention
這裡寫圖片描述

3、如何applymapping
applymapping的作用是復用上一次的混淆規則。
所以我們需要將release生成的mapping.txt應用到debug的混淆上,否則可能無法正確的生成補丁。
解決方式:
第一種:
手動配置debug的混淆文件

第二種:
1. 在gradle 1.5以下時,可以直接task.applyMapping(File file)的方式在代碼中動態添加
2. 在gradle1.5以上時,因為proguard的transform是一個特殊的task,所以並不能直接applyMapping,需要做一些強轉。
(proguardDebug即transformClassesAndResourcesWithProguardForDebug)
這裡寫圖片描述

4、開啟混淆後的Release簽名打包,如果debug模式不開啟混淆的話,會將所有類都打包成補丁。
這是因為,如果debug模式不開啟混淆,那麼就會拿不混淆的代碼和Release已經混淆的代碼進行校驗,md5肯定不一致,所以會將所有類打包成補丁包。
解決方式:
暫時沒有好辦法,老老實實開啟混淆吧。Debug是否開啟混淆要和Release保持一致
這裡寫圖片描述

5、如何簽名補丁
補丁的簽名主要用到的是jdk的工具,jarsigner.exe。使用代碼調用命令行即可

6、如何進行簽名校驗
首先,debug安裝的app不需要進行校驗,這是檢測當前app是否是debug簽名的方法。
然後,這是校驗補丁包和app簽名是否一致

7、android 6.0無法從sdcard加載補丁包
運行時權限機制的問題,可以將補丁包放到app私有空間加載。

8、 androidStudio 2.0以上用到了instantRun,這是否會對debug自動生成補丁包產生影響。
這個問題我還沒有測試,如果真的有影響的話也有很簡單的解決方式,直接使用簽名打包debug也可以生成補丁包。
這裡寫圖片描述

三、參考項目

https://github.com/jasonross/Nuwa
https://github.com/bunnyblue/DroidFix
https://github.com/Livyli/AndHotFix
主要是第三個,簽名校驗的思路來源於它

四、寫在後面

終於算是完成了熱補丁框架了,其中過程真的累人啊!
整個框架的實現思路比較清晰簡單,代碼量也不超過1000行,很適合正在學習這個技術的朋友們。

求star,求star,第一個上傳到github的項目求star (??`ω′?)
https://github.com/AItsuki/HotFix

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved