文章目录
一、加载 Dex 文件到内存中
1、文件处理
2、加载修复包 Dex 到内存
3、获取系统类加载器
4、反射获取系统的 Element[] dexElements
5、反射获取自己加载的 修复包 Dex 的 Element[] dexElements
二、本博客涉及代码
三、 源码资源
一、加载 Dex 文件到内存中
在
【Android 热修复】热修复原理 ( 修复包 Dex 文件准备 | Dex 优化为 Odex | Dex 文件拷贝 | 源码资源 )
【Android 热修复】热修复原理 ( Dex 文件拷贝后续操作 | 外部存储空间权限申请 | 执行效果验证 | 源码资源 )
两篇博客中 , 准备了 Dex 修复包 , 并将修复包 /storage/emulated/0/update.dex
从外置存储空间拷贝到了应用内置存储空间
/data/user/0/kim.hsl.hotfix/app_odex/update.dex
目录中 ;
在 【Android 热修复】热修复原理 ( 类加载分析 | 分析 PathClassLoader 源码 | 分析 BaseDexClassLoader 源码 | 分析 PathDexList 源码 ) 博客中分析了类加载的原理 ;
现在开始将 Dex 文件加载到内存中 , 这里指的是要按照 Dex 文件的管理方式 , 加载到 BaseDexClassLoader 类的 DexPathList pathList 成员的 Element[] dexElements 成员数组中 ;
1、文件处理
修复包可能有多个, 如先后进行了多次修复 , 存在多个修复包 Dex 文件 , 这些 Dex 文件按照时间顺序进行放置 ;
之前已经将 SD 卡中的 /storage/emulated/0/update.dex 文件拷贝到了原应用内置存储空间 /data/user/0/kim.hsl.hotfix/app_odex/update.dex ;
获取 dex 文件所在的应用内置存储空间目录 : 获取 /data/user/0/kim.hsl.hotfix/app_odex/ 目录文件 , 调用如下方法 , 即可生成该文件 ;
应用的包名是 kim.hsl.hotfix , 调用上下文对象的 getDir 方法 , 会在名称前自动加上 " app_ " 前缀 ;
// /data/user/0/kim.hsl.hotfix/app_odex/ 目录文件 File filesDir = context.getDir("odex", Context.MODE_PRI);
获取所有 dex 修复包 : 修复包可能存在多个 , 获取该 /data/user/0/kim.hsl.hotfix/app_odex/ 目录下的所有文件 ;
// 获取 /data/user/0/kim.hsl.hotfix/app_odex/ 目录下的所有文件 File[] listFiles = filesDir.listFiles();
odex 缓存文件目录 : dex 文件需要优化为 odex 文件 , 期间需要一个缓存文件目录 , 这里任意设置一个应用内置存储空间目录即可 ;
// 缓存 odex 文件的目录 , 将 dex 优化为 odex 文件 String optimizedDir = filesDir.getAbsolutePath() + File.separator + "cache_odex";
文件过滤 : 系统打包都是 classes.dex , classes1.dex , classes2.dex 等文件 , 上传的更新包 update.dex 以 .dex 为结尾 , 以上面两个条件作为过滤的依据 , 以 " classes " 开头 , 或以 " .dex " 结尾 的文件就是我们需要加载的 dex 文件 ;
// 过滤文件, 系统打包都是 classes.dex , classes1.dex , classes2.dex 等文件 // 上传的更新包 update.dex 以 .dex 为结尾 // 以上面两个条件作为过滤的依据 for (File file : listFiles){ if (file.getAbsolutePath().startsWith("classes") || file.getAbsolutePath().endsWith(".dex")){ } }
2、加载修复包 Dex 到内存
将 /data/user/0/kim.hsl.hotfix/app_odex/ 目录中的文件加载到内存中 :
使用 DexClassLoader 将 /data/user/0/kim.hsl.hotfix/app_odex/ 目录中的 dex 文件加载到内存中 , 构造 DexClassLoader 类时 , 会自动将 dex 文件进行优化为 odex , 然后加载到上述 DexClassLoader 类的 DexPathList pathList 成员 的 Element[] dexElements 数组成员 中 ;
这个 DexClassLoader 是我们自己创建的类加载器 ;
// 将 dex 文件加载到内存中 // 该 DexClassLoader 是 BaseDexClassLoader 的子类 // BaseDexClassLoader 中有 DexPathList pathList 成员 // 构造该类时 , 会自动将 dex 文件进行优化为 odex , 然后加载到上述 DexPathList pathList 中 // // 参数一 : Dex 文件路径 // 参数二 : 缓存路径, 指的是缓存 Odex 文件的目录 // 参数三 : Dex 中的 lib 库路径, 可以设置 null // 参数四 : 上下文的 ClassLoader DexClassLoader dexClassLoader = new DexClassLoader( file.getAbsolutePath(), optimizedDir, null, context.getClassLoader());
3、获取系统类加载器
系统的类加载器是 PathClassLoader , 该 PathClassLoader 是用于加载查找 Android 应用所有 dex 文件的类加载器 , 最终需要将上面获取的 dexClassLoader 中的 DexPathList pathList 插入到 PathClassLoader 中的 DexPathList pathList 成员中 ;
// 该 PathClassLoader 是用于加载查找 Android 应用所有 dex 文件的类加载器 // 将上面获取的 dexClassLoader 中的 DexPathList pathList // 插入到 PathClassLoader 中的 DexPathList pathList 成员中 PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader();