NuWa熱修復(fù)原理基礎(chǔ)詳細(xì)解說——初識(shí),熱修復(fù)

前言:不得不跟正在看這篇文章的寶寶們說一句,作為菜鳥的我,看了很多大神的文章,對(duì)于熱修復(fù)也是初識(shí),有什么寫的不對(duì)的地方,還望大家指導(dǎo),此篇文章也作為自己的筆記,便于自己總結(jié)。

做這個(gè)筆記之前我看了一下幾篇文章,記下了好的解說圖,和好的觀點(diǎn),附上鏈接,表示感謝:

熱修復(fù),沒你想的那么難

熱補(bǔ)丁動(dòng)態(tài)修復(fù)框架小結(jié)

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

一、什么是熱修復(fù):

相信很多人第一次聽說熱修復(fù)的時(shí)候也是一臉茫然,那么我就用自己的話來跟大家講解一下。

當(dāng)一個(gè)已經(jīng)上線的APP突然發(fā)現(xiàn)一個(gè)嚴(yán)重的bug的時(shí)候,除了重新發(fā)版,讓用戶重新下載覆蓋安裝以外,還有沒有別的方法來解決呢?如果可以有一個(gè)動(dòng)態(tài)修復(fù)的方法就好了,那就是熱補(bǔ)丁動(dòng)態(tài)修復(fù)技術(shù),也就是我們說的熱修復(fù)。向用戶下發(fā)Patch,在用戶無感知的情況下,修復(fù)bug問題。這里用到的是android dex分包方案,后面會(huì)具體解釋如何實(shí)現(xiàn)的。

這里我們先說一下Android的插件化,Android插件化分為三大塊:熱部署,動(dòng)態(tài)加載資源,四大組件動(dòng)態(tài)加載。

分別舉例:

熱部署 ------------------------------熱修復(fù)

動(dòng)態(tài)加載資源-------------------動(dòng)態(tài)換膚

四大組件動(dòng)態(tài)加載----------模塊化開發(fā)

二、基于的原理——心急吃不了熱豆腐

首先,就要從Android的ClassLoader體系來說起:

ClassLoader顧名思義,就是在Java中加載一個(gè)類需要用到的。

在Android中有三大ClassLoader,分別為URLClassLoader,PathClassLoader,DexClassLoader.其中:URLClassLoader:只能用于加載jar文件,但是由于 dalvik 不能直接識(shí)別jar,所以在 Android 中無法使用這個(gè)加載器。

這里我們重點(diǎn)來說后面這兩個(gè)加載類:

PathClassLoader:前面說過熱修復(fù)是用到了dex分包方案(后面會(huì)說什么是dex文件),那么這個(gè)PathClassLoader就是用來去找dex文件的類。當(dāng)apk安裝后,PathClassLoader會(huì)去讀取/data/dalvik-cache/dex文件,例如我們安裝了一個(gè)包名為com.meijia.xxx的apk,那么安裝后就會(huì)在/data/dalvik-cache目錄下,生成一個(gè)data@app@com.meijia.xxx-1.apk@classes.dex的ODEX文件(后面會(huì)講解什么是ODEX文件),而PathClassLoader找的就是這個(gè)ODEX文件,如果說找不到這個(gè)文件,就證明apk還沒有安裝,報(bào)錯(cuò)就是ClassNotFoundException。

DexClassLoader:顧名思義,DexClassLoader就是用來加載dex的加載類,就是從.jar和.apk類型的文件內(nèi)部加載classes.dex文件??梢杂脕韴?zhí)行非安裝的程序代碼,也就指的是插件中的apk代碼。

它的構(gòu)造函數(shù)包含四個(gè)參數(shù):

1.dexPath:就是目標(biāo)類所在的APK或者jar文件的全路徑。

2.dexOutputDir:就是dex在APK或者jar文件中解壓后的dex文件存放路徑

3.libPath:指目標(biāo)類中所使用的C/C++庫存放的路徑

4.classLoad:是指該裝載器的父裝載器,一般為當(dāng)前執(zhí)行類的裝載器

到這里,我們就知道了1.PathClassLoader在這里是作為類加載器,2.DexClassLoader是用來加載classes.dex文件的。繼續(xù)。

PathClassLoader和DexClassLoader都是繼承BaseDexClassLoader這個(gè)類,看源碼如圖:

這里我們通過注釋可以看到1.其中DexPathList pathList就是多dex的結(jié)構(gòu)列表。2.其中pathList里面包含一個(gè)Element [ ] dexElements數(shù)組就是dex列表,每一個(gè)element就是一個(gè)dex文件。

那好,當(dāng)PathClassLoader加載類加載的時(shí)候會(huì)遍歷Element [ ] dexElements,如果找到對(duì)應(yīng)類則加載,找不到,就會(huì)繼續(xù)從下一個(gè)dex文件中查找,那么我們就明白了,試想,如果我們將補(bǔ)丁插件dex文件插入到Element [ ] dexElements的最前面,理論上不同dex中有相同的類名存在時(shí),會(huì)優(yōu)先加載第一個(gè)類,找到了就返回,不會(huì)再繼續(xù)查找下一個(gè)dex文件了,這就是我們說的基于dex分包的熱修復(fù)的原理。

