Android熱修復(fù)方案研究

一闸度、概述

??以前對Android 的熱修復(fù)方案有一些了解侣肄,知道幾個(gè)有名的開源方案,原理大概理解印屁,但是沒有整理匯總一下循捺,上周聽了玉斌大哥在公司做的分享后,感受頗多覺得寫篇博客記一下雄人,不能浪費(fèi)从橘。

??熱修復(fù)是指在不發(fā)新版的情況下修復(fù)線上的緊急 bug,長久以來做移動(dòng)開發(fā)的人員都羨慕做后端或者做 web 前端的人員可以隨時(shí)發(fā)布來修復(fù) bug。那么 移動(dòng)開發(fā)有沒有這樣的方案呢恰力?

Hybrid

如:PhoneGap叉谜、國內(nèi)的 AppCan。本質(zhì)還是利用了 Web 開發(fā)在更新上的優(yōu)勢牺勾,但體驗(yàn)不如 Native正罢。

ReactNative

像Web一樣可以隨時(shí)發(fā)布,又有原生的體驗(yàn)驻民,所以這個(gè)方案優(yōu)勢挺大翻具,有很多項(xiàng)目都在嘗試。

Native HotFix

可以不用發(fā)新版本回还,直接下發(fā)補(bǔ)丁包修復(fù) bug裆泳,純原生體驗(yàn)。

iOS有JSPatch柠硕、Android 有 AndFix工禾、Nuwa、DroidFix 蝗柔、HotFix等

二闻葵、Android Native HotFix

下面按照原理分類為

(一) Dex分包方案(QZone的方案)(如 Nuwa、DroidFix癣丧、HotFix槽畔、RocooFix)

??原理:如果多個(gè) dex 里有相同的class,那么虛擬機(jī)會(huì)優(yōu)先使用最先加載的 dex 中的 class胁编。所以將有問題的類打包到一個(gè)新dex(pathc.dex)厢钧,然后下發(fā)給 app,app 啟動(dòng)時(shí)將該patch.dex插入到其他 dex 前面優(yōu)先加載嬉橙。就達(dá)到了 替換有問題 class 的目的早直。

這里有兩個(gè)難點(diǎn):

1. 改變dex加載順序

2. class_ispreverified

錯(cuò)誤信息:java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation

原因

??dex轉(zhuǎn)化成odex時(shí)會(huì)執(zhí)行dvmVerifyClass進(jìn)行類的校驗(yàn),如 B的引用和B都在一個(gè) dex 里市框,則 B 會(huì)被打上class_ispreverified標(biāo)記霞扬,但是我們優(yōu)先加載 A’,A’和B在兩個(gè)不同的 dex,但 B 卻打上了class_ispreverified標(biāo)識(shí)所以就報(bào)錯(cuò)了。

??兩個(gè)相關(guān)聯(lián)的類在不同的dex中并且有class_ispreverified就會(huì)報(bào)錯(cuò)枫振,谷歌MultiDex拆分dex的時(shí)候就會(huì)處理這種情況如果A 和 B 不在同一個(gè) Dex 就不會(huì)給 B標(biāo)記class_ispreverified喻圃。

??但我們是熱修復(fù),patch.dex 是事后打的 dex,class.dex已經(jīng)安裝的用戶手機(jī)里了蒋得,所以我們無法修改 B 的標(biāo)識(shí)级及。

解決方案:

我們發(fā)布版本打包時(shí)乒疏,將所有的類都引用一個(gè)單獨(dú)dex的一個(gè)類额衙,這個(gè)所有的類都不會(huì)標(biāo)記class_ispreverified了,當(dāng)然這也就失去了class_ispreverified的意義,會(huì)有性能上的影響窍侧。

更新:還有一個(gè)巧妙的方案來防止class_ispreverified,就是在工程里放入一個(gè)android.jar 已經(jīng)存在的類县踢,這樣會(huì)導(dǎo)致multiple class declarations 從而不會(huì)再對class 校驗(yàn)。比如使用com.android.internal.util.Predicate伟件,這樣類的特點(diǎn)是特別簡單沒有額外引用硼啤,然后它從android api 8 就存在了。

QZone 安卓App熱補(bǔ)丁動(dòng)態(tài)修復(fù)技術(shù)介紹

深度理解Android InstantRun原理以及源碼分析

(二)smali diff方案(阿里的方案)(以 AndFix為例)

1. 原理

2. 方法替換(AOP)

??搞過 Android Aop 的同學(xué)知道斧账,我們可以在執(zhí)行一個(gè)方法的前插入另一個(gè)方法谴返,運(yùn)用這個(gè)思路,我們可以把有 bug 的方法替換成我們下發(fā)的新方法咧织。

下邊是 AndFix 使用 JNI hook 方法的一段代碼嗓袱,供大家理解。另一個(gè)實(shí)現(xiàn)AOP 的開源方案

dexposed

Android AOP 常用有的方法有 JNI HOOK 和 靜態(tài)織入习绢。

常用的靜態(tài)織入的庫有:

1渠抹、APT 是代碼生成,java文件 生成 java文件闪萄。使用的annotation類型是SOURCE.

2梧却、Aspectj是靜態(tài)織入。靜態(tài)織入:指在編譯時(shí)期就織入败去,即:編譯出來的class文件放航,字節(jié)碼就已經(jīng)被織入了。AspectJ就是一個(gè)編譯器为迈,把java文件編譯成想要的class文件三椿。使用的annotation類型是SOURCE.

