熱修復之類載入方案 筆記整理

2021-09-26 23:16:04 字數 4453 閱讀 8463

其中,**修復又分為:類載入方案、底層替換方案、instant run 方案。

本篇關於**修復的類載入方案的筆記整理。

涉及原始碼版本為 android 7.1.1。

參考文章:

1、android熱更新實現原理**

2、《android 高階解密》

1、理論基礎

類載入方案是基於 dex 分包方案的。

dex 分包方案主要做的是在打包的時候將應用**分成多個 dex,將應用啟動時必須用到的類和這些類的直接引用類放到主 dex 中,其他**放到次 dex 中。當應用啟動時先載入主 dex,等到應用啟動後再動態載入次 dex。

而關於類的載入,就是遍歷所有的 dex 檔案,從中去載入目標類。這裡就涉及到了乙個類dexpathlist

更進一步的,是具體的是,則是涉及到類載入器。

對於類的載入,是通過classloader來進行的,基於雙親委託模式,會先通過具體的載入器的父載入器來載入類,如果父載入器沒載入到,則會呼叫自身的findclass()方法來自行載入。

涉及到的載入器包括dexclassloaderpathclassloader

dexclassloader可以載入 dex 檔案以及包含 dex 的壓縮檔案(apk 和 jar 檔案),而且可以載入指定路徑中的 dex 檔案,包括外部儲存空間的。

pathclassloader則是 android 系統用來載入系統類和應用程式的類。通常用來載入已經安裝的 apk 的 dex 檔案(安裝的 apk 的 dex 檔案會存在/data/dalvik-cache)。

上述兩個 classloader 都繼承自basedexclassloader

public

basedexclassloader

(string dexpath, file optimizeddirectory,

string librarysearchpath, classloader parent)

@override

protected class<

?>

findclass

(string name)

throws classnotfoundexception

return c;

}

可以看到,通過basedexclassloader#findclass()會進一步呼叫前面說到的dexpathlist型別的pathlist.findclass()

public class findclass

(string name, list

suppressed)}}

if(dexelementssuppressedexceptions != null)

return null;

}

dexpathlist#findclass()中,會遍歷dexelements陣列,該陣列的元素的為dexpathlist.element型別,而其內部又封裝了dexfile成員變數,該變數就對應著實際的 dex 檔案,更進一步的說,載入 class 實際上是通過dexfile來實現的。

因此,類載入方案的實現,就是將補丁 dex 對應的element插入到應用對應的載入器的pathlistdexelements陣列的靠前位置,從而使得後面同名的 class 不被載入。

2、具體實現

補充兩點:

(1)是關於class_ispreverified的問題(涉及到 dalvik 虛擬機器),具體參見:android 冷啟動熱修復技術雜談,因此在測試的時候要使用基於 art 虛擬機器的機型,即 android 5.0 及以上版本。

(2)由於 android 9.0 隱藏了部分 api,所以無法實現反射替換對應的dexelements陣列,因此在測試的要使用 9.0 以下的手機。

關鍵部分**:

public

void

dohotfix

(context context)

throws illegalacces***ception, nosuchfieldexception, classnotfoundexception

// 補丁存放目錄為 /storage/emulated/0/android/data/com.lxbnjupt.hotfixdemo/files/patch

// 注意,這裡的 dexfile 是乙個目錄

file dexfile = context.

getexternalfilesdir

(dex_dir);if

(dexfile == null ||

!dexfile.

exists()

)// 得到 new dexclassloader 時需要的儲存路徑

file odexfile = context.

getdir

(optimize_dex_dir, context.mode_private);if

(!odexfile.

exists()

)// 獲取 /storage/emulated/0/android/data/com.lxbnjupt.hotfixdemo/files/patch

// 目錄下的所有檔案,用於找出裡面的補丁 dex

file[

] listfiles = dexfile.

listfiles()

;if(listfiles == null || listfiles.length ==0)

// 獲取補丁 dex 檔案路徑集合

string dexpath =

getpatchdexpath

(listfiles)

; string odexpath = odexfile.

getabsolutepath()

;// 獲取應用對應的 pathclassloader

pathclassloader pathclassloader =

(pathclassloader) context.

getclassloader()

;// 構建 dexclassloader,用於載入補丁 dex

// dexclassloader 構造方法的四個引數:

// 第二個:解壓的 dex 檔案的儲存路徑,必須是乙個內部儲存路徑

// 第三個:包含 c/c++ 庫的路徑集合,可以為 null

// 第四個:父載入器

dexclassloader dexclassloader =

newdexclassloader

(dexpath, odexpath, null, pathclassloader)

;// 這裡要新 new 乙個 dexclassloader 的原因就是為了借助系統來構建出補丁 dex 對應

// 的 element 元素的陣列,從而插入到應用的 pathclassloader 的

// pathlist.dexelements 中

// 通過反射獲取 pathclassloader 的 element 陣列

object pathelements =

getdexelements

(pathclassloader)

;// 獲取構建的 dexclassloader 的 element 陣列

object dexelements =

getdexelements

(dexclassloader)

;// 合併 element 陣列

object combineelementarray =

combineelementarray

(pathelements, dexelements)

;// 通過反射,將合併後的 element 陣列賦值給 pathclassloader 中 pathlist 裡面的

// dexelements 變數

setdexelements

(pathclassloader, combineelementarray)

;}

而且重啟應用之後,如果沒有觸發載入補丁類,則應用還是會載入原來的 bug 類。

Android 熱修復思路整理

流行的熱修復方式 按技術特點劃分 本文採用的熱修復 思路 載入應用程式的classloder classloader classloader context.getclassloader for file file loadeddex 因為系統通過dexclassloder來載入dex,所以需要將新...

iOS實現熱修復的幾種方案

最近,在調研熱修復技術,也稱作熱更新技術。由於蘋果審核週期有時候比較長,這是公司無法忍受的,所以熱修復技術應運而生。經過查閱多方面的資料,進行如下總結,希望對大家有所幫助。現在比較流行的熱修復技術 一 使用jspatch進行熱修復。jspatch能做到通過js呼叫和改寫oc方法。最根本的原因是 ob...

記錄 動態載入dex實現某些熱修復

日記。private boolean loaddex catch exception e return true catch exception e return false 2 建立乙個專案,以org.jemen.test為包名,建立mydex類,想要熱更新的方法名包含 jemen export出...