1. 程式人生 > >Android 熱修復總結

Android 熱修復總結

前段時間熱修復這個詞非常火,當時只是大體看了一下,今天抽空好好看了一下具體原理.

什麼是熱修復?

簡單的說就是使用者不用重新下載一個新的apk安裝,而是直接下載一個補丁包,通過補丁來替換一些出現bug的類, 當然下載補丁的過程使用者一般是感覺不到的,表面上看是直接修復了bug.

原理

類似與外掛開發,關於外掛開發原理,看這篇 Android外掛原理剖析 ,其中介紹了一下java中的類載入器和android中的類載入器. 熱修復就是利用android中的 DexClassLoader 類載入器,動態載入補丁dex,替換有bug的類

已有的熱修復解決方案:

切入點

想修復方法? 方法在哪裡? 方法都包含在類中. 類在哪裡? 類被包含在dex中,而

最根本的來源是下面這段程式碼:

public Class findClass(String name) {
    for (Element element : dexElements) {
        DexFile dex = element.dexFile;
        if (dex != null) {
            Class clazz = dex.loadClassBinaryName(name, definingContext);
            if (clazz != null) {
                return clazz;
            }
        }
    }
    return
null; }

可以看出呢,BaseDexClassLoader中有個 pathList 物件,pathList中包含一個DexFile的集合 dexElements ,而對於類載入呢,就是遍歷這個集合,通過DexFile去尋找,一個ClassLoader可以包含多個dex檔案,每個dex檔案是一個Element,多個dex檔案排列成一個有序的陣列dexElements,當找類的時候,會按順序遍歷dex檔案,然後從當前遍歷的dex檔案中找類,如果找類則返回,如果找不到從下一個dex檔案繼續查詢。

簡單來說: 首先找到 pathList 物件,然後通過反射改變 dexElements

 陣列.

但是遇到的以下問題: 也就是類被打上了 CLASS_ISPREVERIFIED 標誌

java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation

根據QQ空間的文章, 這個錯誤是因為虛擬機器載入類的時候, 當一個類中的直接方法(Direct Method)來自與同一個dex中,那麼這個類就會被加上 CLASS_ISPREVERIFIED 標誌, 再次通過類載入器載入會出現上面的錯誤.

解決方案: 在需要載入的類中,引用一個別的dex中的類.這樣這個類就不會被加上 CLASS_ISPREVERIFIED 標誌了,然後就可以再次載入了. 上面一個開源庫的普遍方案就是在類的 預設構造方法 上面新增一個其他dex的引用.

總結

於是總體步驟如下:

  1. 可能出現bug的類中,引用一下別的dex中的類.
  2. 因為1中引用了別的dex,需要先將別的dex載入進來.
  3. 現在可以替換bug的類了,載入補丁,通過反射將補丁中的dex放到 pathList 物件的 dexElements 陣列的前面,完成打補丁.

其中兩個注意點:

  • 防止類被加上 CLASS_ISPREVERIFIED 標誌(通過修改類預設構造方法)
  • 生成補丁dex(通過dx工具)