1. AAB与APK的核心区别

Android App Bundle (AAB) 是 Google 于 2018 年推出的官方发布格式,取代了传统的 APK 成为 Play Console 的默认上传格式。虽然两者最终都在设备上安装为 APK,但它们在构建、签名、分发和安装阶段存在根本性差异。理解这些差异是掌握动态交付技术的基础。

对比维度APKAAB (App Bundle)
打包格式单个 ZIP 压缩包,包含所有资源、代码和原生库;所有 DEX 合并为一个或多个 classes.dexZIP 容器,内部按模块和配置拆分为独立条目(如 base/、feature_xxx/、BUNDLE-METADATA/);resources.pb 代替 resources.arsc
签名机制使用 jarsigner 或 apksigner 对整个 APK 文件签名,v1/v2/v3 均可使用 apksigner 对每个独立条目签名(AAB 本身不签名),最后通过 bundletool 生成签名后的 APK 时再统一签名
安装过程直接安装单个 APK 到设备,所有内容一次性安装Google Play 或 bundletool 根据设备配置(屏幕密度、ABI、语言等)从 AAB 提取并合成一个或多个优化的 APK(称为 APK Set),再安装
多APK生成策略手动维护多个 APK(如 xhdpi + arm64、xxhdpi + x86 等),需人工匹配设备配置自动按维度(密度、ABI、语言、API 等级、特性模块)拆分为多个 APK,bundletool 按需合成,开发者无需手动管理多个版本
关键洞察:AAB 并非一个可安装格式,而是一个包含所有可能资源的“母版”。Google Play 商店在分发时动态生成最适合用户手机的 APK,使得应用体积平均缩小 15%–30%。
AAB → 多 APK 生成与安装流程 Android App Bundle (.aab) 模块化容器(base + 动态 feature) Gradle 构建 → 签名 (apksigner) 模块分割 + resources.pb + 签名元数据 bundletool / Play Console 根据设备配置合成 APK Set (.apks) 动态生成的多 APK(每个设备只收到匹配的) Base APK Config Split APK (密度/ABI/语言) Dynamic Feature APK (按需安装) 安装到 Android 设备 Split APK 由 PackageManager 合并为单一应用 对比要点 • AAB 不分发,只上传 • 设备仅收到所需 APK • 签名在合成时完成
动手实践:在 Android Studio 中创建一个新项目,使用 Build → Build Bundle(s) / APK(s) → Build Bundle(s) 生成 .aab 文件。然后通过命令行 java -jar bundletool.jar build-apks --bundle=app.aab --output=app.apks --ks=my.keystore 验证 APK Set 的生成过程。

1.1 打包格式的架构差异

  • APK:所有资源平铺在 ZIP 根目录,resources.arsc 包含所有字符串、颜色、尺寸等资源 ID 映射;DEX 文件受 64K 方法数限制,需要 MultiDex。
  • AAB:使用 resources.pb(Protocol Buffers)代替 resources.arsc,支持更高效的增量编译和资源压缩;模块目录结构清晰,允许多个 DEX 文件按模块拆分。
  • 动态交付关键:AAB 的 base/ 目录包含基础模块,feature_xxx/ 目录包含按需分发模块,每个模块都可以独立配置安装条件。
构建配置示例(build.gradle):启用 Android App Bundle 并声明一个动态特性模块:
// 应用级 build.gradle
android {
    bundle {
        language {
            enableSplit = true
        }
        density {
            enableSplit = true
        }
        abi {
            enableSplit = true
        }
    }
}
// 特性模块 build.gradle (dynamic feature)
android {
    defaultConfig {
        moduleId = "feature_camera"
    }
}

1.2 签名机制的玩法区别

  • APK 签名:对整个文件内容计算摘要,签名后存储在 APK 的 META-INF/ 目录中;v1 使用 JAR 签名,v2/v3 使用 APK Signature Scheme,覆盖整个 ZIP 内容。
  • AAB 签名:上传到 Play Console 的 AAB 本身不包含签名,仅包含签名元数据(BUNDLE-METADATA/com.android.signing/)。Google Play 合成 APK 时使用开发者上传的密钥信息进行重新签名。
  • 本地测试:使用 bundletool 时需要显式指定 keystore,否则生成的 APK 无法安装(INSTALL_PARSE_FAILED_NO_CERTIFICATES)。

1.3 安装过程:从 AAB 到设备

  1. 上传:开发者将 .aab 文件上传至 Google Play Console。
  2. 生成 APK Set:Play 商店(或 bundletool)读取 AAB 的 BundleConfig.pb,根据设备提交的屏幕密度、ABI、语言、API 等级等参数,从 AAB 中提取匹配的资源,合成一个 .apks 压缩包。
  3. 签名:对每个生成的 split APK 使用 App Signing by Google Play 或开发者自己的密钥进行签名。
  4. 安装:设备接收到一组 split APK(base + 配置 split + 按需 feature),PackageManager 将其视为同一应用,合并安装到 /data/app/ 下。

1.4 多 APK 生成策略对比

维度传统 APK 策略AAB 策略
屏幕密度手动维护 mdpi/hdpi/xhdpi/xxhdpi 等多版本自动生成密度分片,设备仅下载对应密度的资源
ABI分别打包 arm64-v8a / armeabi-v7a / x86_64AAB 包含所有原生库,bundletool 按需提取
语言全量包含,APK 体积大可配置按语言拆分,设备只下所需的语言资源
动态特性不原生支持,需自建插件框架(如 Loader)通过 <dist:module> 在 AndroidManifest 中声明安装条件(install-time / on-demand / conditional)
常见陷阱:如果 build.gradle 中未正确启用 bundle { ... enableSplit = true },可能导致 Google Play 仍然合成全量 APK,失去动态交付的体积优势。另外,bundletool 生成的 APK Set 默认不会包含签名的 APK,必须配合 --ks 参数或使用 --mode=universal 生成通用 APK 用于测试。

1.5 模块分割规则与资源代码拆分

AAB 的模块分割遵循以下规则:

  • 资源拆分:按 density、language、mcc、country、screen 等限定符分割,每个 split APK 只包含该设备需要的资源文件。
  • 代码拆分:DEX 文件按模块拆分,base 模块包含应用入口和核心代码,dynamic feature 模块的代码只在按需下载后才可用。
  • 原生库:按 ABI 拆分,设备只会获取匹配的 lib/ 目录。
  • 安装时 vs 按需 vs 条件分发:
    install-time:随 base APK 一同下载安装(合并为初始 APK);
    on-demand:用户运行时按需下载;
    conditional:根据设备特性(如国家、API 级别、硬件功能)决定是否自动安装。