Android App Bundle(AAB)是 Google Play 自 2021 年 8 月起对新应用强制要求的发布格式,也是同一个应用装在两台手机上体积可能完全不同的原因。你不再把编译好的 APK 直接交给 Google Play,而是提交一个 bundle,里面装着全部已编译代码、资源以及组装说明,由 Google Play 生成真正被安装到每台设备上的拆分 APK(split APKs)。

这一改动把许多决定从构建脚本搬到了 Play 侧:哪种 CPU 架构拿到哪些原生库、哪种屏幕密度拿到哪些图片、哪种语言拿到哪些字符串。它同时也带来了一组硬性体积上限——而且这些上限已经变了:base module 的上限不再是 200MB。仍按旧数字做方案的团队,要么把分发策略做得过度复杂,要么在上传时被一个看不出原因的体积错误卡住。

本文按你实际会遇到的顺序讲清 2026 年的全貌:bundle 里到底装了什么、当前的体积上限、拆分 APK 是怎么拼出来的、Play Feature Delivery 与 Play Asset Delivery 的区别、生成的 APK 用哪个版本号、如何用 bundletool 测试,以及上传前该跑的检查清单。


1. App Bundle 里到底装了什么

App bundle 就是你上传的 .aab 产物,用来替代 APK。Google 自己的说法很准确:它包含应用全部已编译的代码与资源,并且把 APK 的生成与签名交给 Google Play 完成。里面大致有四类内容:

bundle 本身永远不会安装到设备上。它是分发的源头,不是安装包。

2. 「拆分」对用户意味着什么

用户点击安装时,Play 会针对这台设备的具体配置生成一组 APK、完成签名,然后下发。常见的拆分维度有:

所以 Play Console 里的「下载大小」不是一个数字,而是横跨各种配置的一个区间;App size 页面会同时给出参考机型的数值和这个区间。用本地构建出来的单个 APK 判断整次发布,是安装转化率事后让人吃惊的常见原因。

3. 2026 年的体积上限

下面这些数字来自 Play Console 官方帮助文档,是应该拿来规划方案的版本。注意 base module 的上限早已不是老文章里写的 200MB。

与这些数字绑定在一起的还有四条约束:

一个历史遗留的坑:仍以普通 APK 形式交付的应用,不适用上面任何一条限制,而是继续沿用旧的 APK 规则——单个 APK 上限 100MB。如果上传报了一个像 2019 年才会出现的体积错误,先确认你上传的到底是不是 bundle。

4. 你需要的到底是哪一种机制

三种机制解决三类不同问题,混用会浪费数周时间。

5. Play Feature Delivery:安装时 / 按需 / 条件

功能模块在清单文件中声明三种下发模式之一:

  1. install-time(安装时):属于首次安装的一部分,用户无法跳过,会计入用户看到的体积。
  2. on-demand(按需):应用主动请求后才下载。代码里必须处理等待中、下载中、已完成和失败四种状态。
  3. conditional(条件):只有在设备满足你声明的条件(设备特性、用户国家、最低 SDK 版本等)时,才在安装时下发。

条件下发是团队最容易忽略的一种。只服务平板的功能模块,或者只在某个支付渠道落地的市场才有意义的模块,没有理由装在每一台设备上。

6. Play Asset Delivery:安装时 / fast-follow / 按需

资源包还支持纹理压缩格式定向,让 Play 按设备 GPU 实际支持的分发对应格式,而不是把全部格式都打进去。对游戏来说,这通常是单项收益最大的一次体积优化。

7. 生成的 APK 用哪个版本号

使用 bundle 之后,你不再为每个 APK 管理版本号。你只在 base module 里设置一个 versionCode,上传之后 Google Play 把它分配给由该 bundle 生成的所有 APK;同一次安装里的所有拆分 APK 共享同一个版本号。

带来的结果是「纪律」而不是「复杂」:要发新版本,就必须递增 base module 的 versionCode 并重新构建完整的 bundle;用户更新时,Play 会把设备上已安装的每个 APK 一起更新。由此有两条实践规则:

8. 签名:上传密钥与应用签名密钥

启用 Play App Signing 后,你上传的产物用上传密钥(upload key)签名,Play 再用应用签名密钥(app signing key)重新签名生成的 APK。签名配置只应该写在 base module 里。两件事经常把人绊住:

9. 发布前用 bundletool 测试拆分

Android Gradle 插件负责构建 bundle,bundletool 负责把它还原成具体设备的 APK,并在本地模拟 Play 的分发过程。Play 自己就是用同一个工具生成 APK 的,所以本地结果与线上行为高度一致。

