文章目錄
- 1 熱修複背景
- 2 代碼修複
-
- 2.1 底層替換方案
- 2.2 類加載方案
- 3 插樁原理
- 4 Dex分包
-
- 4.1 65536限制:
- 4.2 LinearAlloc限制
- 4.3 gradle配置
- 4.4 配置檔案multidex.keep
- 4.5 Application重寫attachiBaseContext
- 5 未來發展展望
1 熱修複背景
剛釋出的版本出現了嚴重的Bug,這就需要去解決Bug、測試打包重新釋出,這會耗費大量的人力和物力,代價比較大。
已經更正了此前釋出版本的Bug,如果下個版本是大版本,那麼兩個版本之間間隔時間會很長,這樣要等到下個大版本釋出再修複Bug,而之前版本的Bug會長期的影響使用者。
版本更新率不高,并且需要長時間來完成版本疊代,前版本的Bug就會一直影響不更新的使用者。
有一些小但是很重要的功能需要在短時間内完成版本疊代,比如節日活動。
正常開發流程與熱修複開發流程對比:

熱修複架構分類與對比:
分類:
阿裡系:AndFix、Dexposed、阿裡百川、Sophix
騰訊系:微信的Tinker、QQ空間的超級更新檔、手Q的QFix
知名公司:美團的Robust、餓了麼的Amigo、美麗說蘑菇街的Aceso
其它:RocooFix、Nuwa、AnoleFix
2 代碼修複
2.1 底層替換方案
在已加載的類中直接替換原有方法,是在原有類的基礎上進行修改,無法實作對原有類進行方法和字段的增減,這樣會破壞原有類的結構。
最大問題是不穩定性,直接修改虛拟機方法實體的具體字段來實作的。Android是開源的,不同的手機廠商開源對代碼進行修改,是以像Andfix就會出現在部分機型上的熱修複失效的現象。
修改ArtMethod
Sophix:全部替換底層的,
2.2 類加載方案
APP重新啟動後,讓ClassLoader去加載新的類。
熱修複優勢:
無需重新釋出新版本,省時省力。
使用者無感覺修複,也無需下載下傳最新應用,代價小。
修複成功率高,把損失降到最低。
ClassLoader classLoader = MainActivity.class.getClassLoader();
while (classLoader != null){
Log.i("MainActivity123",classLoader.toString());
classLoader = classLoader.getParent();
}
輸出:
dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.hongx.fixtest-
iWkvfdNvIRqzj51aylqjJg==/base.apk"],nativeLibraryDirectories=
[/data/app/com.hongx.fixtest-iWkvfdNvIRqzj51aylqjJg==/lib/x86, /system/lib]]]
和
[email protected]
先看看DexClassLoader和PathClassLoader的差別
參考:https://www.jianshu.com/p/7e30ba5cb9ea
1、DexClassLoader可以加載jar/apk/dex,可以從SD卡中加載未安裝的apk
2、PathClassLoader隻能加載系統中已經安裝過的apk
再看看ClassLoader的loadClass方法
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
return c;
}
protected final Class<?> findLoadedClass(String name) {
ClassLoader loader;
if (this == BootClassLoader.getInstance())
loader = null;
else
loader = this;
return VMClassLoader.findLoadedClass(loader, name);
}
findLoadedClass可以看出ClassLoader先去加載的是已加載過的,如果未加載過(c == null)時候才會走,則去所有需要冷啟動重新啟動app後才能生效。
//pathc.dex 放在私有目錄下
3 插樁原理
http://androidxref.com/8.1.0_r33/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
4 Dex分包
4.1 65536限制:
com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536
應用的方法數超過了最大數65536個。因為DVM Bytecode的限制,DVM指令集的方法調用指令invoke-kind索引為16bits,最多能引用65535個方法
4.2 LinearAlloc限制
INSTALL_FAILED_DEXOPT
在安裝應用時可能會提示INSTALL_FAILED_DEXOPT,産生的原因就是LinearAlloc限制,DVM中的LinearAlloc是一個固定的緩存區,當方法數超出緩存區的大小時會報錯。
為了解決65536限制和LinearAlloc限制,進而産生了Dex分包機制。
Dex分包方案主要做的時在打包時将應用代碼分成多個Dex,将應用啟動時必須用到的類和這些類的直接引用類放到主Dex中,其它代碼放到次Dex中。當應用啟動時先加載主Dex,等到應用啟動後再動态地加載次Dex,進而緩解了主Dex的65536限制和LinearAlloc限制
4.3 gradle配置
android {
compileSdkVersion 28
defaultConfig {
...
// 開啟分包
multiDexEnabled true
// 設定分包配置檔案
multiDexKeepFile file('multidex.keep')
}
...
dexOptions {
javaMaxHeapSize "4g"
preDexLibraries = false
additionalParameters = [ // 配置multidex參數
'--multi-dex', // 多dex分包
'--set-max-idx-number=50000', // 每個包内方法數上限
'--main-dex-list=' + '/multidex-config.txt', // 打包到主classes.dex的檔案清單
'--minimal-main-dex'
]
}
}
dependencies {
...
implementation 'com.android.support:multidex:1.0.3'
}
4.4 配置檔案multidex.keep
com/hongx/fixtest/BaseActivity.class
com/hongx/fixtest/BaseApplication.class
com/hongx/fixtest/MainActivity.class
4.5 Application重寫attachiBaseContext
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
Make Project 後檢視app/build/outputs/apk/debug/app-debug.apk 多出一個classes.dex裡面包含了MainActivity、BaseApplication、BaseActivity
5 未來發展展望
熱修複=“黑科技”?
熱修複不同于國内APP程序保活這種“黑科技”,讓app常駐背景,既耗電又占用記憶體,浪費很多手機資源。還有APP的推送服務,無節操地對使用者進行資訊轟炸。還有更無節操的全家桶app。導緻Android手機卡頓不堪,這些所謂的“黑科技”都是為了手機廠商的利益而損害使用者的體驗
而熱修複是能夠讓開發者和使用者雙赢的。不僅廠商能快速疊代更新app,使功能盡快上線,而且熱更新過程使用者無感覺,節省大量更新時間,提高使用者體驗。更重要的能保證app的功能穩定,bug能及時修複。
IOS封殺了熱修複功能,Android的熱修複是否也有可能被幹掉呢?
熱修複未來是十分樂觀的,不僅不會受到封殺,反而會有很大發展空間