① 無需從新發布版本,省時省力java
② 用戶無感修復,也無需下載最新應用,代價小android
③ 修復成功率搞,把損失降到最低git
① 代碼修復github
② 資源修復數組
③ SO庫修復bash
① 在build.gradle defaultConfig裏添加服務器
//開啓分包
multiDexEnabled true
//設置分包配置
multiDexKeepFile file('multidex-config.txt')
複製代碼
② 在build.gradle android裏添加網絡
dexOptions {
javaMaxHeapSize "4g"
preDexLibraries = false
additionalParameters = [//配置multiDex參數
'--multi-dex',
//每一個包內方法數上限
'--set-max-idx-number=50000',
//打包到主 classes.dex的文件列表
'--minimal-main-dex'
]
}
複製代碼
③ 添加multidex 支持依賴app
implementation 'com.android.support:multidex:1.0.3'
複製代碼
④ 引入 moduleide
implementation project(':HaoLinHotFixLibrary')
複製代碼
⑤ 建立 multidex-config.txt 文件 app目錄下 作一些主要類的引用
com/haolin/hotfix/MainActivity.class
com/haolin/hotfix/base/BaseActivity.class
com/haolin/hotfix/base/BaseApplication.class
複製代碼
基礎用法 Application須要繼承MultiDexApplication
BaseApplication extends MultiDexApplication
複製代碼
//修復包 現不作網絡下載 從手機裏拿
File sourceFile = new File
(Environment.getExternalStorageDirectory(), Constants.DEX_NAME);
//目標路徑 私有目錄
File targetFile = new File(getDir(Constants.DEX_DIR, Context.MODE_PRIVATE)
.getAbsolutePath() + File.separator + Constants.DEX_NAME);
if (targetFile.exists()){
targetFile.delete();
}
try {
FileUtils.copyFile(sourceFile, targetFile);
FixDexUtils.loadFixedDex(this);
} catch (Exception e) {
e.printStackTrace();
}
}
複製代碼
package com.haolin.hotfix.library;
import android.content.Context;
import com.haolin.hotfix.library.utils.ArrayUtils;
import com.haolin.hotfix.library.utils.Constants;
import com.haolin.hotfix.library.utils.ReflectUtils;
import java.io.File;
import java.util.HashSet;
import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;
/**
* 做者:haoLin_Lee on 2019/04/19 11:43
* 郵箱:Lhaolin0304@sina.com
* class: 加載熱修復文件
*/
public class FixDexUtils {
private static HashSet<File> loadeDex = new HashSet<>();
static {
//修復以前清空集合
loadeDex.clear();
}
public static void loadFixedDex(Context context) {
File fileDir = context.getDir(Constants.DEX_DIR, Context.MODE_PRIVATE);
//循環私有目錄的全部文件
File[] listFiles = fileDir.listFiles();
for (File file : listFiles) {
if (file.getName().endsWith(Constants.DEX_SUFFIX) &&
!"class.dex".equals(file.getName())) {
loadeDex.add(file);
}
}
//模擬類加載器
createDexClassLoader(context, fileDir);
}
//建立加載補丁的DexClassLoad 類加載器
private static void createDexClassLoader(Context context, File fileDir) {
//建立解壓目錄
String optimizedDir = fileDir.getAbsolutePath() +
File.separator + "opt_dex";
//建立目錄
File fopt = new File(optimizedDir);
if (!fopt.exists()) {
//建立多級目錄
fopt.mkdirs();
}
for (File dex : loadeDex) {
//自有的類加載器
DexClassLoader classLoader = new DexClassLoader
(dex.getAbsolutePath(), optimizedDir, null, context.getClassLoader());
//每循環一次 修復一次(插裝)
hotFix(classLoader, context);
}
}
private static void hotFix(DexClassLoader classLoader, Context context) {
//獲取系統的pathClassLoader
PathClassLoader pathLoader = (PathClassLoader) context.getClassLoader();
try {
//獲取自有的dexElement數組
Object myElements = ReflectUtils.getDexElements(ReflectUtils.
getPathList(classLoader));
//獲取系統的dexElement數組
Object systemElements = ReflectUtils.getDexElements(ReflectUtils.
getPathList(pathLoader));
//合併而且生成新的dexElements數組
Object dexElements = ArrayUtils.combineArray(myElements, systemElements);
//獲取系統的pathList
Object systemPathList = ReflectUtils.getPathList(pathLoader);
//經過反射技術,將新的dexElements 數組賦值給系統的pathList
ReflectUtils.setField(systemPathList, systemPathList.getClass(), dexElements);
} catch (Exception e) {
e.printStackTrace();
}
}
}
複製代碼
將修復好的apk包利用解壓工具打開,裏面會有classes2.dex文件,與舊版本apk和該classes2.dex文件同時複製到手機裏在實際開發項目中應該將classes2.dex文件放在服務器,進行下載修復,我這只是方面demo主要了解下核心原理,主要就是插樁技術。
Tinker熱修復主要運用framework層技術,瞭解插樁原理,核心代碼就是反射技術實現
//獲取系統的pathClassLoader
PathClassLoader pathLoader = (PathClassLoader) context.getClassLoader();
try {
//獲取自有的dexElement數組
Object myElements = ReflectUtils.getDexElements(ReflectUtils.getPathList
(classLoader));
//獲取系統的dexElement數組
Object systemElements = ReflectUtils.getDexElements(ReflectUtils.
getPathList(pathLoader));
//合併而且生成新的dexElements數組
Object dexElements = ArrayUtils.combineArray(myElements, systemElements);
//獲取系統的pathList
Object systemPathList = ReflectUtils.getPathList(pathLoader);
//經過反射技術,將新的dexElements 數組賦值給系統的pathList
ReflectUtils.setField(systemPathList, systemPathList.getClass(), dexElements);
} catch (Exception e) {
e.printStackTrace();
}
複製代碼
謝謝你們的閱讀,想要了解更多,請關注我