Android 插件化技术原理解析

162 阅读4分钟

前言

  • Android插件化是什么?
    Android插件化是指把一些核心复杂依赖度高的模块封装成独立插件,然后根据不同业务进行组合、动态替换,可对插件进行管理、更新。

  • 插件化用于解决什么问题?
    免安装升级应用,减少应用商店APP更新频次,加快功能迭代。减少apk包体积,降低模块间耦合,支持按需加载,突破65535方法数限制。

  • 插件化框架核心内容是什么?

    • 类与资源的动态加载
    • 四大组件的生命周期支持

原理解析

类加载

虚拟机的类加载机制是Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校检、转换解析和初始化的,最终形成可以被虚拟机直接使用的Java类型。在Java语言里面,类型的加载、连接和初始化都是在程序运行期间完成。

安装好了的宿主apk和未被安装的插件apk的主要区别是被安装的宿主app可以直接被系统加载运行,当需要执行插件中的代码时需要在宿主运行时去实现加载插件apk。

在Android中实现宿主加载插件有两种方式

自定义ClassLoader加载插件

系统在加载已安装的apk的class时,会通过这个apk的LoadedApk对象的classLoader去加载,而LoadedApk对象是APK文件在内存中的表示。在获取LoadedApk时会先从一个缓存的map中去获取,需要实现hook掉这份缓存信息中的classloader,控制类加载过程,帮助加载插件。

实现有以下几个核心步骤

  1. 先通过反射获取到缓存LoadedApk对象的mPackages
  2. 构建插件的LoadedApk对象
    2.1 构建插件的ApplicationInfo信息
    2.1.1 构建PackageParser.Package
    2.1.2 构建PackageUserState
    2.2 替换自定义ClassLoader 2.3 hook PMS绕过包信息检查
  3. 用我们提前构建好代理对象替换掉原有的mPackages

插件dex插入系统dexElements

在宿主apk在被加载的过程中,宿主dex会被PathClassLoader add到一个dexElements中,当需要findclass时就会遍历这个dexElements。所以可以通过hook把插件apk add到这个dexElements中委托系统帮我们加载。

对比

方案实现难度代码热加载安全性
自定义classLoader多次hook,实现难度大支持
dexElements插入少量hook,实现简易不支持

资源加载

从Activity或Appliaction获取资源时,实际上是调用的contextImpl的getResource方法,Resource的实现类ResourceImpl在创建时需要传入一个AssetManager对象,而AssetManager创建后会通过addAssetPath传入资源路径完成资源加载。

所以在插件apk中要实现资源加载,只需完成AssetManager对象创建并传入我们资源路径,接着创建Resource,就可以利用这个Resource完成插件资源加载了。

因为插件Resource与宿主Resource不是同一个对象,资源无法共享,还一种资源加载方案是,在我们创建插件的Resource通过hook把宿主Resource与插件Resource进行合并成一个Resource,可以实现宿主与插件资源共享效果,但需要注意资源冲突问题。

四大组件支持

针对普通的类我们仅需在宿主中完成对插件类的加载,然后就可以愉快的调用插件的方法了,但是对于Android的四大组件来说,还需要让四大组件具备生命周期,让插件的四大组件“活过来”。

Activity启动过程简述就是由contextImpl调用到Instrumentation,再由Instrumentation通过binder调用到系统进程里的AMS,经过AMS一系列的参数验证等逻辑最终又调回APP进程里的Instrumentation完成新Activity的启动。

Activity 静态转发方案

1.在宿主内创建ProxyActivity。 2.在ProxyActivity生命周期的各个回调方法里调用插件Activity的生命周期对应的回调方法。

Activity 动态代理方案

  1. 宿主Manifest声明替身StubActivity
  2. 启动插件TargetActivty前,先hook掉Instrumentation的execStartActivity方法,在这个方法里替换掉TargetActivty的Intent,将其替换成StubActivity的Intent用于绕过System server进程的AMS的检查。
  3. 当AMS检查完成后准备启动StubActivity时又会回调到App进程的Instrumentation的newActivity方法,在这里替换为TargetActivty的intent的,用于启动TargetActivty。

其他三大组件的实现原理也大都如此。

思考总结

Android插件化是一项面世近10年的技术,涉及到知识面是很多,如Framework的AMS、PMS,DVM、ART以及JVM等,因为Android底层的迭代是十分缓慢的,因此插件化这项技术的核心内容也基本没有大的变化,但是当对插件化相关的知识理解后,会发现对Android的理解进入一个新的层面。