1、做一个伪Activity壳,通过代理分发生命周期,灵活性较差,代表有DroidPlugin的that框架。
2、通过hook各种framework层实现对坑位的替换,如Instrumentation,H等;hook比较多,兼容性需要适配机型,代表有VirtualAPK。
3、只hook一个classloader,hook一点,坑位占用,比较稳定,代表有RePlugin。
4、无任何hook,通过代理分发技术,分发生命周期,代表有Phantom。
首先插件化在设计分为两种:插件资源与host资源共享,插件资源与host资源独立,下面简单的说一下两个的区别与优缺点。
这个好处是插件可以访问host资源,节约空间。缺点是资源处理比较麻烦,由于插件资源往往容易与host重复,这就容易造成冲突,冲突分两种:资源文件冲突和class文件冲突,资源冲突就是host的资源ID与插件的一样,这样插件解析资源就会出错。class文件冲突是插件的class与host的class类名一样,插件一旦加载host的类,两个类又不同就容易发生错误。在合并资源的时候,需要反射把插件的Resource加入host中,由于机型存在兼容问题(像小米Resource就做MiuiResource),这个需要进行机型适配。在这个冲突问题处理上,可以使用gradle编写插件去除相同的类,同名资源,往往要对比插件与host资源较为复杂。
这个好处是插件资源与host资源不会相互影响,缺点是插件不能访问host的资源,冗余比较多。这是由于插件不能访问host,所有东西都由插件自身解决。优点明显,无需对资源进行特别处理,resource是插件独有,不会跟host冲突。同样插件的dex与host中的dex也是独立,只是共用一个parent,pathClassloader是host,dexClassloader是插件,他们相互对立不能访问,关系如下:
parent classloader
/ \
pathClassloader | dexClassloader
SPlugin参考360的replugin,hook应用中的pathclassloader(application.getBaseContext()),并替换为自己的,实现了对从app的dex中loader的calss进行拦截。SPlugin的插件的使用了资源隔离的dexclassloader加载,与应用的pathclassloader他们的父类,构成了一个三角形(如上关系)。so库在解释插件apk的时候,根据当前平台,复制对应平台so到主app私有文件夹中,在创建dexClassloader把对应的路径设置进去,避免jni调用失败。 插件的四大组件数据从androidmanifest解释获取;从androidmanifest获取组件的类名,内容权限等信息相对容易,但是intent-filter数据无法获取,我猜出于安全吧(隐试数据就是为了不让第三方应用轻易知道),这里由于apk是自己的,可以手动解析,这里用pull解析androidmanifest(SPlugin中自己手写的,用了类似树的结构),SPlugin解释了广播,为后面广播隐试注册做准备。
host | plugin
hostLib | pluginLib
host为主app,依赖一个hostLib库,plugin为插件app,依赖的是pluginLib,hostLib库与hostLib库独立。
插件app可以独立启动(包含jni):插件app
host在assets已包含插件app:主app
github地址(觉得有帮助的给个star ?):SPlugin