Android熱修復(fù)主流方案盤點

前言

上一個大的系列文章叫 "手把手講解", 歷時10個月,出產(chǎn)博文二十余篇,講解細(xì)致,幾乎每一篇都提供了詳實的原理講解,提供了可運行github Demo,并且針對Demo中的關(guān)鍵地地方進(jìn)行了重點拆解。相信每一位詳細(xì)閱讀文章的同行都會有所收獲。但是,講解雖詳細(xì),但是缺乏對于技術(shù)的深度的挖掘。

從今天開始開辟新的專題: 移動架構(gòu)師專業(yè)技能深入淺出,以一步步成為架構(gòu)師為目標(biāo),詳述一項架構(gòu)師技能的最直接使用價值橫向周邊知識以及縱深專業(yè)技術(shù).

最直接使用價值: 網(wǎng)上最怕看到一種文章,全文開篇高大上,讓人覺得遙不可及,通篇看下來卻沒有展示技術(shù)如何落地,落地之后是何種效果。文章寫出來,就要以最容易讓人接受的方式帶讀者進(jìn)入作者的世界,而不是裝作一副高高在上的樣子俯視眾生。所以,文章開篇,一定是最直接的展示技術(shù)的落地效果。提供可運行Demo可以讓讀者親自嘗試。

橫向周邊知識: 一項核心技術(shù),必然不是獨立存在,技術(shù)是一個體系,但是一篇文章能夠詳述的技術(shù)有限,必然是以一項技術(shù)為中心,其他技術(shù)作為輔助。核心技術(shù)需要詳述,但是周邊技術(shù),也需要交代,參天大樹拔地而起也少不得土壤作為依附。用簡明的語言交代周邊知識,并提供這些知識正確的研究方向。也是一個負(fù)責(zé)任的博文作者不可忽視的一步。

縱深專業(yè)技術(shù): 做技術(shù),最忌諱的就是淺嘗輒止。稍微深入一點就退出去,一來不利于理解底層實現(xiàn),長此以往永遠(yuǎn)只是一個技術(shù)小白,成不了大師;二來不利于長久記憶, 記憶力再強(qiáng)的人時間長了,技術(shù)細(xì)節(jié)必然會記憶模糊。但是如果深入內(nèi)核,理解了原理,在技術(shù)的大方向上絕對不會偏差。作為要成為架構(gòu)師的男人,即使記不了那么多細(xì)節(jié),但是對于大方向的把握絕對不能錯。所以,技術(shù)縱深很有必要。

前情提要

上一篇 Android熱更新修復(fù)核心原理 提到了 熱修復(fù)的其中一種Muitidex方案,并且給出了演示Demo。但是真正完整去展現(xiàn)現(xiàn)實中的 熱修復(fù)開源框架,遠(yuǎn)遠(yuǎn)不夠。

正文大綱

  • 阿里AndFix 方案
  • 美團(tuán) Robust方案
  • 騰訊 Tinker dexdiff / DexMerge方案
  • 騰訊 QZone Muitidex方案

正文

熱修復(fù)方案按照是否必須重啟 分為兩類: 重啟生效 / 即時生效。按照 實現(xiàn)方式可以分為3類: java層的實現(xiàn) / native層的實現(xiàn) / java native混合實現(xiàn)

阿里AndFix 方案(已棄用)

AndFix 是 無需重啟native層 的實現(xiàn). 但是,AndFix目前已經(jīng)3年多沒維護(hù)更新。
因為阿里已經(jīng)有了新的替代方案,不再需要維護(hù)。另外,這種純native的實現(xiàn)方式,兼容性十分堪憂。
既然已經(jīng)被棄用,但是稍微了解一下 實現(xiàn)方案也是沒問題的。


上圖解讀
圖中有一段程序按照A=>B=>C的順序去執(zhí)行,然而發(fā)現(xiàn)執(zhí)行到B的時候,存在一個bug,AndFix的修復(fù)方式為:在native層執(zhí)行到B方法的時候,把方法的指針指向了 補(bǔ)丁包里的B方法,繞過了原來的B方法。從而達(dá)到了修復(fù)bug的目的。

使用方法:


在需要修復(fù)的方法上面,加上@MethodReplace注解,給定參數(shù),class和method,表示 該方法替換為 哪個類的哪個方法。

