安卓热修复-multidex的使用

当程序出现一些小Bug需要紧急修复的时候,又不希望用户感知,可以使用热修复的方式快速修复Bug。

原理:实现多分包,将修复Bug的dex包放到加载路径的最前面。

在eclipse的安卓编译使用的ant构建配置文件,文件位置:

android-sdk\tools\ant\build.xml

在eclipse中实现多分包的方式,可以使用自定义ant构建的配置文件。

本文的重点使用android-studio实现热修复:

android classloader浅析

android multidex的使用

直接上代码:

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);
    }
}

你可能感兴趣的:(安卓热修复-multidex的使用)