第2章 Android App Bundle 文件结构解析

Android App Bundle (AAB) 本质上是一个标准 ZIP 压缩包,但其内部文件组织和元数据遵循严格的协议缓冲区(Protobuf)格式。只有掌握 AAB 内部结构,才能理解动态交付的模块切割、资源拆分和多 APK 生成原理。本章逐层拆解 AAB 文件的根目录、base 模块、feature 模块、关键配置文件和资源索引,并通过 bundletool 命令验证结构。

2.1 顶层目录结构

使用 unzip -l *.aab 或 bundletool dump manifest --bundle 可以观察顶层布局。一个典型的 AAB 包含以下核心实体:

路径 / 文件类型作用
BundleConfig.pbProtobuf 文件定义 bundle 版本、分发策略、优化指令
base/目录基础模块,包含所有设备通用的代码和资源
feature_*/目录按需交付的动态特性模块,名称由 dist:module 指定
manifest/目录包含合并后的 AndroidManifest.xml
resources.pbProtobuf 文件全局资源索引表,记录所有资源的 ID、名称、限定符
native.pbProtobuf 文件原生库元数据(可选)
dex/目录DEX 分片描述文件(仅当启用分片时出现)
验证命令: 在终端执行以下命令可查看 AAB 实际内容(请先安装 bundletool):
bundletool dump manifest --bundle=/path/to/app.aab
bundletool dump resources --bundle=/path/to/app.aab
unzip -l /path/to/app.aab | head -30

2.2 base 模块内部结构

base 模块是每个 AAB 的必备模块,存放所有语言、屏幕密度、CPU 架构通用的代码与资源。其子目录结构如下:

base/
├── dex/                    # DEX 字节码(按配置分割)
├── res/                    # 资源文件(布局、图片、字符串等)
├── lib/                    # 原生 so 库
├── assets/                 # 应用资产
├── root/                   # 放置在 APK 根目录的文件
├── manifest/               # 该模块的 AndroidManifest.xml
├── resources.pb            # 该模块的资源索引子表
└── native.pb               # 该模块原生库元数据(可选)

Gradle 构建时通过 android.baseModule 插件生成,默认包含应用启动所需的所有内容。

2.3 feature 模块(动态特性)

feature 模块对应 com.android.dynamic-feature 插件。每个动态特性模块拥有与 base 相似的子目录结构,但 manifest/AndroidManifest.xml 中必须声明 dist:module 和 dist:onDemand 属性。一个典型 feature 模块的清单片段:

<dist:module
    dist:type="feature"
    dist:title="@string/feature_name">
    <dist:delivery>
        <dist:on-demand/>
    </dist:delivery>
    <dist:fusing dist:include="true"/>
</dist:module>

base 与 feature 模块的关键区别:

属性base 模块feature 模块
分发时机安装时强制包含按需下载 / 条件分发 / 安装时可选
是否可移除否是(onDemand="true")
清单中 dist:typefeature 且 dist:onDemand="false"feature
内容完整性必须包含 Activity、Application 等入口可只包含资源或代码
依赖关系无可依赖 base 或其他 feature

2.4 BundleConfig.pb 配置详解

该文件使用 Protobuf 序列化,定义了 bundle 的构建设置。可通过 bundletool dump bundle-config --bundle 查看可读内容。关键字段:

  • Bundletool.version:生成该 AAB 的 bundletool 版本。
  • Optimizations:包含 splitsConfig(按资源/ABI 拆分)、uncompressNativeLibraries、removeUnusedResources 等标记。
  • AabConfig:模块分割规则,例如 standaloneConfig 定义通用 APK 的生成方式。
实践要点: 优化配置直接影响安装包大小。例如 <uncompressNativeLibraries>true</uncompressNativeLibraries> 会使原生库保持压缩,减小用户下载体积,但增加解压耗时。

2.5 资源表(resources.pb)

每个模块都有一个 resources.pb,同时 AAB 根目录也有一份全局聚合资源表。其记录了:

  • 每个资源类型的 ID 范围(例如 0x7F010000-0x7F01FFFF 属于 base 模块)。
  • 每个资源的名称、类型、限定符(语言、密度、版本等)。
  • 资源条目在 split APK 中的归属(用于按资源维度拆分)。

通过 bundletool dump resources --bundle 可以输出所有资源的结构化信息,这对调试资源缺失问题至关重要。

2.6 清单合并规则

多个模块的 AndroidManifest.xml 在构建 APK 时合并成单一清单。合并遵循以下优先级:

  1. base 模块的清单作为基础。
  2. feature 模块的清单通过 <dist:module> 标签附加合并。
  3. 冲突属性(如 minSdkVersion)取最大值,<activity> 等组件直接合并。
  4. merge tools 标记:使用 tools:replace、tools:node="merge" 等控制合并行为。

最终清单中每个 <activity> 都会保留其所在模块的名称,Play Store 据此动态分配下载。

2.7 结构可视化:AAB 文件组织图

下图展示了 AAB 的核心架构,包含两个 feature 模块和一个 base 模块,以及全局配置文件:

Android App Bundle 内部结构 app.aab (ZIP) BundleConfig.pb base/ 模块 feature_map/ feature_pay/ dex/ res/ lib/ manifest/ resources.pb dex/ res/ manifest/ resources.pb dex/ res/ manifest/ 关键路径解析 • base/ 包含启动所需全部组件,必须存在。 • feature 模块按需下载,每个模块拥有独立清单和资源。 • BundleConfig.pb 控制优化策略,resources.pb 聚合资源条目。

2.8 模块分割规则与验证

Google Play 根据 AAB 中的模块信息生成多个 APK:基础 APK(包含 base 模块)、配置 APK(按密度、语言、ABI 拆分)、动态功能 APK(每个 feature 模块生成一个单独 APK)。开发者可通过以下命令验证分割结果:

# 生成所有 APK 到 output 目录
bundletool build-apks --bundle=/path/to/app.aab --output=app.apks

# 查看生成的 APK 列表
unzip -l app.apks | grep "splits/"

# 查看某个 feature 是否被正确提取
bundletool get-size --apks=app.apks --modules=base,feature_map,feature_pay
常见误区: 如果 feature 模块的 AndroidManifest.xml 遗漏 <dist:module> 标签,或者 dist:onDemand 属性与预期不符,则 Play Store 可能拒绝上传或导致动态交付失效。务必在构建后检查 bundletool dump manifest 输出的清单内容。

2.9 本章小结

AAB 文件结构是动态交付的物理基础。开发者需要理解:

  • base 模块与 feature 模块的目录差异。
  • BundleConfig.pb 如何控制优化行为。
  • resources.pb 和 manifest 合并是多 APK 生成的依据。