工程结构搭建
动态功能模块(Dynamic Feature Module)是 Android App Bundle 的核心扩展机制,允许将功能拆分为独立的模块,按需下发。本章将指导你完成从零搭建支持 SplitInstall 的 Android 项目,包括项目创建、模块添加、Gradle 依赖配置以及应用 ID 的设置。
2.1 动态功能模块的项目架构
一个支持按需加载的 Android 项目包含两类模块:Base 模块(即 app 模块)和若干 动态功能模块。Base 模块包含应用的公共代码、资源及 AndroidManifest;动态功能模块则封装独立的功能,通过 SplitInstallManager 按需下发。
| 对比项 | 常规模块 | 动态功能模块 |
|---|---|---|
| 打包方式 | 始终打包到 APK | 单独打包为 split APK |
| 安装时机 | 安装应用时一并安装 | 按需通过 Play Core API 下载安装 |
| 模块类型 | Android Library / Application | com.android.dynamic-feature |
| dist 配置 | 不需要 | 必须配置 distributions |
| 应用ID | 单一 applicationId | 基础 ID + 模块后缀 |
2.2 创建 Android 项目并添加动态功能模块
前提:Android Studio 4.0+,Gradle 6.8+。推荐使用 Android App Bundle 发布格式。
创建步骤:
- 通过 File > New > New Project 创建标准 Android 项目,选择“Empty Activity”。
- 项目创建后,右键点击项目根目录,选择 New > New Module > Dynamic Feature Module。
- 在向导中设置模块名称(如
feature_on_demand),指定 Base 模块 applicationId(通常为com.example.app),并勾选“Install-time inclusion”为 Never(按需安装)。 - 完成向导后,AS 会自动生成模块目录及
build.gradle,并修改根settings.gradle。
生成的动态功能模块 build.gradle 基础配置示例:
apply plugin: 'com.android.dynamic-feature'
android {
compileSdk 34
defaultConfig {
// 不要在此设置 applicationId,由 Base 模块提供
minSdk 21
targetSdk 34
}
}
dependencies {
implementation project(':app') // 依赖 Base 模块
}
2.3 配置 Gradle 模块依赖
动态功能模块必须通过 Base 模块分发,因此需要在 Base 的 build.gradle 中声明对动态模块的 implementation 依赖:
// app/build.gradle
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation project(':feature_on_demand')
// 其他依赖...
}
注意:只能使用
implementation,不能使用 api 或 compileOnly。同时确保 settings.gradle 已包含模块引用:
// settings.gradle
include ':app'
include ':feature_on_demand'
在动态功能模块的 build.gradle 中必须配置 distributions,指定模块名称用于 Play Core API 识别:
// feature_on_demand/build.gradle
android {
dynamicFeatures = [':feature_on_demand'] // 模块标识
}
2.4 设置基础与应用 ID
Base 模块的 applicationId 即应用唯一标识,动态功能模块不需要设置独立的 applicationId,而是使用 distinctApplicationId 或由 Play 自动生成。推荐做法:
- Base 模块:
android.defaultConfig.applicationId = "com.example.app" - 动态功能模块:在
build.gradle中通过distinctApplicationId指定模块后缀,但通常交由系统自动处理,仅需保证applicationIdSuffix不被使用。
若需要为动态模块指定不同的基本 ID(例如为了测试),可在 defaultConfig 中配置:
// 动态模块 build.gradle
android {
defaultConfig {
// 显式设置 distinctApplicationId(可选)
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
// 模块后缀会在基础 ID 上追加
}
}
}
常见的 ID 配置对照:
| 模块 | applicationId | 说明 |
|---|---|---|
| app(Base) | com.example.app | 主 ID |
| feature_on_demand | 自动继承 com.example.app 并追加后缀 | Play 管理 split ID |
| feature_ads | (同上) | 可直接使用 distinctApplicationId |
2.5 常见错误与调试
错误 1:Module not found
运行
原因:distributions 配置缺失或模块名不匹配。
解决:检查动态模块
运行
SplitInstallManager.startInstall() 时抛出 SplitInstallException,提示模块未找到。原因:distributions 配置缺失或模块名不匹配。
解决:检查动态模块
build.gradle 中 dynamicFeatures 的值,确保与 API 调用时传入的模块名一致。
错误 2:Gradle 同步失败 - “Unable to find module with Gradle path”
原因:
解决:在
原因:
settings.gradle 未包含动态模块。解决:在
settings.gradle 中添加 include ':feature_name'。
调试建议:使用
adb shell pm list features 查看当前已安装的 split APK。运行 App Bundle 构建时,可在 build/outputs/bundle/release/ 下检查生成的 .aab 文件,确认动态模块的 module.zip 已包含在内部。
完成上述配置后,项目结构已满足动态功能模块的构建和分发要求。下一步将实现 SplitInstall 的下载与安装逻辑。