用新增DEX的方法实现热修复

public class HotFix {
    public static final String FIX_DEX_PATH = "fix_dex";//fixDex存储的路径
    public static final String DEX_OPT_DIR = "optimize_dex";//dex的优化路径
    public static final String DEX_BASECLASSLOADER_CLASS_NAME = "dalvik.system.BaseDexClassLoader";
    public static final String DEX_PATHLIST_FIELD = "pathList";//BaseClassLoader中的pathList字段
    public static final String DEX_ELEMENTS_FIELD = "dexElements";//pathList中的dexElements字段
    public static final String DEX_FILE_E = "dex";//扩展名

    public void loadDex(Context context, File dexFile){
        if(context == null)return;
        File fixDir = context.getDir(FIX_DEX_PATH,Context.MODE_PRIVATE);
        mergeDex(context,fixDir,dexFile);

    }
    public void mergeDex(Context context,File fixDexFile,File dexFile){
        try {
            File optDir = new File(fixDexFile.getAbsolutePath(),DEX_OPT_DIR);
            if(!optDir.exists())optDir.mkdir();
            PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader();
            DexClassLoader dexClassLoader = new DexClassLoader(dexFile.getAbsolutePath(),optDir.getAbsolutePath(),null,pathClassLoader);
            Object appDexPathList = getDexPathListField(pathClassLoader);
            Object fixDexPathList = getDexPathListField(dexClassLoader);
            Object appDexElements = getDexElements(appDexPathList);
            Object fixDexElements = getDexElements(fixDexPathList);
            Object combineElements = combineArray(fixDexElements,appDexElements);
            setFiledValue(appDexPathList,appDexPathList.getClass(),DEX_ELEMENTS_FIELD,combineElements);
            Log.i("wanlijun","mergeDex:");
        }
        catch (Exception e){
            e.printStackTrace();
            Log.i("wanlijun","mergeDex:"+e.toString());
        }
    }

    public Object getDexPathListField(Object classLoader) throws ClassNotFoundException,NoSuchFieldException,IllegalAccessException{
        return getField(classLoader,Class.forName(DEX_BASECLASSLOADER_CLASS_NAME),DEX_PATHLIST_FIELD);
    }
    public Object getField(Object obj,Class clz,String fieldName)throws  NoSuchFieldException,IllegalAccessException{
        Field field = clz.getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.get(obj);
    }
    public Object getDexElements(Object pathList) throws NoSuchFieldException,IllegalAccessException{
        return getField(pathList,pathList.getClass(),DEX_ELEMENTS_FIELD);
    }
    private static Object combineArray(Object fixDexElements,Object appDexElements){
        Class localClass = fixDexElements.getClass().getComponentType();
        int i = Array.getLength(fixDexElements);
        int j = i + Array.getLength(appDexElements);
        Object result = Array.newInstance(localClass,j);
        for(int k=0;k claz, String filed, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field = claz.getDeclaredField(filed);
        field.setAccessible(true);
        field.set(obj, value);
    }

    /**
     * 复制SD卡中的补丁文件到dex目录
     */
    public static void copyDexFileToAppAndFix(Context context, String dexFileName, boolean copyAndFix) {
        File path = new File(Environment.getExternalStorageDirectory(), dexFileName);
        if (!path.exists()) {
            Toast.makeText(context, "没有找到补丁文件", Toast.LENGTH_SHORT).show();
            return;
        }
        if (!path.getAbsolutePath().endsWith(DEX_FILE_E)){
            Toast.makeText(context, "补丁文件格式不正确", Toast.LENGTH_SHORT).show();
            return;
        }
        File dexFilePath = context.getDir(FIX_DEX_PATH, Context.MODE_PRIVATE);
        File dexFile = new File(dexFilePath, dexFileName);
        if (dexFile.exists()) {
            dexFile.delete();
        }
        //copy
        InputStream is = null;
        FileOutputStream os = null;
        try {
            is = new FileInputStream(path);
            os = new FileOutputStream(dexFile);
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            if (dexFile.exists() && copyAndFix) {
                //复制成功,进行修复
                Log.i("wanlijun","copyDexFileToAppAndFix:");
                new HotFix().loadDex(context, dexFile);
            }
            path.delete();//删除sdcard中的补丁文件,或者你可以直接下载到app的路径中
            is.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

你可能感兴趣的:(android)