一、什么是插件化

android 常用插件 android 插件化方案_插件化

有对比更形象,以组件化为对照

组件化开发:将一个app分成多个模块,每个模块都是一个组件(Module),开发的过程中我们可以让这些组件相互依赖或者单独调试部分组件等,但是最终发布的时候是将这些组件合并统一成一个apk

插件开发:将整个app拆分成很多模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk(组件化的每个模块是个lib),最终打包的时候将宿主apk和插件apk分开或者联合打包。

 

二、插件化的优势

1、解耦,宿主和插件分开编译:编译时只需要编译宿主app,插件app是在编译好后下发到宿主app里的。

2、并发开发:宿主app什么时候发布版本跟插件app什么时候开发完没有关系,宿主app只要开发完并且为插件app提供一个入口就可以了。

3、动态更新插件:插件app在开发完后下发到宿主app里,点击相应的入口就可以跳转到最新版的插件app了。

4、按需下载模块,降低app体积

5、解除单个dex方法65535的限制

 

三、插件化的基础

1、反射:运行时,可以通过名称,获悉其完整构造,并生成其对象实体、或对其fields设值、或唤起其methods,这样的机制称之为反射。关于反射,可以查看 -> Android 反射

2、Hook:安卓面向切面(AOP)编程的基础,可以让我们在不变更原有业务的前提下,插入额外的逻辑.

Hook 的选择点:尽量静态变量和单例,因为一旦创建对象,它们不容易变化,非常容易定位。

Hook 过程:

•寻找 Hook 点,原则是尽量静态变量或者单例对象,尽量 Hook public 的对象和方法。

•选择合适的代理方式,如果是接口可以用动态代理。

•偷梁换柱——用代理对象替换原始对象。

3、类加载机制:

几个重要加载器:BootClassLoaderPathClassLoaderDexClassLoader

android 常用插件 android 插件化方案_插件化_02

DexPathList内部定义了dexElements,专门记录已加载的dex

 

四、几种插件化框架对比

 

Small

VirtualAPK

RePlugin

Atlas

支持四大组件

只支持Activity

全支持

全支持

全支持

组件无需在宿主manifest中预注册

无需

无需

 

无需

 

需要

 

插件可以依赖宿主

可以

可以

轻度依赖

可以

支持PendingIntent

支持

支持

支持

--

兼容性适配

--

接入难度

 

 

 

五、App插件化原理

android 常用插件 android 插件化方案_android 常用插件_03

android 常用插件 android 插件化方案_virtualapk_04

 

对于宿主工程来说,在加载插件工程后,将插件dex插入到宿主工程的dexElements集合后面即可,在之后的运行中就可以按需加载插件中的class。需要注意的是,插件中的类不可以和宿主重复 。

android 常用插件 android 插件化方案_插件化_05

1、Activity

跟进startActivity的调用流程,会发现其最终会进入Instrumentation的execStartActivity方法,然后再通过ActivityManagerProxy与AMS进行交互。

android 常用插件 android 插件化方案_加载_06

Hook AMS:基于动态代理技术实现ActivityManagerProxy,以实现拦截ActivityManagerService的方法调用,然后利用反射将ActivityManagerNative实例替换掉ActivityManagerNative的gDefault成员。

android 常用插件 android 插件化方案_加载_07

Hook Instrumentation:扩展Instrumentation以实现对Activity启动过程的控制,然后使用反射将扩展Instrumentation实例替换ActivityThread对象原来的Instrumentation对象。

android 常用插件 android 插件化方案_加载_08

1) 替换

绕过Android对启动Activity的限制。

提前在主APP中占有坑Activity必须先在AndroidManifest注册,否则不能被startActivity。具体实现为利用hook的VAInstrumentation拦截Instrumentation的execStartActivity方法,并在该方法内将待启动的插件Activity名称改 为StubActivity。

2) 还原

绕过系统对插件Activity的合法校验后,将StubActivity名称改回原来的名称,以使得在Instrumentation.newActivity时实例并启动正确的目标Activity。

android 常用插件 android 插件化方案_加载_09

2、Service

动态代理AMS,拦截service相关的请求,将其中转给Service Runtime去处理,Service Runtime会接管系统的所有操作

插件Service的启动/关闭基于被Hook的AMS,VirtualAPK在拦截到start/bind/stop/unbind Service的调用后,会执行ActivityManagerProxy的invoke方法,之后控制流程和数据会转交给ServiceDelegate对象,之后ServiceDeletegate会判断待启动的Service是本地服务还是远程服务,如果是本地服务,VirtualAPK会反射调用Service相应生命周期的方法;如果是远程服务,VirtualAPK先将目标插件apk加载进来,然后再反射调用目标Service的生命周期方法。

android 常用插件 android 插件化方案_动态代理_10

六、插件化的几个重要优势

体积:按需接入需要的插件,可以达到减少体积的作用

更新:插件独立开发,通过下发实现低成本和低频卸载重装

版本:同个功能插件可以打包生成不同版本,下发时候按版本选择合适的插件apk,可以实现多版本的兼容

七、插件化风险点、

1、个别属性由于插件化实现方式会造成不支持。

2、Android P,禁止调用私有API(经过@hide修饰的方法),在适配上可能需要费些功夫

3、VirtualApk近一年未更新,目前只支持到com.android.tools.build:gradle:3.1.0.