前言
-
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,控制类加载过程,帮助加载插件。
实现有以下几个核心步骤
- 先通过反射获取到缓存LoadedApk对象的mPackages
- 构建插件的LoadedApk对象
2.1 构建插件的ApplicationInfo信息
2.1.1 构建PackageParser.Package
2.1.2 构建PackageUserState
2.2 替换自定义ClassLoader 2.3 hook PMS绕过包信息检查 - 用我们提前构建好代理对象替换掉原有的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 动态代理方案
- 宿主Manifest声明替身StubActivity
- 启动插件TargetActivty前,先hook掉Instrumentation的execStartActivity方法,在这个方法里替换掉TargetActivty的Intent,将其替换成StubActivity的Intent用于绕过System server进程的AMS的检查。
- 当AMS检查完成后准备启动StubActivity时又会回调到App进程的Instrumentation的newActivity方法,在这里替换为TargetActivty的intent的,用于启动TargetActivty。
其他三大组件的实现原理也大都如此。
思考总结
Android插件化是一项面世近10年的技术,涉及到知识面是很多,如Framework的AMS、PMS,DVM、ART以及JVM等,因为Android底层的迭代是十分缓慢的,因此插件化这项技术的核心内容也基本没有大的变化,但是当对插件化相关的知识理解后,会发现对Android的理解进入一个新的层面。