# 生成覆盖所有支持设备配置的 APK 集合
bundletool build-apks \
  --bundle=app-release.aab \
  --output=app.apks \
  --ks=upload-key.jks --ks-key-alias=upload

# 只部署与当前连接设备匹配的拆分
bundletool install-apks --apks=app.apks

# 生成一个 universal APK 做快速自检
bundletool build-apks --bundle=app-release.aab --output=app.apks --mode=universal

# 打开本地测试,用于验证按需模块与资源包
bundletool build-apks --bundle=app-release.aab --output=app.apks --local-testing

--local-testing 会把相关元数据写入 APK 清单,让 Play Core 库改用本地拆分而不是去连 Play。不加这个参数,按需下载相关代码就无法脱离商店验证。若要针对特定设备生成规格,用 bundletool get-device-spec。

正式全量发布之前,内部测试轨道仍然是最省事的验证方式,可以确认真实安装是否解析到了正确的拆分,包括你关心崩溃率的那批低端机型。

10. 先看 App size 页面,再谈优化

应用有正式发布后,Play Console 会在「Monitor and improve → Android vitals → App size」里显示下载大小:参考机型的数值、跨配置的区间、你自定义对照组的同类比较、随时间变化的趋势,以及两个比体积本身更有价值的指标:

11. 上传前检查清单

  1. 上传产物是 .aab,不是 universal APK。
  2. base module 的 versionCode 只在一处递增。
  3. 上传密钥只配置在 base module 中,且密钥库有非单机备份。
  4. base module 压缩下载大小在 500MB 以内;若想避开移动数据体积提示,控制在 200MB 以内。
  5. 单个 feature module 在 500MB 以内;所有模块与安装时资源包累计在 4GB 以内。
  6. 单个 asset pack 在 1.5GB 以内;按需与 fast-follow 资源包累计在 30GB 以内。
  7. asset pack 数量不超过 100,功能模块数量按最低支持版本满足 100 或 50 的建议值。
  8. 应用超过 1GB 时,最低支持版本为 API 21 或更高。
  9. 按需功能通过 Play Core 库实现,并显式处理等待、下载中与失败状态。
  10. 存在多种 GPU 格式时,为资源包开启纹理压缩格式定向。
  11. 已用 bundletool install-apks 在至少一台低端机与一台 arm64 机器上验证,并对每条按需路径跑过 --local-testing。
  12. 发布上线后回看 App size 页面,包括剩余空间不足 2GB 的两项指标。
  13. 数据安全表单与内容声明仍然与新增模块实际收集的数据一致。
  14. 商店页面的文案与截图描述的仍是用户现在真正下载的版本,而不是你本地测试用的 universal 构建。

12. 只在发布之后才暴露的七种失败

  1. 按需模块始终不下载:Play Core 的接入假定请求一定成功,没有为失败或被取消的请求写重试路径。
  2. 安装时资源包让商店页体积暴涨:一次内容更新之后安装转化率下滑,而代码一行未改。
  3. 条件模块装到了不满足条件的设备上:条件写在了错误的清单文件里。
  4. 版本号冲突:CI 给 bundle 打版本号,而构建文件里还留着按 ABI 生成的旧方案。
  5. 密钥签名错误:更换密钥库后没有同步更新 base module 的配置。
  6. 弱网首次启动失败:应用首屏依赖一个还没下载完的 fast-follow 资源包。
  7. 数据安全表单不一致:新拆出的模块里落进了新的 SDK,但没有人重新声明。

13. KappS 在这里做什么

体积与下发方式,和开发者账号、付款资料、税务信息处在同一条运营链上:任何一环都可能悄悄卡住一次发布。KappS 帮助开发者在这条链上准备并提交合规材料,包括 bundle 与下发配置的复核——因为在安装时资源包和 fast-follow 资源包之间做选择,衡量单位是安装转化率,而不是兆字节。

我们不做的,是绕开商店。体积上限、下发声明、数据安全答案,都是 Google 会拿你实际提交的产物去核对的;一个声称了 bundle 并不会做的事的商店页面,通向的是被拒的发布或者被停用的账号,这不是我们提供的服务。真正的办法只有一个:如实构建 bundle,如实声明它包含什么,并尊重那些上限。

来源(Google 官方文档):About Android App Bundles(developer.android.com/guide/app-bundle);Play Console 帮助中心「优化应用体积并遵守 Google Play 体积上限」(support.google.com/googleplay/android-developer/answer/9859372);Configure the base module;Play Asset Delivery;Play Feature Delivery;bundletool(developer.android.com/tools/bundletool)。