到這里,我們就知道了熱修復(fù)就是在ClassLoader(類加載器)中插入一個(gè)dex文件。

那么什么是dex文件?什么又是ODEX文件呢?它們和class是什么關(guān)系?為什么Android只能識(shí)別dex文件,不能直接識(shí)別class文件呢?

先看一下class的結(jié)構(gòu),如圖(摘自鄧凡平老師博客)

我們可以看到一個(gè)class文件中包含很多版本信息,常量等信息。

dex文件就是將整個(gè)Android項(xiàng)目中的所有class文件合并成一個(gè)或者幾個(gè)dex文件,當(dāng)兩個(gè)或幾個(gè)class文件中有重復(fù)的字符串,那么dex就只存一份就可以了,換種說法就是dex是對(duì)class的壓縮。

所以,在Android dalvik虛擬機(jī)中是無法識(shí)別一個(gè)class文件的,因?yàn)樗麄兊慕Y(jié)構(gòu)不同,一個(gè)dex文件的結(jié)構(gòu)如圖

然后什么是ODEX呢,Android dalvik虛擬機(jī)也不是直接識(shí)別dex文件的,當(dāng)APK被安裝的時(shí)候,虛擬機(jī)會(huì)實(shí)現(xiàn)一次優(yōu)化,就是將dex文件轉(zhuǎn)換成odex文件,這次轉(zhuǎn)換是為了對(duì)不同的手機(jī)硬件做對(duì)應(yīng)的優(yōu)化,而class轉(zhuǎn)換成dex,是針對(duì)不同平臺(tái)的優(yōu)化,兩者意義上是不同的。

然而,就在這優(yōu)化過程中,在虛擬機(jī)啟動(dòng)的時(shí)候會(huì)有很多參數(shù),其中有一項(xiàng)叫做verify的選項(xiàng),當(dāng)這個(gè)選項(xiàng)被開啟之后,就會(huì)實(shí)行一個(gè)類的校驗(yàn),具體校驗(yàn)內(nèi)容就是,如果static方法、private方法、構(gòu)造函數(shù)等,其中的直接引用(第一層關(guān)系)到的類都在同一個(gè)dex文件中,那么該類就會(huì)被打上CLASS_ISPREVERIFIED標(biāo)志

校驗(yàn)過程如下:

一旦這個(gè)類CLASS_ISPREVERIFIED標(biāo)志被打上,那么我們也就不能從別的dex文件中替換這個(gè)類了,那么我們之前說的在Element [ ]中插入dex的方法就無用了,知道了原因,辦法就好想了。

不就是如果這個(gè)dex中的類沒有引用其他dex文件中的類,就會(huì)被打上CLASS_ISPREVERIFIED
標(biāo)志么?那么我們就讓他引用就好了。

三、如何阻止CLASS_ISPREVERIFIED標(biāo)記

到這里,試想,如果我們?cè)谒械念惖臉?gòu)造函數(shù)中,引用一個(gè)其他dex文件中的類的方法的話,是不是就可以防止被打上CLASS_ISPREVERIFIED標(biāo)記了。

其中,hack.dex文件是要在最先加載進(jìn)來的,不然如果當(dāng)應(yīng)用啟動(dòng)的時(shí)候,hack.dex沒有先加載進(jìn)來的話,這些引用它的類,就會(huì)報(bào)錯(cuò),找不到hack.dex中的AntilazyLoad這個(gè)類。

那么問題來了?

如何去修改一個(gè)類?又如何在應(yīng)用啟動(dòng)時(shí)最先加載hack.dex這個(gè)文件呢?

不同的修復(fù)方案的解決辦法是不同的,這里就不一一介紹了,因?yàn)槿绻f的話,要說的東西太多,我覺得自己還說不好,就搜羅網(wǎng)絡(luò)上熱門的方案大致以下幾種開源框架。

https://github.com/dodola/HotFix?

https://github.com/jasonross/Nuwa?

https://github.com/bunnyblue/DroidFix

其中鴻洋大神的文章是用HotFix解說的:HotFix解說

濤哥的文章是用Nuwa解說的:Nuwa解說

總結(jié):在學(xué)習(xí)一項(xiàng)新知識(shí)的時(shí)候,需要很大的耐心,對(duì)于基礎(chǔ)不是很好的同學(xué),會(huì)在學(xué)習(xí)的過程中發(fā)現(xiàn)越來越多自己不懂的地方,這時(shí)候請(qǐng)不要煩躁,請(qǐng)靜下心來,反復(fù)對(duì)敲,不懂的地方更是要耐心的去找資料去學(xué)習(xí),當(dāng)你明白了一項(xiàng)新知識(shí)以后,你會(huì)發(fā)現(xiàn),你學(xué)到的比你想象的還要多。以此共勉,加油~

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

相關(guān)閱讀更多精彩內(nèi)容

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