往期参考:
- 需求定义
- 基本原理
- 插件实现
- 资源覆盖
插件形式
插件一般是独立Apk形式,但是也可以内置集成在应用里面,这些模块也可以注册为虚拟插件,由插件管理模块统一管理。
虚拟插件包含“宿主插件”这一特殊插件,、它将宿主APP虚拟为一个插件,主要用于资源覆盖中作为覆盖目标。
插件环境
插件环境是指插件运行所依赖的环境。不同的插件需要不同的环境,有的插件可以在多个环境下运行。
插件环境通过一个接口类表示,在插件描述中需要表明插件可以工作的环境,可以列出多个;同时,插件类也需要继承这些接口,内置插件通过插件类继承的接口来达到同样的效果,虽然这可能是多余的。
插件集成
插件集成方式及对应目录(以优先级顺序排列):
集成方式 | 扫描目录 | 说明 |
应用升级插件 | /data/data/<package>/cache/plugins/ | 应用缓存目录 |
外部升级插件 | /sdcard/<package>/cache/plugins/ /data/data/<package>/cache/plugins/external/ | 从USB目录拷贝到该目录 没有扩展sdcard时 |
应用内置插件 | /data/data/<package>/cache/plugins/assets/ | 从应用assets资源解压出来 |
系统升级插件 | /data/xxxplugins/ | 全局的,限系统预置应用使用 |
系统预置插件 | /system/xxxplugins/ | 全局的,限系统预置应用使用 |
应用集成插件 | 没有插件形式,但是作为插件统一管理 | 注册Plugin入口类 |
虚拟应用插件 | 将应用特殊虚拟为一个插件 | 目前用于皮肤覆盖 |
插件加载
加载流程
- 导入插件
- 外部插件:通过插件Context,加载插件描述
- 内置插件:已经提供插件类,没有额外描述
- 依赖检查
- 检查环境依赖,过滤
- 外部插件:检查插件描述中的环境依赖
- 内置插件:检查插件实现的环境接口
- 检查插件依赖(递归)
- 检查插件依赖,如果依赖插件不存在,则依赖性失败
- 递归依赖插件,如果依赖插件检查失败,则当前插件依赖性失败
- 启动插件(递归)
- 如果有依赖,先启动依赖插件
- 构建插件ClassLoader(内置插件跳过)
- 加载插件类(内置插件跳过)
- 创建插件类实例
- 调用插件实例的start方法
- 清除未使用插件
因为所有的检查都先做了,所以环境不相关的插件在清除后都不会留下痕迹。启动失败的插件可能会遗留插件类,导致插件部分资源不能释放。
延迟加载
插件加载过程中包含dex优化和so库解压等步骤,这些步骤都比较耗时。为了减少应用首次启动的时间,应该将插件的一部分加载步骤推迟。
具体方案为:
- 推迟“启动插件”这一步,不影响依赖检查
- 虚拟插件不推迟
- 资源包不推迟
缓存管理
缓存目录:
集成方式 | 缓存目录 | 特殊说明 |
应用插件 | /data/data/<package>/cache/plugins/ | 包括:应用升级插件、外部升级插件、应用内置插件、应用集成插件、虚拟应用插件 |
系统升级插件 | /data/xxxplugins/ | 皮肤覆盖仍使用应用内部缓存 |
系统预置插件 | /data/xxxplugins/ | 皮肤覆盖仍使用应用内部缓存 APK时间是“系统构建时间”与“实际APK时间”取大者 可使用预置资源(odex,so) |
缓存项目:
项目 | 缓存子目录 | 特殊说明 |
锁文件 | 缓存根目录 |
|
Native库 | lib |
|
Dex优化 | dex | Android O以上无效 |
配置文件 | props、缓存根目录 | 老版本配置文件解压在缓存根目录 |
资源覆盖 | idmap | 覆盖目标包的缓存目录, |
插件更新
未完待续