缺陷
修復(fù)粒度為:method. AndFix只能以方法為粒度去修復(fù)bug。作用有限,針對大范圍的類替換和資源替換,那就無能為力了。

美團(tuán) Robust方案

Robust 是 即時生效Java層實現(xiàn)的熱修復(fù)實現(xiàn)方案.

美團(tuán)的Robust方案,是參考了谷歌的InstantRun方案(之前在androidStudio里面有這個選項,可以選擇打開instant run運行app)的思路而設(shè)計出來的。

其主要設(shè)計思想就是一句話:編譯打包時,在程序的某些方法里面,都插入一段代碼(全自動操作):


當(dāng)changeQuickRedirect不為空的時候,該方法就會命中if(changeQuickRedirect!=null),從而執(zhí)行修復(fù)的實現(xiàn)代碼。當(dāng)為空的時候,則正常執(zhí)行原邏輯。

而平時我們自己編碼,只需要加上一個@modify注解,來標(biāo)記這個方法需要打補(bǔ)丁包,也就是需要插入上面這個if(changeQuickRedirect!=null)代碼段。

為什么它可以即時生效?


上圖解析:
利用ClassLoader,當(dāng)客戶端手機(jī)收到補(bǔ)丁包 patch.dex的時候,執(zhí)行補(bǔ)丁包,把指定方法的changeQuickRedirect反射的手段賦值,讓它變成非空。從而讓下一次程序邏輯走到這里的時候,走修復(fù)之后的邏輯。

Robust是如何將這么多if(changeQuickRedirect!=null)代碼段插入到代碼邏輯中的?:

上圖中的if(changeQuickRedirect!=null)代碼段,并非我們手動編寫,而是由Robust框架自動插入的。
這個技術(shù)叫做 字節(jié)碼插樁,意為:對class進(jìn)行操作,按照class文件的格式,插入自己想要的邏輯。
目前Robust支持兩種字節(jié)碼插樁方案AspectJJavasist.

騰訊 Tinker dexdiff / DexMerge方案

Tinker 是騰訊自研的 重啟生效Java層的實現(xiàn).

原理

Tinker基于一個基準(zhǔn)dex,以及修復(fù)bug之后的dex,使用dexdiff算法,計算出差分包dex。然后把差分包推送給客戶端,客戶端收到之后,重啟運行app,把差分包dex和原dex進(jìn)行合并,形成新的dex。然后ClassLoader去創(chuàng)建類class對象的時候,就會創(chuàng)建修復(fù)bug之后的類class對象。 從而達(dá)到 修復(fù)bug的目的。


Dexdiff算法

了解增量更新的人應(yīng)該知道 bsdiff。 bsdiff是無視文件格式,生成兩個二進(jìn)制文件的差異文件。dexdiff是基于bsdiff,并且進(jìn)行了針對dex文件格式的優(yōu)化。 Tinker除了支持Dex修復(fù)之外,還支持so修復(fù),只不過so的差分包,是直接使用的bsdiff算法生成的。

騰訊 QZone Muitidex方案

Multidex方案是 基于ClassLoader的 純java實現(xiàn)重啟生效的熱修復(fù)方案.

原理

Apk打包的時候可能生成多個classes.dex文件。JVM中 類加載器ClassLoader,在程序運行使用到某一個Class的時候,是按照順序查找的方式進(jìn)行的。一旦找到,就會緩存起來,下一次loadClass就不會去查找,而是直接使用緩存中的(所以Muitldex方案必須重啟app). 而,當(dāng)我們把補(bǔ)丁dex文件放到 順序查找的最前面,那么類加載器 查找到它之后,就會直接使用。原來的同樣的類便處于后方,不會再生效。由此,使用補(bǔ)丁Class完全替換了 原class.

至于更深入的原理,上一篇 Android熱更新修復(fù)核心原理 已經(jīng)給出了詳細(xì)講解。在此就不贅述。

方案對比


結(jié)語

推薦一篇好文:https://www.cnblogs.com/popfisher/p/8543973.html 對于熱修復(fù)做了非常詳盡的講述。
本人能力有限,除Multidex熱修復(fù)方案之外,其他三種只是有所耳聞。接下來將會對Muitldex方案的一些兼容問題做出詳細(xì)解讀。盡情期待。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容