第2章 App Bundle原理:打包拆分、模块化、签名分发

2.1 什么是Android App Bundle

Android App Bundle(.aab)是Google于2018年推出的官方发布格式,它取代了传统APK成为Google Play商店的默认上传格式。AAB本身不是可安装包,而是包含所有编译后代码和资源的容器,由Google Play商店根据用户设备配置(屏幕密度、CPU架构、语言等)动态生成并分发优化的APK分片(Split APK)。

核心优势:减小初始安装包体40%以上,按需下载模块,实现动态交付。

2.2 APK vs AAB:关键差异对比

对比维度 APK AAB
交付格式 单一可安装包 发布容器,需平台转换
包含内容 所有资源配置无条件打包 仅保留原始代码和资源,不冗余
设备适配 由开发者手动分包(多APK) 由商店自动分发最优分片
动态模块 不支持运行时按需安装 通过SplitInstall API原生支持
签名方式 直接对APK签名 对AAB签名,分片继承签名
文件后缀 .apk .aab

2.3 App Bundle构建与分发流程

下图展示了从源代码到最终设备安装的完整链路:

App Bundle构建与分发流程 App Bundle 构建与分发流程 源代码 & DEX 原生库 & 资源 Android Gradle Plugin (AGP 打包) App Bundle (.aab) Google Play 按需拆包 & 分发 (Split APKs生成) 设备安装模块 基础模块 + 配置模块 + 特性模块 (按设备屏幕密度/CPU/语言拆分) 模块化拆分依据 屏幕密度 · CPU架构 · 语言

2.4 打包拆分原理

Android Gradle Plugin(AGP)在构建AAB时,会将应用划分为多个逻辑模块,每个模块最终输出独立的Split APK。拆分粒度包括:

  • Base模块:所有设备都需要的核心代码和资源(如Application类、通用资源)。
  • Config模块:按屏幕密度(mdpi/hdpi/xhdpi等)、CPU架构(armeabi-v7a/arm64-v8a/x86)、OpenGL ES纹理等拆分。
  • Language模块:按系统语言分离字符串资源。
  • Feature模块:开发者通过com.android.dynamic-feature插件声明的按需功能。
提效技巧:使用bundletool的extract-apks命令可本地验证拆分结果,无需上传商店。
java -jar bundletool.jar build-apks \
  --bundle=app.aab \
  --output=app.apks \
  --ks=my-release-key.jks \
  --ks-pass=pass:123456 \
  --ks-key-alias=myalias \
  --key-pass=pass:123456

2.5 模块化结构配置

在项目根目录的settings.gradle中声明所有模块:

include ':app'
include ':feature_camera'
include ':feature_ar'
include ':feature_payments'

在基础模块(app)的build.gradle中引用动态特性模块:

// app/build.gradle
android {
    dynamicFeatures = [':feature_camera', ':feature_ar']
}

dependencies {
    implementation project(':feature_camera') // 作为动态特性,运行时安装
    implementation project(':feature_ar')
}

动态特性模块自身需声明为动态特性插件:

// feature_camera/build.gradle
plugins {
    id 'com.android.dynamic-feature'
}
android {
    compileSdk 33
    defaultConfig {
        minSdk 21
    }
}
dependencies {
    implementation project(':app')
    // 其他依赖
}

2.6 签名与分发

AAB的签名流程与APK类似,使用JKS签名文件。关键步骤:

  1. 生成签名密钥(keytool)
  2. 配置build.gradle签名信息或使用-ks参数通过jarsigner手动签名
  3. 通过bundletool构建APKS集并签名

手动签名示例(使用jarsigner):

jarsigner -keystore my-release-key.jks \
  -storepass 123456 \
  -keypass 123456 \
  -signedjar app_signed.aab \
  app.aab myalias

自动签名(推荐用于本地测试):

// 使用bundletool一次性签名
bundletool build-apks \
  --bundle=app.aab \
  --output=app.apks \
  --ks=my-release-key.jks \
  --ks-pass=pass:123456 \
  --ks-key-alias=myalias \
  --key-pass=pass:123456
关键注意:Play商店要求AAB使用应用签名密钥(App Signing Key)进行签名。上传至Play控制台时,建议启用Google Play App Signing,让Google托管应用签名密钥,防止密钥丢失导致无法更新。

2.7 常见错误与优化

  • Error: No matching variant of …:动态特性模块与基础模块的minSdkVersion、targetSdkVersion不一致。确保所有模块版本对齐。
  • Duplicate resources:动态特性模块不应包含与base模块重复的资源。使用dist标签筛选或重命名。
  • Split APK安装超时:特性模块体积过大。建议单模块不超过150MB,使用On-Demand模式分块下载。
性能优化建议:
• 将大型资源(3D模型、高清贴图)单独抽离为按需特性模块。
• 使用SplitInstallManager的deferredInstall在后台静默下载非关键模块。
• 对语言资源启用android.bundle.language.enableSplit = false避免过多小APK。