Andfix熱修復框架原理及原始碼解析-上篇

yangxi_001發表於2016-12-02

1.不知道如何使用的同學,建議看看我上一篇寫的介紹熱補丁和Andfix的使用,這樣你才有一個大概的框架。通過使用Andfix,其實我們心中會有一個大概的輪廓,它的工作原理,大概就是,所謂的補丁檔案,就是通過打包工具apkpatch比對新的apk和舊的apk之間的差異。然後讓我們的舊包執行的時候,就載入它,把以前的一些資訊替換掉。我們現在就抱著這個大方向去深入原始碼探個究竟!!首先看下Demo裡面Application的程式碼。

 

2.一開始例項化PatchManager,然後呼叫init()這個方法,我們跟進去看看。我註釋的很詳細,大致就是從SharedPreferences讀取以前存的版本和你傳過來的版本進行比對,如果兩者版本不一致就刪除本地patch,否則呼叫initPatchs()這個方法。

 

3.分析下initPatchs()它做了什麼,其實程式碼很簡單,就是把mPatchDir資料夾下的檔案作為引數傳給了addPatch(File)方法,然後呼叫addPatch()方法,addPatch方法的作用看下面的註釋,寫的很清楚。

 

4.我們可以看到addPatch()方法裡面會例項化Patch,我們跟進去看看例項化過程中,它又幹了什麼事。

 

它裡面呼叫了init()方法,可以看到裡面有JarFile, JarEntry, Manifest, Attributes,通過它們一層層的從Jar檔案中獲取相應的值,提到這裡大家可能會奇怪,明明是.patch檔案,怎麼又變成Jar檔案了?其實是通過阿里打補丁包工具生成補丁的時候寫入相應的值,補丁檔案其實就相到於jar包,只不過它們的副檔名不同而已。提到這裡我們就來單獨的探索下,補丁檔案是怎麼一步步生成的。因為阿里沒有對打補丁工具進行加密和混淆,我們可以使用jdgui開啟檢視。所需相應的工具程式碼demo等我都統一放在下面的下載連結裡面。有需要的自行取下。


5.好了,我們現在來分析下補丁檔案如何生成的,用jdgui開啟apkpatch-1.0.3。先從main方法開始。


可以看到:下圖1部分就是我們前面介紹如何使用命令列打補丁包的命令,檢查命令列是否有那些引數,如果沒有要求的引數,就給使用者相應的提示。第二部分,我們在打正式包的時候,會指定keystore,password,alias,entry相關引數。另外name就是最後生成的檔案,可以忽略。

 

Main函式最後一個方法是我們的大頭戲,上面的引數傳給ApkPatch進行初始化,然後呼叫doPatch()方法。

 

 

我們再跟進去,看看ApkPatch初始化的過程中,做了什麼。

 

呼叫了父類的方法,我們再看看父類Build.

 

乾的事情其實比較簡單,就是給變數進行賦值。可以看到out,我們的輸出檔案就是這麼來的,沒有的話,它會自己建立一個。

然後我們再回到apkPatch.doPatch()這個方法。看看這個方法裡面是什麼。

 

這個方法主要做的就是在我們的out輸出檔案中生成一個smali資料夾,還有diff.dex, diff.apatch檔案。可以找到你的輸出檔案確認下。

 

DiffInfo相當於一個儲存新包和舊包差異資訊的容器來,通過diff方法將二者的差異資訊給info.然後就是三個最重要的方法,buildCode(), build(),release()。我們接下來一個個的看下,他們究竟為何這麼重要。

 

看到baksmali和smali,反編譯過apk的同學一定不陌生,這就是dex的打包工具和解包工具,關於這個具體就不深入了,有興趣的同學可以深入瞭解下。這個方法的返回值將DiffInfo中新新增的classes和修改過的classes做了一個重新命名,然後儲存了起來,同時,將相關內容寫入smali檔案中。為什麼要進行重新命名,其實是為了防止和之前安裝的Dex檔名字衝突。


接下來看看build(outFile, dexFile),首先從keystone裡面獲取應用相關簽名,將getMeta()中獲取的Manifest內容寫入"META-INF/PATCH.MF"檔案中。getMeta()方法上面,例項化PatchBuilder,然後呼叫writeMeta(getMeta())。我們走進去先看看。

 


這個就是將dexFile和簽名相關資訊寫入classes.dex檔案中,可以有點蒙。我們就看看writeFile()方法。

 

SignedJarBuilder的構造方法做了一些初始化和賦值操作,提到這個是方便能夠理解writeFile()這個方法。writeFile裡面呼叫了writeEntry(),我們看看它。

 

這個方法就是從input輸入流中讀取buffer資料然後寫入到entry。然後聯絡到我上面提到的將dexfile和簽名相關資訊寫入到classes.dex裡面。應該能好理解點。

上面提了一大堆,我們的東西準備的差不多了,現在就看看最後一個方法ApkPatch release(this.out, dexFile, outFile)

 

這個方法就是將dexFile進行md5加密,把build(outFile, dexFile);函式中生成的outFile重新命名。哈哈,看到”.patch”有沒有很激動!!我們的補丁包一開始的命名就是一長串。好了,到這裡,補丁檔案就生成了!接下來我們看看,怎麼來使用它。堅持就是勝利,馬上你就要熬過頭了...沒辦法,別人團隊花了這麼長時間做的,想分析就得花時間。

相關資料工具及demo下載地址:http://pan.baidu.com/s/1hsdcs7a

轉載請註明轉自:http://blog.csdn.net/u011176685/article/details/50984796

相關文章