1. App Bundle入门
我第一次接触 App Bundle 是在一次线上事故之后。当时我们的 APK 已经快 80MB 了,用户抱怨下载太慢,特别是海外地区。后来我试了 Android App Bundle(AAB),发现它并不是一种新的安装包格式,而是一种 发布格式。说白了,你上传到 Google Play 的是 .aab 文件,用户真正下载到手机上的还是 APK——只不过这个 APK 是按需定制的。
Apple 那边早就用了类似思路(App Thinning),Android 这边直到 2018 年才推出。嗯,迟到了几年,但效果确实好。
AAB 的工作原理:Google Play 替你“切”包
你可以把 .aab 想象成一个原材料仓库。里面装着你所有的代码、资源、原生库、语言包等。用户点击安装时,Google Play 的服务端会根据用户的设备信息(屏幕密度、CPU 架构、语言等),只提取出需要的那部分,组装成一个“瘦身版”APK 交付给用户。
核心点:AAB 不是 APK 的替代品,而是 APK 的生成配方。
举个例子:你的应用同时支持 armeabi-v7a 和 arm64-v8a。用户 A 用的是 64 位手机,下载到的 APK 只包含 64 位的 so 文件;用户 B 用 32 位手机,则只拿到 32 位的 so。以前用传统 APK,你得把所有架构的 so 都塞进去,白白浪费存储和流量。
AAB vs APK:5 个核心区别
| 对比项 | APK | AAB |
|---|---|---|
| 用途 | 安装包(直接安装) | 发布格式(提交商店) |
| 能否直接安装 | 可以 | 不可以(无签名,不完整) |
| 文件大小 | 较大(包含所有资源) | 较小(模块化,但包含全部可能的资源) |
| 用户下载量 | 全量包 | 按需生成的瘦身包 |
| 动态分发 | 不支持 | 支持(动态功能模块、按需加载) |
说白了,APK 是成品,AAB 是半成品。你不可能把一个 .aab 文件通过 adb 直接安装到手机上——我当年第一次拿到 .aab 时还愣了半天,因为没有安装按钮。后来才明白,需要借助 bundletool 把它转成通用的 APK。
为什么 Google 要推 AAB?
理由很简单:减少用户下载量。Google 官方数据显示,使用 AAB 后应用的下载大小平均降低 20% 以上。你要是做过国际化应用,就知道这个数字有多香。我在印尼本地化的时候,当地用户很多还是 3G 网络,甚至 2G,少 10MB 安装包就能显著提高转化率。
另外,AAB 还引入了分阶段部署(Staged Rollout)。你可以给不同的用户群体(比如内测组、5% 的稳定版用户)颁发不同的签名密钥,然后在服务器端控制更新的节奏。这一点我们在后面章节会反复用,先记住这个概念。
小提示:国内应用商店目前大多不支持 AAB,所以如果你的应用只面向国内市场,暂时还是用传统 APK。但是做海外发行,AAB 已经成为必然选择——Google Play 从 2021 年 8 月起已经强制要求新应用必须使用 AAB 发布了。
AAB 的内部结构
我拆解过一个典型的 .aab 文件,它的内部跟 APK 大不相同。来看看关键目录:
base/
├── manifest/
│ └── AndroidManifest.xml
├── dex/
│ └── classes.dex / classes2.dex ...
├── res/
│ ├── drawable-mdpi/
│ ├── drawable-hdpi/
│ └── drawable-xhdpi/ ...
├── lib/
│ ├── armeabi-v7a/
│ └── arm64-v8a/ ...
├── assets/
├── root/
└── ...
注意到了吗?资源目录按密度、语言等维度拆分得很细。在打包成 APK 时,Google Play 会基于这个结构只选取与你设备匹配的条目。比如你的手机是 320dpi(xhdpi),那么 mdpi、hdpi 的图片就不会被打进最终的 APK 里。
还有一个重要的文件是 BundleConfig.pb,它指定了哪些模块是“按需”的,哪些是“随基座安装”的。这是分阶段部署的配置入口。
我曾经踩过的坑:多语言资源不全
有一次我测试 App Bundle 的沉浸式翻译功能,发现某些语言界面显示不全。排查了半天,发现是因为我漏掉了 playcore 打包规则中的一个配置。默认情况下,用户下载只包含他手机语言对应的资源字符串。如果我希望所有用户都能看到某个特殊语言的内容,必须在模块配置里强制保留。嗯,这个坑在后面第 15 章讲动态模块时会详细展开,这里你先有个印象。
为了避免这种问题,官方提供了 bundletool 来模拟不同设备生成 APK 并验证。
# 生成指定设备的 APK
java -jar bundletool.jar build-apks \
--bundle=my_app.aab \
--output=my_app.apks \
--ks=my_keystore.jks \
--ks-pass=pass:password \
--key-pass=pass:password
# 安装到设备
java -jar bundletool.jar install-apks \
--apks=my_app.apks
我通常会先用 --device-spec 参数指定一个 480dpi、英文、arm64-v8a 的虚拟设备来测试,确保切片逻辑正确。
你真正需要掌握的核心知识体系
为了让你一眼看清全貌,我把这一章的知识结构画成了图:
我的建议:刚开始不用去背 AAB 的内部结构表,你只要知道它的切片思想就够了。先动手用 Android Studio 打包一次 .aab,再用 bundletool 转成 APK 装到手机上跑跑看,比看十篇文档都管用。
注意:如果你使用 Instant App 或者 on-demand 动态模块,AAB 文件的大小上限跟 APK 不一样,部分内容不能超过 150MB。后面部署的时候我们会专门讲这个限制。