Android 插件化小结

Android 插件化小结

简介

插件化可以用于让apk不经过安装而运行起来,将一些不常用的模块做成插件,当需要用到时再下载运行,这可以减小主app安装包的大小,在开发过程中也可以单独调试某个插件模块,避免整个项目太大编译运行太慢问题;

常见的插件化框架有:dynamic-load-apk、VirtualApp、RePlugin、shadow等

实现原理

插件化的实现主要需要解决以下几个问题:

  • 插件apk中类的加载,以及和宿主app的相互调用

  • 插件apk中资源的加载,以及和宿主app的相互使用

  • 插件apk中四大组件的生命周期管理

类加载

插件apk中的类主要是通过DexClassCloader去加载的,这里也分为两种方式:

  • 单独为每个插件apk创建一个ClassLoader;这种方式的优点是插件之间ClassLoader相互隔离,如果不同插件引入相同类库不同版本不会存在问题;缺点就是插件之间和宿主之间相互调用需要持有对应的ClassLoader

  • 将多个插件ClassLoader与宿主ClassLoader合并为一个ClassLoader;这种方式主要是通过反射DexPathList,将不同插件的dex路径添加到同一个数组中,跟热修复原理相似;优点是插件之间和宿主之间的类都可以直接访问;缺点就是不同插件引入同一类库不同版本时会有问题,需要将用到的公共类库抽离到一个独立的公共插件中

资源加载

插件资源的加载一般是通过反射构建Assetmanager并调用addAssetPath将apk路径添加进去,然后通过传入AssertManager构建Resources对象;不同插件之间的资源也是可以单独分开管理和合并为一个这两种方式的:

  • 单独分开管理:优点是相互独立,就算资源名重复也不会出现问题,只需要重写代理Activity的getResources方法返回插件的资源对象就可以;缺点是互相使用对方资源需要先获取到Resource对象

  • 合并为一个Resources:通过反射调用Assetmanager的addAssetPath方法将所有插件和宿主的资源添加进去,然后利用反射替换到原来宿主中的Resource对象,比如:ContextThemeWrapper.mResources、LoadedApk.mResources、ActivityThread.mResourcesManager等;缺点就是需要反射修改更多地方的Resources对象,并且需要解决资源id可能重复问题(可以通过修改apk中resources文件,或者修改aapt编译源码)

四大组件的支持

四大组件的类仅仅创建出实例是不能正常使用的,需要结合生命周期的调用才能正常使用;四大组件中Activity是最复杂的,在插件化中Activity主要有两种实现方式:

  • 代理Activity:

    • 当启动插件里的Activity时,会先启动一个代理Activity,代理Activity里会根据插件Activity相关信息,创建插件Activity实例,并传入当前代理Activity对象给插件Activity,然后在各个生命周期方法中,调用插件Activity中各个生命周期方法,还需要重写getClassLoader、getResources等方法返回对应插件的ClassLoader和资源对象

    • 插件Activity这边需要统一继承自一个插件Activity基类,在这个基类中会重写setContentView、startActivity等方法,转而调用代理Activity中的方法

    • 优点是不需要hook系统api,没有兼容性问题

    • 缺点是如果Activity不是默认启动模式,而是SingleTask、SingleInstance等,需要自己管理Activity栈,会相对麻烦一些

  • Hook系统启动Activity过程

    • Activity启动过程:

      • startActivity/startActivityForResult

      • Instrumentation.execStartActivity

      • ActivityTaskManager.startActivity

      • AMS从PMS中查找Activity信息、创建进程、处理启动模式、任务栈等等

      • 通过Handler向ActivityThread发送消息,调用Instrumentation.newActivity方法通过反射创建Activity实例

      • 接着调用Activity各个生命周期方法

    • Hook启动Activity过程:

    • Activity启动过程中,校验Activity是否注册到AndroidManifest文件中是在AMS中,所以关键的Hook点有两个:一个是在调用AMS之前 ,将要启动的插件Activity替换成预置的Activity用于躲过AMS的检查;另一个点是在ActivityThead中创建Activity之前,需要将预置的Activity再替换回插件Activity

    • Hook点根据不同插件化框架会有所不同,比如有些Hook Instrumentation的execStartActivity和newActivity方法;也可以Hook ActivityTaskManager(静态Sington单利)和ActivityThread中的Handler(Handler中的callback)

    • 优点:生命周期和启动模式完全由系统服务负责

    • 缺点:通过Hook方式不稳定,需要适配不同Android版本

  • 其他组件:

    • Service和ContentProvider与Activity类似

    • BroadCastReceiver是通过解析Manifest,将静态广播转为动态注册

Shadow实现方法

Shadow号称零反射插件化框架,主要体现在以下几个方面:

  • 加载插件里的类是通过DexClassLoader加载,没有用到反射去合并各个插件的dex

  • 资源加载时并没有通过AssetManager反射构建,而是通过PM的getResourcesForApplication方法创建

  • 在四大组件支持方面,则是走的是Activity代理方式避免Hook系统api

猜你喜欢

转载自blog.csdn.net/guangdeshishe/article/details/129968750
今日推荐