熱修復、熱補丁與插件化

標簽(空格分隔): Android


基礎知識補充:###

為什么需要分包:
Android2.3及以前版本用來執行dexopt(用于優化dex文件)的內存只分配了5M,
一個dex文件最多只支持65536個方法

其實android中的分包,除了用dex分包還可以用插件化,即將一些獨立的功能做成一個單獨的apk,當打開的時候使用DexClassLoader動態加載,然后使用反射機制來調用插件中的類和方法。這固然是一種解決問題的方案:但這種方案存在著以下兩個問題:

  1. 插件化只適合一些比較獨立的模塊;
  2. 必須通過反射機制去調用插件的類和方法,因此,必須搭配一套插件框架來配合使用;

但是使用dex分包方案仍然有幾個注意點:

  1. 由于第二個dex包是在Application的onCreate中動態注入的,如果dex包過大,會使app的啟動速度變慢,因此,在dex分包過程中一定要注意,第二個dex包不宜過大。
  2. 由于上述第一點的限制,假如我們的app越來越臃腫和龐大,往往會采取dex分包方案和插件化方案配合使用,將一些非核心獨立功能做成插件加載,核心功能再分包加載。(采用dex分包+插件化)

熱修復、熱補丁##

參考文章:安卓App熱補丁動態修復技術介紹——QQ空間終端開發團隊鴻洋文章

應用場景:
當一個App發布之后,突然發現了一個嚴重bug需要進行緊急修復,這時候公司各方就會忙得焦頭爛額:重新打包App、測試、向各個應用市場和渠道換包、提示用戶升級、用戶下載、覆蓋安裝。有時候僅僅是為了修改了一行代碼,也要付出巨大的成本進行換包和重新發布。
這時候就提出一個問題:有沒有辦法以補丁的方式動態修復緊急Bug,不再需要重新發布App,不再需要用戶重新下載,覆蓋安裝?

熱修復是基于android dex分包方案的,android dex分包原理
簡單來說,其原理是將編譯好的class文件拆分打包成兩個dex,繞過dex方法數量的限制以及安裝時的檢查,在運行時再動態加載第二個dex文件中。除了第一個dex文件(即正常apk包唯一包含的Dex文件),其它dex文件都以資源的方式放在安裝包中,并在Application的onCreate回調中被注入到系統的ClassLoader。因此,對于那些在注入之前已經引用到的類(以及它們所在的jar),必須放入第一個Dex文件中。


這里要區別PathClassLoader與DexClassLoader###

PathClassLoader和DexClassLoader都繼承自BaseDexClassLoader
1、Android使用PathClassLoader作為其類加載器,只能去加載已經安裝到Android系統中的apk文件;
2、DexClassLoader可以從.jar和.apk類型的文件內部加載classes.dex文件就好了。如果大家對于插件化有所了解,肯定對這個類不陌生,插件化一般就是提供一個apk(插件)文件,然后在程序中load該apk,那么如何加載apk中的類呢?其實就是通過這個DexClassLoader。熱修復也用到這個類!

#BaseDexClassLoader源碼
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
    Class clazz = pathList.findClass(name);

    if (clazz == null) {
        throw new ClassNotFoundException(name);
    }

    return clazz;
}

#DexPathList
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;
}

#DexFile
public Class loadClassBinaryName(String name, ClassLoader loader) {
    return defineClass(name, loader, mCookie);
}
private native static Class defineClass(String name, ClassLoader loader, int cookie);
//
可以看出呢,BaseDexClassLoader中有個pathList對象,pathList中包含一個DexFile的集合dexElements,而對于類加載呢,就是遍歷這個集合,通過DexFile去尋找。
ok,通俗點說:
一個ClassLoader可以包含多個dex文件,每個dex文件是一個Element,多個dex文件排列成一個有序的數組dexElements,當找類的時候,會按順序遍歷dex文件,然后從當前遍歷的dex文件中找類,如果找類則返回,如果找不到從下一個dex文件繼續查找。(來自:安卓App熱補丁動態修復技術介紹)

總結##

其實就是兩件事:1、動態改變BaseDexClassLoader對象間接引用的dexElements;2、在app打包的時候,阻止相關類去打上CLASS_ISPREVERIFIED標志。


理論基礎:把多個dex文件塞入到app的classloader之中,但是android dex拆包方案中的類是沒有重復的,如果classes.dex和classes1.dex中有重復的類,當用到這個重復的類的時候,系統會選擇哪個類進行加載呢?
   一個ClassLoader可以包含多個dex文件,每個dex文件是一個Element,多個dex文件排列成一個有序的數組dexElements,當找類的時候,會按順序遍歷dex文件,然后從當前遍歷的dex文件中找類,如果找類則返回,如果找不到從下一個dex文件繼續查找。
理論上,如果在不同的dex中有相同的類存在,那么會優先選擇排在前面的dex文件的類

在此理論基礎上,我們構想了熱補丁的方案,,我們可以在這個dexElements中去做一些事情,把有問題的類打包到一個dex(patch.dex)中去,然后把這個dex插入到Elements的最前面比如,在這個數組的第一個元素放置我們的patch.jar,里面包含修復過的類,這樣的話,當遍歷findClass的時候,我們修復的類就會被查找到,從而替代有bug的類。


插件化##

Android插件化基礎:使用了自定義的ClassLoader來實現的加載,功能比較簡單,只支持class的加載與另外也可以通過使用系統的DexClassLoader來直接加載Jar,Apk

使用PathClassLoader加載已安裝的apk插件、DexClassLoader加載未安裝的apk插件

通過插件化的操作,就可以做一個簡單的代碼邏輯的插件化了。將你的邏輯處理代碼打包成Jar或者APK,放到服務器上。
客戶端開啟后檢查是否有新的版本,如果有就后臺下載,覆蓋源文件(這樣邏輯上應該先把舊的邏輯加載到內存中,這里可以有很多不同的策略)。
下次打開的時候,直接加載新下載的Jar或者APK就動態更新了內部邏輯
【與原先的下載新的APK跟新版本不同,因為插件化的APK只是新增的功能類,所以體積小】

插件化框架:

此處輸入圖片的描述
此處輸入圖片的描述

插件化發展歷史:博客一博客二
說到未來,也不得不提去年出來的ReactNative,RN比插件化更輕量級,越來越多人選擇了RN,或許會代替插件化,雖然還有很多缺點,比如說沒網的時候


熱修復與插件化的對比##

共同原理:
都使用ClassLoader來實現的加載的新的功能類,都可以使用PathClassLoader與DexClassLoader
不同的是:
  熱修復因為是為了修復Bug的,所以要將新的同名類替代同名的Bug類,要搶先加載新的類而不是Bug類,所以多做兩件事:在原先的app打包的時候,阻止相關類去打上CLASS_ISPREVERIFIED標志,還有在熱修復時動態改變BaseDexClassLoader對象間接引用的dexElements,這樣才能搶先代替Bug類,完成系統不加載舊的Bug類
  而插件化只是增肌新的功能類或者是資源文件,所以不涉及搶先加載舊的類這樣的使命,就避過了阻止相關類去打上CLASS_ISPREVERIFIED標志和還有在熱修復時動態改變BaseDexClassLoader對象間接引用的dexElements
  所以插件化比熱修復簡單,熱修復是在插件化的基礎上在進行替舊的Bug類

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容