Android插件化的机制

插件化是什么?

对大型APP,需要动态更新模块功能。我们把宿主apk拆分成多个子apk,下发给宿主app来动态加载,这个过程叫做插件化。

我们可以通过ClassLoader类加载机制加载插件。 但是在Android系统,对Activity、Service、广播、contentProvider这些组件是由系统服务管理的。也就是说,数据(DEX)准备好之后,还需要系统服务去加载这个数据(DEX文件)。

我们要用到Hook技术(反射、动态代理、静态代理)和Classloader机制,而且要熟悉AMS、PMS和四大组件交互过程。

加载插件的几种方法?

我们以加载插件中一个activity为例,来分析插件化实现过程。

加载插件中的字节码

合并插件到宿主的PathClassLoader中

 1. 使用自定义的DexClassLoader我们就能加载插件dex中任意.class类,用反射技术就能操作得到的插件Class了。

2. 反射BaseDexClassLoader,修改其中“dexElements", 利用插件dex,反射实例化相应到element,把它插入到dexElements数组中,至此以后可以默认使用宿主的classloader加载所有的插件。有个缺点是类库可能会冲突。

ClassLoader加载插件中的Activity

上面通过自定义ClassLoader加载一个class文件到JVM中。我们还需要用Hook技术修改AMS的客户端,达到欺上瞒下的目的。

在启动插件activity启动过程中有两个主体

一个是App进程,一个是AMS。 AMS系统服务,四大组件的大领导,所以你要启动一个activity,你要向领导提前打报告。

上图是启动插件acitivty流程,

1. hook的第一个点:修改Request信息。ActivityManagerProxy,把startActivity(Intent)信息替换成占位activity(StubActivity), StubActivity是宿主AndroidManifest文件中注册的,开机启动时,PMS安装宿主apk的时候,PMS会解析apk信息,并把信息共享给AMS,所以AMS是认识它的。我们把ActivityManagerProxy动态代理成MyActivityManagerProxy,把RealIntent替换stubIntent,欺骗AMS。

2. hook的第二个点,修改响应信息(handler中)。等AMS校验Intent信息结束后,通知宿主启动的时候,我们可以hookActivityThread中的handler的callback接口,把原来的realIntent还原出来。同时要注意在这里我们动态加载插件的activity字节码了,这里两种方案加载插件,第一种就是上文提到的也可以一次性把所有插件dex合并到宿主的baseDexclassloader中,第二种是我们可以修改Loadedapk中classloader,为了隔离,我们采用第二种办法修改loadedAPK类,插件都使用自己的classloader。

加载插件的资源文件,如何解决资源冲突。

加载资源,我们通过getResource().getDrawable(resid),得到资源,其实底层最终都是调用getAssetManager,根据资源id,去resource.arce这个map里面加载映射好的资源文件。

我们可以hook AssetManager的addAssetPath方法,添加插件的路径,那么assetManager会返回插件的资源。

两种加载插件资源的方案

第一种方案是,一次性把插件的资源一次性通过hook assetManager.addAssetPath(pluginPath)合并到宿主的AssetManager里。

第二方案是,每次进入插件的Activity,才去替换AssetManager的assetPath为插件的路径,退出插件的界面时,再把AssetManager的assetPath还原成宿主的assetPath。

对于第一种方案要解决资源id冲突,常见的办法是编译插件的时候,修改aapt工具,把插件资源的packageID重命名,这样就不会与宿主产生冲突。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值