4. 插件安装与卸载流程对比:RePlugin的APK托管 vs Atlas的Bundle生命周期管理
4.1 系统分层与模块边界
插件安装与卸载是插件化框架的入口与出口,直接影响动态下发、版本控制和资源回收的可靠性。两种方案在分层和职责上存在本质差异:
| 层次 | RePlugin | Atlas |
|---|---|---|
| 宿主工程 | 提供 Container + 任务调度,不感知具体APK | 提供 Bundle 管理容器,维护所有 bundle 的元数据 |
| 插件框架层 | Gardener(安装器)+ Loader(加载器) | Bundle Manager + Bundle Installer + Bundle Loader |
| 运行时层 | 直接通过 PackageManager 安装/卸载 APK(需要系统签名或 root) | 通过自定义 ClassLoader + AssetManager 加载/释放 Dex 与资源 |
模块边界对比: RePlugin 的安装过程等价于"系统级 APK 安装",边界在宿主与系统之间;Atlas 的安装则完全在应用进程内完成,边界在宿主框架与 bundle 之间。
4.2 组件职责
- RePlugin.Gardener(安装器): 负责接收下载完成的 APK 文件,调用
PackageInstaller或通过adb install机制将其安装到系统分区。卸载时同样通过系统 API 移除 APK。 - RePlugin.PluginLoader: 监听系统广播(
ACTION_PACKAGE_ADDED)感知插件状态变化,触发 Dex 和资源加载。 - Atlas.BundleInstaller: 解析下载的 bundle zip 包,将 Dex 文件写入宿主私有目录,生成
BundleArchive实例,注册到BundleManager。 - Atlas.BundleUnInstaller: 从
BundleManager中移除元数据,回收 ClassLoader 和 AssetManager 引用。
4.3 插件安装流程详解
RePlugin - APK 托管模式
// 核心安装调用 (需在 hook 后的系统上下文中)
RePlugin.install(context, "/data/data/.../plugin.apk");
// 内部调用链
PluginLibraryInternal.install(...)
→ ensurePluginInstalledInternal(Context, String)
→ PackageManager.installPackage(Uri, ...) // 系统级安装
→ 监听 ACTION_PACKAGE_ADDED 广播
→ PluginManager.preparePlugin(...) // 准备运行时环境
风险点: 该方式在非 Root 设备上存在权限限制。RePlugin 通过 Hook
PackageManager 绕过部分检查,但在 Android 10+ 的 scoped storage 和隐私策略下,安装成功率下降明显。
Atlas - Bundle 生命周期管理
// 安装一个 bundle (从下载到激活)
BundleManager mgr = Atlas.getInstance().getBundleManager();
BundleArchive archive = mgr.installBundle("com.example.plugin", bundleZipFile);
// installBundle 内部流程
1. 解压 bundle.zip → 获取 Dex、so、AndroidManifest
2. 将 Dex 写入 /data/data/.../bundles/com.example.plugin/classes*.dex
3. 生成 BundleArchive 对象,持有 packageName、version、installedPath
4. 创建独立的 BundleClassLoader(parent = host ClassLoader)
5. 反射创建 Bundle Context(自定义 AssetManager + Resources)
6. 回调 onBundleInstalled 到宿主
// 卸载
mgr.uninstallBundle("com.example.plugin");
→ BundleArchive 标记为 UNINSTALLED
→ 解除 ClassLoader 引用
→ 删除私有目录中的 Dex 文件(延迟 GC)
4.4 数据流与控制流
两种方案在数据流向和控制权归属上形成鲜明对比:
- RePlugin 数据流: 插件 APK → 系统 PackageInstaller → 系统/data/app → 广播回调 → 宿主 Loader。控制权归属系统。
- Atlas 数据流: bundle.zip → BundleInstaller → 私有目录 → BundleArchive → BundleManager → loader。控制权完全在宿主进程。
4.5 数据流与控制流关键差异
| 维度 | RePlugin | Atlas |
|---|---|---|
| 安装源 | 必须是可安装的 APK(签名对齐) | 任意 bundle zip(仅包含 Dex + 资源) |
| 安装接口 | RePlugin.install(Context, apk) |
BundleManager.installBundle(name, zip) |
| 下载触发 | 宿主自行下载,Gardener 只负责安装 | BundleManager 可集成下载回调 |
| 文件落地 | 系统 /data/app 或 /system/plugin |
宿主私有目录 /data/data/.../bundles/ |
| 卸载粒度 | 全量卸载(整个 APK 移除) | 可按 bundle 名称单条移除 |
| 卸载后资源回收 | 由系统 GC + 宿主清理广播 | 框架层显式释放 ClassLoader、AssetManager |
| 权限风险 | 高(依赖系统 hook + Android 版本兼容) | 低(完全在进程内管理) |
4.6 选型权衡
什么时候选 RePlugin 的 APK 托管?
- 插件需要作为独立 APK 被系统识别(例如:桌面快捷方式、Intent 唤起)
- 团队已有系统级 hook 经验,且目标 Android 版本可控(≤ 9.0)
- 插件体积大,需要利用系统优化(如 dex2oat)提升加载速度
什么时候选 Atlas 的 Bundle 生命周期?
- 目标 Android 版本 ≥ 10,避免系统 API 限制
- 需要精确管理插件内存和资源(直播、游戏、地图等重型场景)
- 插件数量多,需要批量安装/卸载/更新,且要求进程内快速切换
4.7 风险点
- RePlugin 安装风险: 系统广播可能延迟或丢失(低内存杀进程时),导致插件状态不一致;Google Play 上架时可能因 hook 被拒。
- Atlas 卸载风险: 卸载后 ClassLoader 引用未完全释放,导致内存泄漏;私有目录残留 Dex 文件,需配合
tempDir清理策略。 - 版本兼容性: RePlugin 的 APK 托管在 Android 12+ 的
PackageInstaller改动下几乎失效,必须降级为模拟安装。
4.8 落地步骤
- RePlugin 安装落地:
- 搭建下载通道,确保 APK 完整性校验(MD5/SHA256)。
- 调用
RePlugin.install,监听安装结果回调。 - 建议降级方案:若系统安装失败,回退到
DexClassLoader方式(框架内置 fallback)。
- Atlas 安装落地:
- 定义 bundle 元数据(name、version、dependencies)。
- 下载 bundle.zip,解压后调用
installBundle。 - 使用
BundleArchive.getBundleClassLoader()加载插件类。
4.9 验收标准
| 验收项 | RePlugin 验收方法 | Atlas 验收方法 |
|---|---|---|
| 安装后插件可正常打开 | 通过 Intent 启动插件 Activity | 通过 BundleContext 创建插件 View |
| 卸载后插件资源回收 | 检查 /data/app/ 中文件是否移除 |
检查 bundles/ 目录是否清理,ClassLoader 是否可 GC |
| 重复安装版本更新 | 安装新版 APK,旧版自动替换 | 调用 installBundle 时 version 递增 |
| 异常恢复能力 | 安装中断后重试能否恢复 | 安装失败后 BundleArchive 状态回滚 |