ClassLoader 加载 dex 文件
继承关系
BootClassLoader:
加载 Android Framework 层的 class 文件。PathClassLoader:
加载 dex 文件,包括 jar、zip、apk 中的 dex 文件。DexClassLoader:
加载 dex 文件,包括 jar、zip、apk 中的 dex 文件。
ClassLoader 加载 Class 的流程
双亲委托机制:
首先检测这个类是否已经被加载了,如果已经加载了,直接获取并返回。如果没有被加载,当 parent 不为 null 时,调用 parent 的 loadClass() 进行加载;当 parent 为 null 时,调用 findClass() 方法,依次递归,如果找到了或者加载了就返回,如果既没找到也加载不了,才自己去加载。
BootClassLoader#findClass() 是直接调用了 Class.classForName() 方法;
DexClassLoader#findClass() 是加载传入的 APK 文件中的所有 dexFile 到 dexElements 数组,然后再调用 Element#findClass() 查找 dexFile 中是否包含指定的 class。
执行插件中的方法
原理
1、创建插件的 DexClassLoader 类加载器,然后通过反射获取插件的 dexElements 值;
2、获取宿主的 PathClassLoader 类加载器,然后通过反射获取宿主的 dexElements 值;
3、合并宿主的 dexElements 与插件的 dexElements,生成新的 Element[];
4、最后通过反射将新的 Element[] 赋值给宿主的 dexElements。
核心代码
|
|
启动插件中的 Activity
关键难点——无法通过 AMS 检测
插件的 Activity 没有在宿主的清单文件中注册。
启动 Activity 流程
绕过 AMS 检测——hook
hook:
劫持,改变代码的正常执行流程。
1、在宿主中创建一个 ProxyActivity 继承自 Activity,并且在 manifest 中注册;
2、当启动插件的 Activity 时,在 AMS 检测前,找到一个 hook 点,然后通过 hook 将启动插件 Activity 的 Intent 替换成启动 ProxyActivity 的 Intent;
3、在 AMS 检测完后,找到一个 hook 点,然后通过 hook 将启动 ProxyActivity 的 Intent 替换成启动插件 Activity 的 Intent;
4、启动插件的 Activity。
核心代码
将启动插件 Activity 的 Intent 替换成启动 ProxyActivity 的 Intent
|
|
将启动 ProxyActivity 的 Intent 替换成启动插件 Activity 的 Intent
|
|
启动插件的 Activity
|
|
让插件中的 Activity 加载插件中的资源
前期铺垫
1、加载 res 中的资源是通过 Resources,但是最后也是调用 AssetManager,只是会先通过 id 查找。AssetManager 可以加载未编译过的资源。
|
|
2、启动 Activity 时会调用 ActivityThread#performLaunchActivity(),此时建立了 Resources、AssetManager 和 Context 的绑定关系,并且指定了资源目录。
|
|
|
|
|
|
原理
- 创建 AssetManager,反射 addAssetPath 方法设置插件的资源目录;
- 创建 Resources,绑定该 AssetManager;
- 在 Application 中重写 getResources(),使用该 Resources;
- 在插件的 Activity 中重写 getResources(),使用 Application 中的 Resources。
核心代码
|
|
|
|
|
|
当宿主的 Activity 和插件的 Activity 都继承于 AppCompatActivity 时会报错
|
|
报错的原因
当宿主和插件都使用 AppCompatActivity 时,由于编译时会将资源建立映射关系,在宿主和插件中分别建立了 1 次映射关系,且这 2 次映射关系基本上不会相同。在宿主中 key1 -> value1,在插件中 key2 -> value2。
但是 AppCompatDelegateImpl 类只会在宿主中被加载一次,也就是宿主和插件都使用 key1 查找资源。
解决办法
让插件使用自己的 Resource。
|
|