安卓热修复-multidex的使用
2017-02-20 本文已影响72人
czins
当程序出现一些小Bug需要紧急修复的时候,又不希望用户感知,可以使用热修复的方式快速修复Bug。
原理:实现多分包,将修复Bug的dex包放到加载路径的最前面。
在eclipse的安卓编译使用的ant构建配置文件,文件位置:
android-sdk\tools\ant\build.xml
在eclipse中实现多分包的方式,可以使用自定义ant构建的配置文件。
本文的重点使用android-studio实现热修复:
直接上代码:
public class DexPatcher {
public static final String PATCH_DEX_PATH = "patch_dex";
public static final String PATCH_DEX = "patch.dex";
public static final String DEX_FILE_EXTENSION = ".dex";
private static final String DEX_ELEMENTS = "dexElements";
private static final String PATH_LIST = "pathList";
private static final String PATH_LIST_CLASS = "dalvik.system.DexPathList";
private static final String OPTIMIZED_PATH = "optimized";
private static final String BASE_DEX_CLASSLOADER_CLASS = "dalvik.system.BaseDexClassLoader";
public static void patch(Context context) {
try {
File patchDexDir = context.getDir(PATCH_DEX_PATH, Context.MODE_PRIVATE);
File optimizedFile = new File(patchDexDir, OPTIMIZED_PATH);
if (!optimizedFile.exists()) {
optimizedFile.mkdirs();
}
for (File file : patchDexDir.listFiles()) {
if (file.getName().endsWith(DEX_FILE_EXTENSION)) {
DexClassLoader dexClassLoader = new DexClassLoader(file.getAbsolutePath(), optimizedFile.getAbsolutePath(), null, context.getClassLoader());
Object primaryElements = getDexElements(context.getClassLoader());
Object dexElements = getDexElements(dexClassLoader);
Object combineElements = combineDexElements(primaryElements, dexElements);
setFieldValue(getPathList(context.getClassLoader()), DEX_ELEMENTS, combineElements);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static Object combineDexElements(Object primaryElements, Object dexElements) {
Class<?> cls = primaryElements.getClass().getComponentType();
int ll = Array.getLength(dexElements);
int tl = ll + Array.getLength(primaryElements);
Object combineElements = Array.newInstance(cls, tl);
for (int i = 0; i < tl; i++) {
if (i < ll) {
Array.set(combineElements, i, Array.get(dexElements, i));
} else {
Array.set(combineElements, i, Array.get(primaryElements, i - ll));
}
}
return combineElements;
}
private static Object getDexElements(Object clsLoader) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
return getFieldValue(getPathList(clsLoader), Class.forName(PATH_LIST_CLASS), DEX_ELEMENTS);
}
private static Object getPathList(Object clsLoader) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
return getFieldValue(clsLoader, Class.forName(BASE_DEX_CLASSLOADER_CLASS), PATH_LIST);
}
private static Object getFieldValue(Object object, Class<?> cls, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field field = cls.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object);
}
private static void setFieldValue(Object object, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
}
}