第3章 Gradle配置AAB构建:动态特性、bundle与feature依赖
Android App Bundle (AAB) 的构建核心在于 Gradle 的正确配置。本章系统讲解如何在 build.gradle 中声明动态功能模块、配置 bundle 约束、管理 feature 依赖关系,以及通过模块分割规则实现按需交付。掌握这些配置后,你将能构建出支持动态交付、条件分发和安装时分发的高质量 AAB 包。
3.1 开启 AAB 构建
在项目根 build.gradle 中引入 Android Gradle 插件(AGP 7.0+ 必须);在应用模块中设置 bundle 区块以启用 AAB 格式输出。
// 项目级 build.gradle
buildscript {
dependencies {
classpath "com.android.tools.build:gradle:7.4.2"
}
}
// app/build.gradle
plugins {
id 'com.android.application'
}
android {
// 可选:明确指定 AAB 为唯一产出
bundle {
language {
enableSplit = true
}
density {
enableSplit = true
}
abi {
enableSplit = true
}
}
}
从 AGP 7.0 开始,
bundle {} 配置默认启用,无需手动开启;但显式设置 enableSplit 可以控制资源拆分行为。3.2 动态功能模块声明
动态功能模块是一个独立的 Gradle 子模块,使用 com.android.dynamic-feature 插件。每个模块可以包含自己的代码、资源和清单,最终由 bundletool 打包为独立的 APK 切片。
// feature1/build.gradle
plugins {
id 'com.android.dynamic-feature'
}
android {
compileSdk 34
defaultConfig {
minSdk 21
targetSdk 34
}
}
dependencies {
implementation project(':app') // 必须依赖主应用
implementation 'androidx.core:core:1.12.0'
}
动态功能模块必须依赖
project(':app'),否则构建时会报“dynamic feature must depend on application”错误。3.3 bundle 配置与模块声明
在主应用 build.gradle 中,通过 dynamicFeatures 列表注册所有动态功能模块。同时可以在 bundle {} 内针对每个模块设置交付条件。
// app/build.gradle(完整配置)
android {
dynamicFeatures = [':feature1', ':feature2']
}
// 在 feature 模块的 AndroidManifest 中定义交付条件
<dist:module dist:instant="false">
<dist:delivery>
<dist:install-time /> <!-- 安装时分发 -->
<!-- <dist:on-demand /> <!-- 按需下载 -->
<!-- <dist:conditional>...</dist:conditional> -->
</dist:delivery>
<dist:fusing dist:include="true" />
</dist:module>
动态功能模块的交付条件在
AndroidManifest.xml 中由 <dist:delivery> 标签指定,而非 Gradle 配置。这是常见误区。3.4 dependencies 中的 feature 依赖
主应用模块无需在 dependencies 中显式添加 feature 依赖——dynamicFeatures 列表已经完成注册。但 feature 模块之间可以相互依赖,此时需要显式声明。
// feature2/build.gradle
dependencies {
implementation project(':app')
implementation project(':feature1') // feature2 依赖 feature1
}
当 feature 之间存在依赖时,bundletool 会把所有被依赖的模块一起打包到同一个 APK 切片中,避免运行时报 ClassNotFoundException。
3.5 模块分割规则与资源拆分
AAB 的资源拆分依赖 bundle {} 配置和 AndroidManifest 中的 <dist:module> 属性。以下表格对比三种常见交付方式的关键区别:
| 交付方式 | XML 标签 | 分发时机 | 代码/资源打包方式 |
|---|---|---|---|
| 安装时 (install-time) | <dist:install-time /> | APK 安装时一并下载 | 合并到 base APK 或独立 APK |
| 按需 (on-demand) | <dist:on-demand /> | App 运行时通过 PlayCore API 下载 | 独立 APK 切片,仅含该 feature |
| 条件分发 (conditional) | <dist:conditional>...</dist:conditional> | 满足条件(如国家、API 版本)时自动下载 | 根据条件生成不同变体 |
资源拆分原则:各 feature 模块的资源必须位于模块内,不可引用主模块的 R ID;为避免 ID 冲突,建议使用 tools:replace="android:label" 等合并策略。
3.6 常见错误及解决方案
- 错误:
Dynamic feature module must depend on the base application module
解决:确保 feature 的build.gradle中包含implementation project(':app')。 - 错误:
Manifest merger failed : Attribute application@label value=(..) from AndroidManifest.xml
解决:在两个模块的<application>标签上添加tools:replace="android:label"。 - 错误:
Duplicate class found in modules (e.g. support-annotations)
解决:使用implementation代替api,或在主模块中exclude group: '...'。 - 错误:
AAPT: error: style attribute '@android:attr/xxx' not found.
解决:检查 compileSdk 是否一致,确保 feature 模块也引用相同的主题。
上图展示了 Gradle 构建 AAB 时的核心依赖关系与打包流程。注意:主应用模块通过
dynamicFeatures 列表注册所有功能模块,各模块在 Manifest 中独立声明交付策略;最终的 bundletool 根据这些配置生成一个或多个 APK 切片。