第4章 Atlas架构深度解析:Bundle概念、AXML资源合并、ClassLoader隔离、动态部署引擎

系统边界与分层架构

Atlas 的核心思路是将宿主应用拆解为若干可独立开发、编译和动态更新的 Bundle。系统边界定义在宿主 APK 与 Bundle APK 之间,通过三层架构实现解耦:

  • 宿主层:提供运行容器、基础框架、公共资源与类库。宿主本身不包含业务逻辑,仅负责 Bundle 的生命周期管理。
  • Bundle 层:每个 Bundle 是一个独立的业务模块,包含自身资源、代码、AndroidManifest 片段。Bundle 之间不可直接引用代码,仅通过接口或宿主提供的服务进行通信。
  • 内核层:Atlas 运行时内核,负责启动过程、ClassLoader 组装、资源合并、动态部署信号的监听与执行。
选型权衡:Atlas 的 Bundle 粒度比 RePlugin 更细,适合超大型 App(如手机淘宝)的渐进式解耦,但初始配置成本更高。
信任链路:宿主与 Bundle 之间的信任通过签名校验建立。Atlas 要求每个 Bundle 必须使用与宿主相同的签名进行签名,否则拒绝加载。

Bundle 概念与生命周期

Bundle 是一个经过 Atlas 工具链加工的独立 APK,包含完整代码、资源及合并后的 AndroidManifest 片段。它既不是宿主的一部分,也不是完全独立的进程容器,而是运行在宿主进程内的一个“模块”。

Bundle 状态描述触发时机
已安装Bundle APK 解压至宿主内部存储,资源表已注册首次启动时或动态部署安装后
已加载ClassLoader 已创建并加入隔离链,可反射调用入口类首次访问 Bundle 组件时
已挂载AXML 资源已合并至宿主 ResourcesBundle 被激活时
已卸载ClassLoader 废弃,资源表注销动态部署更新老旧 Bundle 时
  • 数据流:Bundle 安装 → 读取 AndroidManifest → 注册 Activity/Service → 等待第一次加载。
  • 控制流:宿主启动 → Atlas 内核扫描已安装 Bundle → 按依赖顺序预加载基础 Bundle → 按需懒加载业务 Bundle。

AXML 资源合并机制

多个 Bundle 的资源 ID 存在冲突风险。Atlas 在编译期通过 AXML 资源合并 过程解决:将每个 Bundle 的 resources.arsc 反编译为中间 XML,然后与宿主的公共资源表进行合并,生成统一的资源映射表。

@工具侧:AtlasMergeRes
输入:宿主 R.txt + 各 Bundle 的 resources.arsc
输出:合并后的 resources.arsc 及插件 R.java
过程:
1. 收集所有 Bundle 中定义的资源名称和类型
2. 检测重复资源名(优先使用宿主版本)
3. 重新分配全局资源 ID
4. 生成最终的 resources.arsc
  • 风险点:资源 ID 重分配可能导致旧版本 Bundle 引用错误的资源。必须在更新 Bundle 时同时发布新合并的资源表。
  • 落地步骤:在 CI 流水线中配置 AtlasMergeRes 任务,确保每次打包前执行。验收标准:宿主安装后,所有 Bundle 中引用的资源 ID 与宿主预期一致,不出现 ResourceNotFoundException。

ClassLoader 隔离体系

Atlas 使用 多 ClassLoader 链 实现 Bundle 之间的代码隔离。每个 Bundle 拥有一个独立的 AtlasClassLoader,并形成父子委托链:

Boot ClassLoader
    └─ PathClassLoader (宿主)
        └─ AtlasClassLoader (BundleA)
            └─ AtlasClassLoader (BundleB)
                └─ AtlasClassLoader (BundleC, 依赖 BundleB)
  • 信任链路:只有被宿主信任的 Bundle 才能被挂载到链中。信任声明在宿主 AndroidManifest 的 atlas-bundle 配置中。
  • 风险点:如果 Bundle A 和 Bundle B 包含同名类,委托链将总是优先返回先加载的版本。设计时应避免 Bundle 间依赖未声明的类。
  • 验收标准:通过 Class.forName 验证,Bundle 只能加载自身与宿主提供的类,无法访问其他 Bundle 的内部类。
选型权衡:ClassLoader 链会增加类查找开销。每增加一个 Bundle,首次类加载平均耗时增加 5-15ms。对冷启动敏感的场景需控制 Bundle 数量在 30 个以内。

动态部署引擎

Atlas 的动态部署引擎负责在不重启应用的前提下更新 Bundle。核心控制流如下:

  1. 信号接收:引擎后台轮询或接收推送通知,获取新 Bundle APK 的下载地址。
  2. 下载与验证:下载 APK 后校验签名与宿主一致,防止篡改。
  3. 替换与挂载:将旧 Bundle 标记为待卸载,新 Bundle 解压至临时目录,通过 AtlasClassLoader 重新挂载,同时更新资源表。
  4. 热切换:等待已加载的旧组件全部销毁,然后更新组件注册表,使新请求指向新 Bundle。

数据流示例:动态部署更新一个 Bundle 时,受影响的 Activity 会经历 onDestroy() → 新 Bundle 挂载 → 下次 startActivity() 自动使用新组件。

落地步骤:

  • 宿主集成 Atlas SDK 并开启动态部署监听。
  • 构建动态部署 Bundle,使用 atlas-patch 工具生成差异包。
  • 部署至线上测试环境,验证更新成功率 ≥99%,且不导致宿主崩溃。
Atlas 架构核心组件与数据流 宿主应用 容器 + 框架 Atlas 内核 动态部署引擎 Bundle 实例 多 Bundle 并行加载 AXML 资源合并 合并 resources.arsc ClassLoader 链 隔离 + 委托 动态部署引擎 信号 → 下载 → 签名 → 挂载 🔑 关键控制流与信任链路 1. 宿主启动,Atlas 内核初始化,扫描已安装 Bundle。 2. 内核根据依赖树按序创建 Bundle 的 ClassLoader 并挂载资源。 3. 动态部署信号到达 → 下载新 Bundle → 签名校验 → 替换旧 Bundle(原子操作)。 4. 所有 Bundle 组件访问需通过内核提供的接口,禁止直接跨 Bundle 引用。

选型权衡总结

维度Atlas权衡说明
Bundle 粒度极细(可到单个模块)适合大团队分布式开发,但初始化配置复杂
资源合并编译期全量合并避免运行时冲突,代价是打包时间显著增加
ClassLoader 隔离多链委托强隔离性,但类加载性能下降,需注意 Bundle 数量
动态部署支持全量 + 差分更新差分算法优化后包体较小,但需要服务端配合处理基线版本

风险点与规避措施

  • 资源 ID 错乱:强制在每次发布 Bundle 时执行资源合并流水线,禁止手工修改 R 文件。
  • 类加载死锁:避免在 Bundle 初始化阶段进行跨 Bundle 类加载。可使用延迟初始化或在宿主线程之外处理。
  • 动态部署回滚困难:每次动态更新前,保留当前 Bundle 的快照目录。一旦新版本崩溃,内核应自动回退到快照版本。

验收标准

  1. 宿主安装后,所有预置 Bundle 的 Activity 能成功启动并显示正确资源。
  2. 通过 ADB 命令或推送信号触发动态部署,新的 Bundle APK 生效后,旧组件页面正常关闭,新组件 100% 可用。
  3. ClassLoader 隔离验证:Bundle A 无法通过反射访问 Bundle B 的内部类,只能通过宿主声明接口调用。
  4. Monkey 测试 2 小时,无因资源冲突、ClassLoader 或动态部署导致的崩溃。