Android熱修復之dex修復原理

Android熱修復之dex修復原理

首先有一個出Bug的類

 

 

然後在點擊按鈕事件裏面添加調用bug類的方法

 

 

模擬bug出現的場景。

 

 

再修復這個出bug類的方法

 

然後生成dex文件

 

dx命令

dx --dex --output=a.dex com\example\hellojnicallback\BugTest.class

要把BugTest的包路徑都複製過來,然後執行命令,執行成功後可以看到a.dex文件生成,重命名fix_dex.dex後把這個文件放到手機的sd卡上

 

 

在點擊單選按鈕2的時候調用修復的方法

 

 

 

這個主要是調用MergeDexUtil裏面的copyDexFileToAppAndFix方法

 

copyDexFileToAppAndFix方法主要是先把sdcard目錄上的dex文件copy到應用的目錄下

 

再調用mergeDex方法修復

 

 

 

 

 

104~106獲取我們APP和的補丁dex文件的BaseDexClassLoader裏面的pathList屬性,

如下,該屬性是個DexPathList類型。

108~109行獲取DexPathList類裏面的dexElements屬性,該屬性是一個Element數組

111行則是把兩個數組和並,並且補丁裏面的Element數組在前面.現在看這些代碼會感覺有點懵逼

至於爲什麼這樣子,稍後解析原理時再說明緣由,瞭解了原理之後再來看這些代碼自然會茅塞頓開。

BaseDexClassLoader部分源碼

 

DexPathList部分源碼

 

 

getField主要是反射調用對象的屬性,setFieldValue主要是反射設置對象的屬性

 

 

combineArray方法主要是合併兩個數組

 

 

點擊2的單選按鈕

 

再次點擊helloworld控件後,顯示的是我們修復成功後的值

 

 

 

 

 

 

 

原理探祕篇:

首先一個類要能夠被使用,要被類加載器加載進來的。而android中主要用的是兩個類加載器DexClassLoaderPathClassLoader

適用場景:

    DexClassLoader可以加載jar/apk/dex,可以從SD卡中加載未安裝的apk

    PathClassLoader只能加載系統中已經安裝過的apk

 

 

BootClassLoader:java虛擬機中不同的是BootClassLoader是ClassLoader內部類,由java代碼實現而不是c++實現,是Android平臺上所有ClassLoader的最終parent,這個內部類是包內可見,所以我們沒法使用。

URLClassLoader:只能用於加載jar文件,但是由於 dalvik 不能直接識別jar,所以在 Android 中無法使用這個加載器。

平常我們安裝的app裏面的類加載基本都是PathClassLoader加載的

測試代碼

 


輸出

PathClassLoader 繼承BaseDexClassLoader ,加載類的方法在BaseDexClassLoader裏面,再查看BaseDexClassLoader方法


BaseDexClassLoaderfindClass方法的54行,實際上加載findClassDexPathList類的findClass去加載的,繼續看DexPathListfindClass方法

findClass338行是DexPathList裏面的一個dexElements數組裏面去查找類的。

 

dexElements數組裏面的Element是個啥呢

ElementDexPathList的一個內部類,裏面包含了DexFile對象

 

 

一般情況下,如果我們的app沒有分包的話,解壓apk文件,可以看到解壓的目錄下有個classes.dex文件,這個文件就是我們所有的源文件的class的合集後轉成dex的文件,至於爲什麼要把class文件轉成dex文件,因爲google工程師覺得class文件還是有很多冗餘信息,而且剛開始的時候手機內存本來就很小,於是把所有的class文件信息合併一個dex文件,並打包在apk中,

如果只有一個dex文件,DexPathList裏面的一個dexElements的大小就爲1 ,有兩個則爲2 依次類推。

BaseDexClassLoader加載類如果要加載某個類,則從dexElements數組的依次查找類,如果查找到了,則返回。也就是前面我們把我們自己生成dex文件插到dexElements前面的原因,因爲查找到了我們的類,後面同樣的類就不會有機會加載到了。

總結:此技巧利用了android類加載器的加載機制從而實現了熱修復。

但是有個缺點是某個出bug的類加載過一次後,只能等app重新啓動後才能實現修復功能,因爲我們知道類加載過後就類信息就已經存在方法區中了,下次再用的話就不會重新再加載了一遍了。

 

做個試驗

helloworld控件的點擊事件添加異常捕獲,以免app異常退出

 

在修復之前點擊helloworld控件,出現了異常。

 

在點擊2的單選按鈕修復。

 

 

修復後再點擊helloworld控件查看打印信息,依然沒有修復。

 

也就是說要app重新啓動才能達到修復效果

demo地址

如果想要app不重新啓動的情況下達到修復效果,可以查看博客熱修復之AndFix探祕

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章