Android熱修復(fù)原理及應(yīng)用
為什么做這個分享色徘?
1 之前分享主題以代碼規(guī)范、業(yè)務(wù)重構(gòu)操禀、設(shè)計優(yōu)化相關(guān)介紹的比較多褂策,再分享此類主題可能重復(fù)比較多。
2 平時需求以業(yè)務(wù)需求為主,純技術(shù)的不算太多斤寂,而Android熱修復(fù)算是一個比較火的技術(shù)主題
3 Github上熱度榜上耿焊,目前月內(nèi)最火熱的Java開源框架就是 tinker
一 什么是熱修復(fù)
二 熱修復(fù)原理及兩種主要實(shí)現(xiàn)方式
三 Tinker簡介及一個示范案例
四 Tinker框架結(jié)構(gòu)及代碼流程分析
一 什么是熱修復(fù)
背景
當(dāng)一個App發(fā)布之后,突然發(fā)現(xiàn)了一個嚴(yán)重bug需要進(jìn)行緊急修復(fù)遍搞,這時候公司各方就會忙得焦頭爛額:重新打包App罗侯、測試、向各個應(yīng)用市場和渠道換包溪猿、提示用戶升級钩杰、用戶下載、覆蓋安裝诊县。有時候僅僅是為了修改了一行代碼讲弄,也要付出巨大的成本進(jìn)行換包和重新發(fā)布。
這時候就提出一個問題:有沒有辦法以補(bǔ)丁的方式動態(tài)修復(fù)緊急Bug依痊,不再需要重新發(fā)布App避除,不再需要用戶重新下載,覆蓋安裝胸嘁?
能夠解決該問題的技術(shù)方案就稱為熱修復(fù)驹饺!
熱修復(fù)定義 用戶不用重新下載一個新的apk安裝,而是直接下載一個補(bǔ)丁包,通過補(bǔ)丁來替換一些出現(xiàn)bug的類, 下載補(bǔ)丁的過程用戶一般是感覺不到的,表面上看是直接修復(fù)了bug.
二 熱修復(fù)原理及兩種主要實(shí)現(xiàn)方式
如何實(shí)現(xiàn)這個技術(shù)方案 有以兩個流派
Native流派,代表有阿里的Dexposed缴渊、AndFix與騰訊的內(nèi)部方案KKFix赏壹;
Java流派, 代表有Qzone的超級補(bǔ)丁、大眾點(diǎn)評的Nuwa衔沼、百度金融的RocooFix, 餓了么的Amigo以及美團(tuán)的Robust
其中以下幾個框架已經(jīng)開源
Dexposed https://github.com/alibaba/dexposed
AndFix https://github.com/alibaba/AndFix
Nuwa https://github.com/jasonross/Nuwa
RocooFix https://github.com/dodola/RocooFix
Amigo https://github.com/eleme/Amigo
二 熱修復(fù)原理及幾種實(shí)現(xiàn)方式
這兩種方式代表著什么 具體原理是怎樣的 這得從Android打包說起
Android應(yīng)用所使用的編程語言是Java語言蝌借,編譯時通過JDK將Java源程序轉(zhuǎn)換成標(biāo)準(zhǔn)的Java字節(jié)碼文件(.class文件),再通過工具軟件DX把所有的字節(jié)碼文件轉(zhuǎn)換轉(zhuǎn)成Android dex文件(.dex),最后使用Android打包工具(aapt)將dex文件指蚁、資源文件以及AndroidManifext.xml(二進(jìn)制格式)組合成一個應(yīng)用程序包(.apk),應(yīng)用程序包發(fā)布到手機(jī)上就可以運(yùn)行了菩佑。
其中Dex文件的生成方式如下
Java編譯器創(chuàng)建JVM字節(jié)碼后,Dalvik的dx編譯器刪除.class文件凝化,重新把它們編譯成Dalvik字節(jié)碼稍坯,然后把它們寫進(jìn)一個.dex文件中。這個過程包括翻譯搓劫、重構(gòu)瞧哟、解釋程序的基本元素(常量池、類定義枪向、數(shù)據(jù)段)
常量池描述了所有的常量勤揩,包括引用、方法名秘蛔、數(shù)值常量等
類定義包括訪問標(biāo)志陨亡、類名等基本信息
數(shù)據(jù)段包含各種被VM執(zhí)行的函數(shù)代碼以及類和函數(shù)的相關(guān)信息(例如Dalvik虛擬機(jī)所需要的寄存器數(shù)據(jù)傍衡、局部變量表、操作數(shù)堆棧大懈喝洹)蛙埂,還有實(shí)例變量
Dex文件頭主要包括校驗及其它結(jié)構(gòu)的偏移地址和長度信息 文件頭結(jié)構(gòu)表如下 整個dex文件結(jié)構(gòu)還是挺復(fù)雜的
說完了整個打包流程 那兩個流派到底是什么?先說結(jié)論
1 Native流派核心是替換函數(shù),將Java方法的屬性設(shè)為native轉(zhuǎn)到JNI層處理,在JNI中又把方法指針指向了Java Hook,在hook中回調(diào)其他Java方法,Java->Native Hook->Java Fix,最終回調(diào)到任意的目標(biāo)方法.
2 Java流派核心是替換dex,有點(diǎn)像插件動態(tài)加載,原理是虛擬機(jī)在加載類--即從類名映射到class文件的過程時順序遍歷系統(tǒng)中dexElements組,dexElements持有應(yīng)用所有dex,一旦其中element能夠成功加載立即返回目標(biāo)類對應(yīng)的class.于是可以通過反射層層獲取各種成員各種變量,最后獲取到dexElements這個成員,將這個數(shù)組arrayCopy一份,順便在復(fù)制出來的數(shù)組第0個位置放上自己的dex,最后將復(fù)制體set回dexElements,實(shí)現(xiàn)了將class替換成自己的遮糖。
Java流派可能解釋比較抽象 因為里面涉及到Android的ClassLoader體系
ClassLoader體系
android中加載類一般使用的是PathClassLoader和DexClassLoader
1 PathClassLoader? //Android是使用這個類作為其系統(tǒng)類和應(yīng)用類的加載器绣的。并且對于這個類,只能去加載已經(jīng)安裝到Android系統(tǒng)中的apk文件
2 DexClassLoader? //該類可以用來從.jar和.apk類型的文件內(nèi)部加載classes.dex文件止吁,可以用來執(zhí)行非安裝的程序代碼
這兩個類都繼承自BaseDexClassLoader被辑。
加載類簡單來說就是給個classname燎悍,然后去findClass敬惦,細(xì)節(jié)可以參考BaseDexClassLoader中代碼
BaseDexClassLoader中代碼