編輯:關於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中進行操作。
在重構項目之前,我先記錄下了這些思路和流程,然後根據這個流程來實現熱補丁框架,效率真的快了很多。
release簽名打包作為發布版本,每次release打包都會重新生成hash.txt和mapping.txt(開啟混淆的情況下才有mapping)
每次debug運行的時候(直接運行項目或者buildapk),都會通過校驗hash.txt和mapping.txt生成已簽名補丁包。
直接將補丁包放到sdcard中即可完成熱修復
加載補丁的時候需要進行簽名校驗,防止惡意代碼注入
拋棄transform,使用純hook的方式實現。
主要hook的task有這幾個:
不混淆的情況:
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
這樣就可以控制混淆和不混淆兩種情況了。
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
最近忙著項目,很久沒有總結提交博客和提交github了。接下來我打算整理下項目中用到的比較有用的發表到博客上。也打算總結一些關於設計模式和源碼分析的博客。今天的話就先來講
1. 前言前幾篇學習了jni開發的基本流程、動態注冊native函數以及相關編譯文件的編寫,咱們也算是知道了jni開發,但是還不夠,今天咱們來學習下,java和jni的數
一 概述DiffUtil是support-v7:24.2.0中的新工具類,它用來比較兩個數據集,尋找出舊數據集-》新數據集的最小變化量。 說到數據集,相信大家知道它是和誰
1、概述 群裡的一個哥們有個需求是這樣的:問題;主要功能就是:1、循環的一個滑動;2、每次滑動結束,保持每個Item的完整。然後我當時給他寫了個Demo,所