首页 / 资讯中心 / 文章详情

Android App Bundle(AAB)打包全流程:从签名到上架实践指南

Android App Bundle(AAB)打包全流程:从签名到上架实践指南 ★ FEATURED ARTICLE
1. 打包格式换血为什么AAB成了上架的唯一出路先说个背景。从2021年8月开始Google Play就强制要求新应用必须使用Android App Bundle格式提交APK上传通道彻底关闭。也就是说只要你的目标市场包含Google PlayAAB就不再是“要不要用”的选项而是唯一的通行证。那AAB到底是什么一句话概括它不再是一个直接安装到手机上的文件而是Google Play用来“按需定制”APK的原材料。开发者上传AAB之后Google Play会基于它自动生成不同屏幕密度、不同CPU架构、不同语言版本的专属APK用户在下载时拿到的其实是一个从AAB里动态切出来的瘦身包。听起来很魔法但本质并不复杂。AAB的完整名称是Android App Bundle.aab内部结构里包含了base模块、动态功能模块、资源表、DEX文件、原生库等所有编译产物。Google Play拿到这个“半成品”之后结合用户的设备参数动态拼装出只含该设备所需资源的最小安装包这一步在内部会拆成base APK、config APK、split APK等多个分片。换个生活化的类比AAB就像是餐厅后厨的“总菜谱”里面写着所有食材和做法Google Play是为你量身定做的厨师。用户下单时厨师只挑选这位顾客需要的食材做菜不会把门店整个后厨都端上桌。相比以前一个APK把所有架构arm64-v8a、armeabi-v7a、x86的资源、所有屏幕密度的图片、所有语言翻译全打包进去AAB天生就是省体积的。从实际收益看我以前维护的一个工具类App合入两张370MB左右的高清插画资源后整体体积从APK时代的85MB降到了AAB下载时的58MB。这30%的降幅对用户转化率的影响是肉眼可见的尤其是海外地区很多用户还用着仅剩几百MB空间的入门级手机包体每小一分下载转化概率就高一分。不过AAB也有一个很多人忽略的代价它要求你彻底接受“Google Play帮你分发”这个设定。你无法再依赖传统的APK拖拽安装测试也无法轻易绕过Google Play的签名体系。这也是这篇文章要解决的痛点——从配置、打包、测试到上架把AAB全链路走通。2. 打包之前必须先搞定的四件事2.1 签名体系想清楚谁是你的“根密钥”AAB和APK一样上传前必须签名。但和APK时代不一样的是Google Play现在强烈推荐你开启Play App Signing功能。通俗理解就是你把“上传密钥”的签名给Google Play一份Google Play自己手里的“应用签名密钥”才是最终用户手机上安装包的有效签名。这意味着什么如果你的上传密钥丢了通过Play Console重新生成即可App还能继续更新但应用签名密钥是你整个应用身份的根一旦泄露或丢失你只能被迫换包名重新上架所有用户数据全部归零。所以Google Play会要求你自己生成并保管好应用签名密钥它只保存公钥。实际经验我一般会生成两套密钥上传密钥用于日常CI/CD构建时给AAB签名应用签名密钥则离线保存在加密U盘里只在需要换上传密钥时才接触。无论你的团队多小都不要让同一个密钥承担两种角色也别把应用签名密钥上传到任何云端服务、代码仓库、共享网盘里。当你第一次在Play Console上传AAB时系统会引导你注册Play App Signing那时候你会看到Google生成的一个签名密钥对。注意如果你是从原有APK迁移过来的Google会给你一个导出加密密钥的机会把原APK的签名迁移到AAB新体系上这一步一定要在旧密钥还能用时完成不然老用户更新会变成“签名冲突”的直接翻车现场。2.2 版本号与版本名AAB上传的隐形门槛AAB的versionCode必须是整数这是Android的老规矩但AAB时代有个特殊坑Google Play要求版本号必须持续递增而且同一应用的所有跟踪轨道中不能出现低于已发布版本的versionCode。一旦上传回滚版本或者误传低版本号控制台会直接拒绝且没有任何强制覆盖入口。我踩过的坑是在一次灰度发布中手动把一个分支的versionCode调小了几百结果上传时Play Console直接报错“Version code X has already been used”。那次只能重新构建一次才把发布流程救回来。所以现在我把版本号统一交给CI/CD管道管理每次构建前由脚本读取上一个大版本号并递增而不是靠开发者在build.gradle里手改。versionName倒是无所谓随便命名但建议留给版本管理系统标记比如用git短哈希、构建序号或日期方便日常排查。Google Play虽然不校验versionName的唯一性但你在崩溃分析、用户反馈平台里筛日志时一个混乱的versionName会非常难用。2.3 分渠道拆包与语言资源策略AAB的优势建立在合理拆分之上但拆分策略没配好反而会带来意想不到的问题。先说资源拆分。AAB默认会通过android.bundle配置来拆分语言资源、屏幕密度和ABI。如果你的App有中文简体、中文繁体、英语、日语等多语言全部资源一起打进AAB里没问题Google Play会根据用户手机语言自动分发对应语言资源。可这里有个坑如果用户后续在系统里切换语言Google Play会动态下发新语言资源这个过程需要网络而且首次切换会有一定延迟。所以涉及大量图片资源的App要评估是否有必须在运行时切换语言的场景。如果有建议保留部分核心资源在base模块中而不是全部丢给Google Play去按需分发。ABI拆分方面2021年之后Google Play基本只需要arm64-v8aarmv7和x86的用户占比已经极低。如果你的原生库同时支持多架构默认建议直接过滤掉x86和armeabi避免AAB文件膨胀。但前提是你确认自己的用户设备分布可以通过Play Console的设备报告查看别拍脑袋决定。2.4 动态功能模块要不要用什么时候用AAB真正的杀手级能力是动态功能模块Dynamic Feature Module它允许你把一些低频使用的大功能做成按需下载用户用到时才临时拉取实现“秒开”的轻盈体验。比如一个大型App里的增强现实相机功能、特定游戏模式、超高清素材包都很适合放进动态功能模块。但我的建议是新手不要第一版就冲动态功能模块。原因很简单它引入的复杂度远超普通人预期——你需要处理SplitCompat兼容库、模块间资源引用、模块卸载状态、开发者自己维护的服务器等等任何一个环节出问题都可能导致用户卡在“功能不可用”的困境里。如果你是刚切换到AAB先把基础模块的拆分跑通后面再针对实际反馈决定要不要上动态功能。多数产品在AAB的基础拆分上就已经拿到了可观的体积收益没必要为了追新而增加发布链条的长度。3. 从Gradle到大盘实操打包AAB全流程3.1 build.gradle配置焦点在bundle块现在假设你已经用Android Studio创建好项目我们直接进入配置文件环节。以Groovy DSL为例最常见的构建配置是android { compileSdk 34 defaultConfig { applicationId com.example.demo minSdk 21 targetSdk 34 versionCode 10010 versionName 1.0.10 } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile(proguard-android-optimize.txt), proguard-rules.pro signingConfig signingConfigs.release } } bundle { language { enableSplit true } density { enableSplit true } abi { enableSplit true } } }bundle块是AAB独有的配置三个子块分别控制是否拆分语言资源、屏幕密度资源和CPU架构资源。默认三个都是true一般不用动。有一点必须特别提醒如果你启用了minifyEnabledR8混淆一定要在proguard-rules.pro里精确配置Keep规则特别是动态功能模块、反射调用、注解处理器生成的类。AAB模式下拆出来的每个分片APK都需要单独执行混淆映射如果Keep规则不全很容易出现某个分片APK崩溃但本地测试又复现不了的情况。签名配置如果你希望通过Android Studio构建按钮直接打出Release AAB在File - Project Structure - Signing Configs里配置好keystore路径和密码。也可以用更干净的做法在gradle.properties里用环境变量引用密钥信息避免硬编码到版本库。例如signingConfigs { release { storeFile file(System.getenv(KEYSTORE_PATH)) storePassword System.getenv(KEYSTORE_PASSWORD) keyAlias System.getenv(KEY_ALIAS) keyPassword System.getenv(KEY_PASSWORD) } }3.2 生成AAB三种方式看场景最直观的方式是Android Studio工具栏的Build - Build Bundle(s) / APK(s) - Build Bundle(s)构建产物在app/build/outputs/bundle/release/app-release.aab。如果你在命令行或CI环境里用Gradle Task./gradlew bundleRelease这个任务会生成经过签名、压缩对齐但AAB的压缩对齐方式和APK不太一样、带元数据信息的完整AAB文件。如果只需要调试用途的未签名包可以跑bundleDebug。第三种方式是从已有APK反向生成AAB虽然Google官方说AAB和APK互转并非完全保真但在某些迁移场景例如你维护一个很老的工程一时半会儿没法用新版Gradle构建AAB官方也提供了一种借助Android Studio的迁移向导完成转换。不过我不建议太依赖这个路径它容易丢失动态功能模块配置最好还是从源码直接构建。构建完成后强烈建议做一次“本地安装验证”再上传这一步后面会专门讲。3.3 用bundletool验证AAB内容bundletool是Google官方推荐用来操作AAB的命令行工具。你可以在GitHub releases页面下载jar包也可以从Android SDK的cmdline-tools里调用。最常用的验证命令是java -jar bundletool.jar get-size total --apks/path/to/app.apks但在此之前你需要先通过build-apks生成一组APK集合java -jar bundletool.jar build-apks --bundle/path/to/app-release.aab --output/path/to/app.apks --ks/path/to/upload.keystore --ks-passpass:yourpassword --ks-key-aliaskeyalias --key-passpass:keypassword生成后的.apks其实是一个zip包里面包含所有可能分发的APK副本。你可以解压查看会发现存在多个目录比如splits/base-master.apk、splits/base-arm64_v8a.apk等。这时你就直观理解了AAB的切分逻辑。验证完毕之后还可以用bundletool做一次设备安装模拟java -jar bundletool.jar install-apks --apks/path/to/app.apks --device-idemulator-5554这个命令会把符合当前模拟器/设备配置的APK分片推到设备上并安装成功效果等同于用户在Google Play的下载安装行为。它特别适合在发布前做一次冒烟测试比先把包传到内测轨道再下载要快得多。3.4 打包过程中的常见坑汇总我在处理AAB构建时碰到过几个频率很高的坑集中列出来坑一bundleRelease跑完发现AAB文件极小大概率是资源被错误混淆或排除。常见原因是shrinkResources和minifyEnabled同时开着且Keep规则缺少对某类资源的保护。排查方式是打开AAB文件查看res目录是否存在别只看总大小。坑二Gradle版本和Android Gradle Plugin版本不匹配导致AAB无法生成。AGP 7.0以上配Gradle 7.0AGP 8.0对应Gradle 8.0这些组合表格在Google官方文档里写得很清楚升级时不要只升级AGP而忘了Gradle wrapper。坑三AAB过大但本地APK不大。这通常是原生库多架构未过滤导致的。检查build.gradle里的abiFilters配置比如只保留arm64-v8a。也可以打开AAB的根目录看看lib文件夹下是否同时包含多个ABI目录。坑四上传后提示“上传的AAB签名无效”。99%的原因是上传密钥输了错误密码或alias或者签名配置文件里的路径是相对路径但在CI里工作目录变了。建议在打包命令后打印keystore信息做核对。4. Play Console上传与发布不只是拖拽文件4.1 创建应用与开启Play App Signing在Play Console里点击“创建应用”填写应用名称、默认语言、应用类型等基本信息后进入“应用版本”页面。首次上传AAB会触发Play App Signing注册流程Google会给你生成应用签名密钥并给你两个选项选项AGoogle自己管理应用签名密钥升级密钥选项B您自行管理应用签名密钥。选A省心但万一Google出问题你的应用会跟着受影响选B更安全但你必须把密钥放在安全的地方。我的选择是B严格遵守密钥隔离原则。注册完成后Play Console会显示一份上传密钥证书的指纹你需要把它配置到应用服务端如果配过API key或应用内校验和第三方SDK后台例如推送服务确保它们是同一套签名。4.2 创建发布轨道内测、公开测试还是正式版Google Play的发布轨道分为内部测试、封闭式测试、开放式测试和生产环境。你可以把同一个App用一个AAB发布到多个轨道。内部测试轨道适合通过邮件列表邀请少数测试者最多支持100人不需要审核就能发布。封闭式测试适合通过Google Group或Cloud Game服务管理一定规模的测试者开放式测试则是面向所有用户公开的Beta渠道一般用来做大范围回归验证。实际操作中我会先用内部测试轨道验证AAB安装、登录、支付流程然后用开放式测试轨道做灰度验证确认没有明显问题后再升到生产。每个轨道上传AAB时都要检查版本号是否与线上冲突。上传细节上AAB文件大小限制是150MB超过的话需要借助Play Feature Delivery的额外标准比如使用Play Asset Delivery交付大体积资源。这又回到动态功能模块的话题但一般休闲游戏或普通App不会触顶。4.3 定价、内容评级与商店信息在正式发布前Play Console会要求你填完商店信息、内容评级问卷、目标受众和隐私政策等。这些不是本文重点但有一点值得注意内容评级问卷如果填错可能导致App在部分国家或地区被隐藏。特别是涉及用户生成内容UGC的App建议照实勾选“允许用户互相交流”否则审核可能被驳回。商店信息的短描述和长描述里尽量把核心功能和体积优势写出来AAB带来的小体积本身就是很好的卖点。比如“安装包更小启动更快”这类语言在面向部分低端设备市场时很有吸引力。4.4 正式发布与更新策略发布到生产轨道后Google Play审核通常会在几小时内完成但特殊情况下可能拖到一两天。如果审核被拒一般会在邮件里说明原因你可以修改后在Play Console里重新提交同一个AAB。这里有个重要经验Google Play审核通过不等于“全量发布”你在Play Console里可以把发布范围设置为“逐步发布”比如首日1%、第二日5%、第三日20%观察崩溃率和用户评价后再逐步放量。AAB的多个分片APK在这种场景下依然有效用户拿到的仍是按需定制的包体不会因为阶段发布而改变体积。更新策略上任何时候提交新版本都要确认新versionCode大于所有已发布版本应用签名密钥和上传密钥都没有变化除非主动迁移混淆映射文件已备份因为后续要从Play Console下载去混淆映射来排查崩溃日志5. 上线之后的监控、排查与常见异常5.1 用Play Console监控AAB分片表现很多人以为发布完就结束了其实AAB模式下的监控和APK时代有很大区别。你需要关注的不再是一个整体安装包的崩溃率而是不同分片APK各自的崩溃报告。Play Console的Android Vitals页面会按分片展示崩溃和ANR数据如果某个ABI或某个密度的分片崩溃率异常就能精准定位到资源或原生库问题。实际操作中我会定期导出AAB的拆分统计看看实际分发到用户设备上的分片APK数量分布这能反向评估你的资源和ABI过滤策略是否合理。如果一个完全没必要保留的x86架构分片占了大量下载就说明该清理掉这部分资源了。5.2 常见异常问题速查把我在多个项目里遇到的高频问题整理成一个速查表问题现象可能原因解决方法上传AAB时提示版本号已存在versionCode低于或等于线上版本在build.gradle里调大versionCode后重新构建下载安装时提示“安装包无效”AAB签名与Google Play记录不一致检查上传密钥和应用签名密钥是否匹配必要时做密钥迁移解锁新语言后资源加载慢language split把资源拆到分片运行时动态下载核心语言资源放回base模块调整bundle配置动态功能模块点击无反应SplitCompat未正确初始化或模块未安装确认Application中调用了SplitCompat.installR8混淆后某个页面白屏反射或注解类被混淆移除补全Keep规则后重建上传包超过150MB上限base包过大考虑拆分动态功能模块或用Play Asset Delivery托管资源5.3 崩溃日志解析时的AAB地图AAB时代排查崩溃日志时混淆映射文件显得更重要。因为Google Play分发的APK和你本地构建的APK并不完全一致崩溃日志里的类名和方法名如果未被去混淆就需要你手动用Mapping文件做映射。建议每次发布前把app/build/outputs/mapping/release/mapping.txt打包进公司内部的发布系统对应版本号归档。我遇到过几次崩溃日志里只有a.b.c.d这种混淆名没有映射文件就只能干瞪眼的情况现在每次构建都会强制归档。如果你希望省事点可以在Play Console里勾选“自动上传去混淆映射文件”但为了多一层保障本地存档永远不会亏。5.4 AAB的测试人员管理窍门内部测试轨道里测试人员必须通过Gmail账号加入白名单。如果在企业环境里测试员可能不想用私人邮箱测试你也可以把内部测试和封闭式测试结合起来用Google Group管理一组测试账号。发布内测版本时选择“内部测试轨道”并点击“创建新版本”上传AAB后把下载链接发给测试者。内部测试的下载地址通常是play.google.com/apps/testing/包名测试者需要用加入白名单的账号登录才能看到。要注意内部测试链接不会经过审核某种意义上这个“瞬发”体验反而最接近开发者的日常调试循环。6. 我的几点亲身经验AAB切换的正确打开方式从APK时代迁移到AAB的这几年里给我印象最深的不是体积减少了多少而是整个发布思维模式的转变。APK时代你可以自己下载文件拿去任何应用市场包体统一逻辑简单。AAB时代Google Play变成了你唯一的核心分发渠道你要接受“同一个应用在不同设备上安装的内容可能不同”这个事实并针对性地设计测试矩阵。我建议的切换路径是第一步先在开发环境里用同一套源码分别打APK和AAB把两者解压对比确认AAB内的资源、DEX和Manifest没有异常。第二步在内部测试轨道发一个AAB包让测试同学用至少三种不同分辨率、两种以上ABI的真实设备安装重点看下载速度、启动速度和关键功能是否正常。第三步逐步放量用Play Console的“逐步发布”控制在1%到5%的用户量观察几天的崩溃曲线后再全量。如果你手上维护着老旧的APK版本尤其注意老用户能否顺畅升级到AAB版本。我曾经处理过一个老项目原始签名密钥是弱口令保护发布年头又久差点在迁移时丢掉。后来通过Play Console的密钥导出流程保住了老签名整个过程花了一整个下午真正体会到了提前规划签名体系的价值。最后再分享一个小技巧在本地调试AAB时不要去Google Play下载正式包因为每次等待后台生成APK集合再下载耗时太长。直接用它生成的.apks包和bundletool命令做本地安装体验几乎等同于Google Play的分发逻辑但能节省大量等待时间。AAB不是银弹它是一个需要配合工程习惯、发布流程和监控体系才能发挥价值的整套方案。如果你正准备迁移上去建议从一个小型App或一个独立渠道开始把签名、打包、测试、监控的闭环跑顺然后再扩大范围。等你真正上手了就会发现它对包体治理的推动力是APK时代很难做到的。
阅读完成 · 觉得有帮助?
咨询建站