2. Android App Bundle 的文件结构
2.1 核心概念:模块化发布单元
Android App Bundle(AAB)不是传统的 APK,而是一个标准化容器,内部按模块组织资源与代码。每个模块对应一组功能或分发条件,Google Play 在生成最终 APK 时会根据设备配置只选择需要的模块。AAB 文件实际上是 ZIP 格式,扩展名为 .aab,其顶级目录结构固定如下:
| 目录 / 文件 | 职责 | 分发角色 |
|---|---|---|
base/ | 应用的核心代码、资源、清单 | 所有设备必须包含 |
feature_*/ | 按需下载的功能模块 | 可通过 Play Feature Delivery 延迟或按条件下发 |
asset_pack/ | 大型资源包(纹理、音视频) | 通过 Play Asset Delivery 按需或即时分发 |
BundleConfig.pb | 元数据:版本、压缩选项、签名配置 | 构建工具和 Play 商店读取 |
BUNDLE-SIGNATURE | 可选的数字签名文件 | 验证完整性 |
关键区别:
base 是强制模块,feature_ 和 asset_pack 是可选模块,它们共同构成了“一次构建,智能拆分”的模型。
2.2 文件结构原理图解
2.3 生活化类比:可拆装的集装箱
想象一个国际货运集装箱(app.aab),内部被分成三个区域:
- base 就像集装箱的底盘和钢架——无论什么运输方式都必须有它,否则货物无法固定。
- feature_* 是货柜里的独立包装箱。买家可以只买 A 箱(基础功能)或同时买 B 箱(高级功能);商家按需发货,节省运费。
- asset_pack 是贴在集装箱外侧的专用消防设备包,只有运到特定港口才需要取出,且不占主货舱。
- BundleConfig.pb 相当于集装箱的运输清单和海关文件,告诉港口机器怎样拆包、哪些货物可以合并。
2.4 常见误区与关键区别
误区 1:
事实:
base 模块可以像普通 module 一样任意拆分事实:
base 是 AAB 的根模块,必须包含完整的 AndroidManifest.xml 和所有 mipmap-* 启动图标资源,否则 Play 商店拒绝上架。你不能将 base 设计为“空壳”,它必须包含应用启动所需的所有入口代码。
误区 2:
事实:必须遵循
feature_ 目录名称可以随意起事实:必须遵循
feature_<模块名> 格式,构建工具以此识别模块类型。若命名为 myfeature/ 而非 feature_myfeature/,Gradle 会将其视为普通资源目录而非动态功能模块,导致无法按需下发。
与 APK 的关键区别:APK 将所有代码和资源打包成一个扁平文件,而 AAB 通过模块目录清晰分离关注点。APK 中的 assets/ 对应 AAB 的 asset_pack/,但 AAB 的 asset_pack 可以独立配置压缩、安装时间(install-time / fast-follow / on-demand)。
2.5 自测练习题
-
题目 1:一个 AAB 文件是否可以不包含
base/目录?如果不可以,至少需要包含哪些强制文件?(提示:参考核心定义与 Play 商店要求)
- 题目 2:假设你有一个大型 3D 游戏,希望主 APK 不携带高精度贴图,而是在用户进入“画质设置”后按需下载。你应该使用哪个模块来存放这些贴图?请说明选择的理由。
答案参考
1. 必须包含
2. 使用
1. 必须包含
base/,且必须包含 AndroidManifest.xml、classes.dex 和启动图标资源。缺少任意一项都将被 Play 拒绝。2. 使用
asset_pack/(Play Asset Delivery)。因为贴图属于大型资源,不需要代码逻辑,且可以设置为 on-demand 或 fast-follow 模式。若使用 feature_* 则必须包含代码和清单,增加冗余。
2.6 应用边界说明
AAB 文件结构的设计目标是支持模块化分发和动态交付。以下是其适用范围与限制:
- 适用场景:大型应用(>150MB)、需要按条件下发功能(如国家、设备能力)、希望对 APK 大小进行精细控制。
- 不适用场景:纯库项目(因为没有 base 模块)、独立插件通过非 Google Play 渠道分发(因为 AAB 依赖 Play 商店的拆分过程)。
- 边界注意:所有
feature_*和asset_pack都必须在base模块的清单中通过<dist:module>声明,否则 Play 商店将忽略它们。构建时需确保 Gradle 插件版本 ≥ 3.6.0。