什么是插件化

将App功能拆分成多个模块,每个模块都是一个apk,最终打包成宿主apk和多个插件apk,插件apk放到云端通过接口动态下发到宿主apk,实现功能集成。

插件化的优势

  1. 宿主apk和插件是分开编译的,是两个apk,更利于多人开发。
  2. 插件模块功能的迭代更新和bug修复可以通过服务端接口动态下发,不需要重新下载安装整个apk,更加灵活方便
  3. 主apk的各个功能模块,用户可以按需下载,可以减小主apk的包体积
  4. 可以解决65535问题

插件化的原理

通过一个宿主Activity成为插件apk的载体来显示插件中的内容,这个过程的核心就是重写宿主Activity的getResources()和getClassLoader()方法,将资源和类加载器指向插件apk中的内容。将宿主Activity的生命周期和上下文Context传递给插件Activity来处理。

另外还有两种利用Hook实现的插件Activity加载原理:

1)Hook IActivityManager

Activity通过startActivity的启动过程如下:

startActivity-Instrumentation.execStartActivity()->ActivityManager.getService().startActivity()->
IActivityManager.Stub.asInterface->AMS.startActivity()

这里ActivityManager.getService返回的是一个Singleton实现的单例,该单例是静态的,返回的是IActivityManager,这是一个Hook点,IActivityManager是一个接口,这里可以采用动态代理来实现Hook。

1.1 在AndroidManifest.xml中注册SubActivity。

1.2 反射获取ActivityManager的静态实例Singleton<IActivityManager>,反射获取Singleton中的mInstance实例,该实例就是IActivityManager的实例对象。

1.3 动态代理创建IActivityManager的代理对象,通过反射赋值给Singleton内部的mInstance。在动态代理中拦截启动Activity的方法,将startActivity传入的targetIntent替换成我们新建的proxyIntent,并设置跳转目的为SubActivity,将targetIntent做为参数赋给proxyIntent。

1.4 之后到启动Activity的过程,AMS会远程调用ApplicationThread的scheduleLaunchActivity。然后主线程的ActivityThread的Handler收到LAUNCH_ACTIVITY会调用handleLaunchActivity,通过Instrumentation启动Activity到Activity的onCreate方法。

研究Handler机制可以发现,在Handler通过dispatchMessage分发消息时,如果Handler的mCallback不为空,就会执行mCallback的handleMessage方法,我们可以以mCallback作为Hook点,使用自定义的mCallback来替换它。在mCallback中判断消息类型如果是LAUNCH_ACTIVITY时,将启动SubActivity的Intent替换为启动TargetActivity的Intent。可以反射获取ActivityThread,在反射获取它的mH即Handler对象,替换mCallback,这个过程可以在Application的attachBaseContext方法中进行。

2)Hook Instrumentation

启动Activity最后都会调用Instrumentation的execStartActivity方法。并且在ActivityThread的performLaunchActivity中使用mInstrumentation的newActivity方法,其内部会用类加载器来创建Activity的实例。我们可以写一个Instrumentation的代理类InstrumentationProxy并替换它,然后就可以截获它的execStartActivity和newActivity方法。

也是一样,在AndroidManifest注册一个SubActivity来躲过AMS验证。当发起startActivity时检查TargetActivity是否已注册,如果没有则将TargetActivity的ClassName保存起来后面还原,接着把启动的TargetActivity替换成SubActivity,通过反射调用execStartActivity方法,这样就可以用SubActivity通过AMS的验证。在Instrumentation的newActivity方法中还原TargetActivity,在newActivity方法中创建此前保存的TargetActivity,还原TargetActivity。

详细实现

pluginDemo: Android插件化demo

插件化框架

插件化 Android 版本 问题 插件apk_动态代理