3、ASM或者Javassist或者dexmaker 是Java 字節(jié)碼操控框架葫辐。它能被用來動(dòng)態(tài)生成類或者增強(qiáng)既有類的功能搜锰。使用的annotation類型是class.

注:

cglib底層采用ASM字節(jié)碼生成框架,實(shí)現(xiàn)動(dòng)態(tài)代理實(shí)現(xiàn)AOP

cglib在android中是不能使用的耿战。使用dexmaker框架來仿照動(dòng)態(tài)生成.dex文件蛋叼,實(shí)現(xiàn)cglib的動(dòng)態(tài)代理功能

3. ApkPatch tool

??AndFix 提供了一個(gè)打包 patch 的工具,這個(gè)工具將舊Apk和新Apk做 diff 得出一個(gè)patch apk剂陡。

熟悉增量更新的同學(xué)應(yīng)該知道狈涮,增量更新也是做 diff 求增量包,但是他是在字節(jié)碼層面上求增量包鸭栖,增量包+舊 apk 合并成新 apk歌馍。

??而ApkPatch是通過對比兩個(gè) apk 反編譯后的 smali 文本文件來求 diff 的。所以他是從 class 層面上求 diff晕鹊。得到的patch就是標(biāo)準(zhǔn)的 dex 包松却。 該 dex 可直接被 load暴浦。

4. 以前注意事項(xiàng)

一個(gè) patch 包要修復(fù)哪些類的哪些方法,這個(gè)路徑信息會(huì)被打包到 patch.apk 的META-INFO里

patch.apk在打包時(shí)要使用相同的簽名晓锻。

混淆的情況:打包 patch.apk 時(shí)要使用主apk混淆時(shí)導(dǎo)出的 mapping 文件歌焦,防止主apk和patch.apk 由于混淆而無法對應(yīng)相應(yīng)的類和函數(shù)。

目前 apkpatch 沒有開源砚哆,還有一些小 bug独撇,如不支持 mulitdex。雖然沒有開源但還是有方法修復(fù)的躁锁,比如反編譯導(dǎo)出源碼纷铣、還有 javasist 神器。具體怎么修復(fù)以后再說战转,也可能官方會(huì)修復(fù)关炼。

(三)微信的方案

AndFix 由于影響正向開發(fā)過程(只能修改方法、不能修改 field匣吊、不能新增類等問題)儒拂、庫本身難于維護(hù)以及發(fā)現(xiàn)的莫名其妙的 bug(不同rom對dex的校驗(yàn)機(jī)制不一致)。

nuwa 僅支持更新 Java 代碼色鸳,不能更新資源和 so 文件社痛。

全量替換新的Dex。即我們完全使用了新的Dex命雀,那樣既不出現(xiàn)Art地址錯(cuò)亂的問題蒜哀,在Dalvik也無須插樁。當(dāng)然考慮到補(bǔ)丁包的體積吏砂,我們不能直接將新的Dex放在里面撵儿。但我們可以將新舊兩個(gè)Dex的差異放到補(bǔ)丁包中,最簡單我們可以采用BsDiff算法狐血。

附《Android核心知識(shí)筆記2020》分享

前段時(shí)間我和圈子里的幾位架構(gòu)師朋友一起閑聊時(shí)的突發(fā)奇想淀歇,我們在學(xué)習(xí)Android開發(fā)的時(shí)候或多或少也受到了一些前輩的指導(dǎo),所以想把這份情懷延續(xù)下去匈织。三個(gè)月后浪默,這套資料就出來了,需要這份資料的朋友加Android學(xué)習(xí)交流群1049273031即可獲取缀匕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纳决,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乡小,更是在濱河造成了極大的恐慌阔加,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件满钟,死亡現(xiàn)場離奇詭異胜榔,居然都是意外死亡约急,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門苗分,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人牵辣,你說我怎么就攤上這事摔癣。” “怎么了纬向?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵择浊,是天一觀的道長。 經(jīng)常有香客問我逾条,道長琢岩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任师脂,我火速辦了婚禮担孔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吃警。我一直安慰自己糕篇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布酌心。 她就那樣靜靜地躺著拌消,像睡著了一般。 火紅的嫁衣襯著肌膚如雪安券。 梳的紋絲不亂的頭發(fā)上墩崩,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機(jī)與錄音侯勉,去河邊找鬼鹦筹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛址貌,可吹牛的內(nèi)容都是我干的盛龄。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼芳誓,長吁一口氣:“原來是場噩夢啊……” “哼余舶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锹淌,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤匿值,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后赂摆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挟憔,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钟些,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绊谭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片政恍。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖达传,靈堂內(nèi)的尸體忽然破棺而出篙耗,到底是詐尸還是另有隱情,我是刑警寧澤宪赶,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布宗弯,位于F島的核電站,受9級特大地震影響搂妻,放射性物質(zhì)發(fā)生泄漏蒙保。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一欲主、第九天 我趴在偏房一處隱蔽的房頂上張望邓厕。 院中可真熱鬧,春花似錦扁瓢、人聲如沸邑狸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽单雾。三九已至,卻和暖如春她紫,著一層夾襖步出監(jiān)牢的瞬間硅堆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工贿讹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渐逃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓民褂,卻偏偏與公主長得像茄菊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子赊堪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容