VirtualApk加载插件原理

         在VirtualApk官方文档https://github.com/didi/VirtualAPK/wiki/第三方技术文章中介绍了加载插件四大组件和资源的原理, 我想总结一下加载插件的原理并画了个流程图。

 

为了加深对VirtualApk的理解, 考虑问题:

1、插件中的类是被哪个classloader加载的? 答:跟Constants.COMBINE_CLASSLOADER参数有关。

2、插件能加载宿主的类是如何实现的? 答:将宿主的dexElements插入到插件DexClassLoader的dexElements前面。

3、插件之间能相互加载对方的类吗? 答:不能;

4、如果宿主和插件有相同的类, 到底加载的是哪一个?答:跟Constants.COMBINE_CLASSLOADER参数有关。

5、插件能加载其它插件吗? 答:不能;

6、各个插件的包名能相同吗? 答:不能;

7、如何加载插件中类? 答:详见PluginContext类, 在启动插件中activity时会替换上下文, 包括mResources、mBase、mApplication等字段,从而可以使用插件classloader加载其中的类。

8、Class.forName和new SomeClass()的区别是forName只加载当前类和静态成员, 而new对象则加载当前类、静态成员和成员变量类。

以VirtualApk里的demo为例,按照流程图的顺序依次讲解:

1、 下图是完整的加载插件逻辑, 只能在宿主app执行!

 

2、 下面看看loadPlugin函数做了什么。 每个apk文件最后都会生成一个LoadedPlugin实例,并缓存到mPlugins里。 注意:VirtualApk只能加载apk格式的插件,不能直接加载dex;各个插件的包名必须不同。 

 

3、下面看看create函数做了什么, 就是new个实例, 业务逻辑封装在构造函数里。

 

    public static LoadedPlugin create(PluginManager pluginManager, Context host, File apk) throws Exception {
        return new LoadedPlugin(pluginManager, host, apk);
    }


4、下面仔细分析LoadedPlugin构造函数。 缓存了宿主中PluginManager实例的引用和宿主上下文, 解析插件文件(注意必须是apk格式!)并加载资源文件和dex,解析插件里的AndroidManifest.xml并缓存activity、instrument、service、provider信息,注册静态广播, 加载资源文件原理见VirtualAPK 资源加载机制分析

 

 

5、 下面着重分析一下mClassLoader是怎么生成的。  使用DexClassLoader加载插件中的dex, 然后判断布尔值Constants.COMBINE_CLASSLODER,默认值是true即可以加载宿主中的类, 值是false是不能加载宿主中的类。

如何实现的呢? 关键是insertDex函数。

 

6、 调试insertDex函数, 可以看到将宿主dexElements插入到插件dexElements前面, 因为ClassLoader的双亲委派机制, 会按照dexElements数组顺序依次查找加载类。 如果在前面的dexElement里成功加载了一个类, 就不会尝试去后面的dexElement里查找了。

PS: 宿主和插件有同一个类(包名、类名相同), 如果COMBINE_CLASSLOADER为true则插件会加载宿主中的类;如果值为false则会加载插件中的类。

 

7、加载插件的最后一步是实例化插件中的Application对象,并调用其onCreate函数。 即plugin.invokeApplicaiton(); 注意用的是this.mClassLoader, 即当前LoadedPlugin的classloader。

 

8、 加载完插件后启动其中的activity, 如何使用插件中的classloader和资源呢?  首先在启动插件中activity时最终走到newActivity函数, 使用插件plugin.getClassLoader()加载对应类。

         在调用onCreate函数前判断是否为插件中的activity, 如果属于插件则替换mResources、mBase、mApplication, 即切换到插件上下文。 该插件activity访问资源、加载类时都使用插件LoadedPlugin的属性; 如果不属于插件即宿主activity, 则按照Android默认逻辑;

 

  好了, 以上就是VirtualApk加载插件的流程原理。 如有遗漏,欢迎补充。

PS: 在调试宿主apk时, 不要混淆插件代码, 否则找不到插件中的函数。 发布版本时,宿主、插件都要用release版本。 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值