android热修复制作的实例讲解(代码教程)
程序员文章站
2022-07-05 22:46:47
类的加载机制
需要注意的地方
1.每次生成之后一定要测试; 2.尽量的不要分包,不要分多个dex 3.混淆的时候,设计到NDK AndFix.java 不要混淆 4.生成包...
类的加载机制
需要注意的地方
1.每次生成之后一定要测试; 2.尽量的不要分包,不要分多个dex 3.混淆的时候,设计到NDK AndFix.java 不要混淆 4.生成包之后一般会加固什么的,这个时候生成的差分包,一定要在之前去生成。 5.既然是去修复方法,第一个不能增加成员变量,不能增加方法
public class FixDexManager { private Context mContext; private File mDexFile; private static final String TAG = FixDexManager.class.getSimpleName(); private Object applicationDexElements; public FixDexManager(Context context) { this.mContext = context; //可以访问的dex目录 mDexFile = context.getDir("odex", Context.MODE_PRIVATE); } /** * 修复dex包 */ public void fixDex(String fixDexPath) throws Exception { //2.获取下载好的补丁 dexElement //2.1移动到系统能够访问的 dex目录下 File srcFile = new File(fixDexPath); if (!srcFile.exists()) { throw new FileNotFoundException(fixDexPath); } File destFile = new File(mDexFile, srcFile.getName()); if (destFile.exists()) { Log.d(TAG, "patch [" + fixDexPath + "] has be loaded."); return; } copyFile(srcFile, destFile); //2.2ClassLoader读取fileDex路径 List fixDexFiles = new ArrayList<>(); fixDexFiles.add(destFile); } /** * 把dexElement注入到classLoader */ private void injectDexElement(ClassLoader classLoader, Object dexElements) throws Exception { //1.先获取pathList Field pathListField = BaseDexClassLoader.class.getDeclaredField("pathList"); //所有属性都可以获得 pathListField.setAccessible(true); Object pathList = pathListField.get(classLoader); //2.获得pathList中的dexElements Field dexElementsFiled = pathList.getClass().getDeclaredField("dexElements"); dexElementsFiled.setAccessible(true); //注入 dexElementsFiled.set(dexElementsFiled.get(pathList), dexElements); } /** * 合并数组 */ private static Object combineArray(Object arrayLhs, Object arrayRhs) { Class localClass = arrayLhs.getClass().getComponentType();//获得数组对象 int i = Array.getLength(arrayLhs); int j = Array.getLength(arrayRhs); Object result = Array.newInstance(localClass, j); for (int k = 0; k < j; ++k) { if (k < i) { Array.set(result, k, Array.get(arrayLhs, k)); } else { Array.set(result, k, Array.get(arrayLhs, k - 1)); } } return result; } /** * 将路径复制到目标文件下 */ public static void copyFile(File src, File dest) throws IOException { FileChannel inChannel = null; FileChannel outChannel = null; try { if (!dest.exists()) { dest.createNewFile(); } inChannel = new FileInputStream(src).getChannel(); outChannel = new FileOutputStream(dest).getChannel(); inChannel.transferTo(0, inChannel.size(), outChannel); } finally { if (inChannel != null) { inChannel.close(); } if (outChannel != null) { outChannel.close(); } } } /** * 从classLoader中获取 * * @param classLoader */ private Object getDexElementsByClassLoader(ClassLoader classLoader) throws Exception { //1.先获取pathList Field pathListField = BaseDexClassLoader.class.getDeclaredField("pathList"); //所有属性都可以获得 pathListField.setAccessible(true); Object pathList = pathListField.get(classLoader); //2.获得pathList中的dexElements Field dexElementsFiled = pathList.getClass().getDeclaredField("dexElements"); dexElementsFiled.setAccessible(true); return dexElementsFiled.get(pathList); } /** * 加载全部的修复包 */ public void loadFixDex() throws Exception { File[] dexFiles = mDexFile.listFiles(); List fixDexFiles = new ArrayList<>(); for (File dexFile : dexFiles) { if (dexFile.getName().endsWith(".dex")) { fixDexFiles.add(dexFile); } } fixDexFiles(fixDexFiles); } /** * 修复dex */ private void fixDexFiles(List fixDexFiles) throws Exception { //1.先获取已运行的dexElement ClassLoader applicationClassLoader = mContext.getClassLoader(); Object dexElements = getDexElementsByClassLoader(applicationClassLoader); File optimizedDirectory = new File(mDexFile, "odex"); if (!optimizedDirectory.exists()) { optimizedDirectory.mkdir(); } //修复 for (File fixDexFile : fixDexFiles) { ClassLoader fixDexClassLoader = new BaseDexClassLoader( fixDexFile.getAbsolutePath(),//dex路径 必须要在应用目录下的dex文件中 optimizedDirectory,//解压路径 null,//.so文件的位置 applicationClassLoader//父classloader ); Object fixDexElement = getDexElementsByClassLoader(fixDexClassLoader); //3.把补丁的dexElement插到已经运行好的dexElements的最前面 //合并数组 applicationDexElements = combineArray(dexElements, fixDexElement); } //注入到原来的类中applicationClassLoader injectDexElement(applicationClassLoader, applicationDexElements); } }
上一篇: C语言程序设计学习笔记--指针
下一篇: 排序之二:希尔排序(C语言实现)