第3章 构建拆分模块:创建与配置
动态交付的核心在于将APK拆解为多个可按需下载的模块。本章将引导你从零开始,在 Android Studio 中创建一个 Dynamic Feature 模块,完成关键的 build.gradle 配置,并设置模块的按需下载(on-demand)属性。
3.1 理解 Dynamic Feature 模块的结构
一个 Dynamic Feature 模块并非普通的 Android Library 模块。它在编译时生成独立的 .apk 或 .aab 切片,并在运行时由 Play Core SDK 触发下载。其结构具备以下特征:
- 清单(Manifest)独立性:每个模块拥有自己的
AndroidManifest.xml,其中必须声明dist:module属性。 - 资源与代码隔离:模块内的资源(layout/drawable)和 Java/Kotlin 代码默认不包含在基础 APK 中。
- 依赖基座(Base):Feature 模块依赖于 Base 模块,但 Base 模块不应反向依赖 Feature 模块中的任何类或资源。
创建模块时,Android Studio 会自动生成基础结构,但你需要手动调整依赖关系与版本号以保证与 Base 模块一致。
3.2 创建 Dynamic Feature 模块
使用 Android Studio 内置向导可以在几秒内完成模块创建:
- 右键点击项目根目录 → New → Module。
- 在面板中选择 Dynamic Feature Module,点击 Next。
- 设置模块名称(例如
feature_payment)、包名(通常以.feature_payment结尾)以及最低 API 等级。 - 选择基础模块(Base application module),通常为
app。 - 在 Module Title 中输入用户可见的模块名(例如“高级支付功能”),该名称会在安装确认对话框中显示。
- 设定 Install-time inclusion 为 Do not include at install-time(即 on-demand 模式),点击 Finish。
3.3 配置 build.gradle(项目级与模块级)
创建后,需要手动调整至少两处配置以确保稳定构建:
① 项目级 build.gradle(位于项目根目录):确保已声明 Google Play Services 依赖。
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:8.2.0"
classpath "com.google.android.play:core:1.10.3"
}
}
② 模块级 build.gradle(位于 feature 模块目录下):这是整个动态交付配置的核心。
plugins {
id 'com.android.dynamic-feature'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.yourcompany.feature_payment'
compileSdk 34
defaultConfig {
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0"
}
// 确保以 AAB 格式打包
bundle {
language {
enableSplit = true
}
density {
enableSplit = true
}
abi {
enableSplit = true
}
}
}
dependencies {
// 必须依赖基础模块
implementation project(":app")
// 可选:引入 Play Core 用于在模块内触发下载
implementation 'com.google.android.play:core:1.10.3'
}
版本对齐警告: Feature 模块的
compileSdk 和 targetSdk 必须与 Base 模块完全一致,否则构建会因版本冲突失败。3.4 设定 on-demand 属性
模块的按需下载行为由 AndroidManifest.xml 中的 <dist:module> 标签控制。向导会生成大致框架,但需要人工确认以下关键行:
<dist:module
xmlns:dist="http://schemas.android.com/apk/distribution"
dist:instant="false"
dist:title="@string/module_title">
<dist:delivery>
<dist:on-demand/>
</dist:delivery>
<dist:fusing dist:include="true"/>
</dist:module>
参数含义对照:
| 属性 | 值 | 说明 |
|---|---|---|
dist:on-demand | (空元素) | 模块仅在运行时通过 API 下载,非首次安装包含 |
dist:fusing include | true | 允许在低于 Android 5.0(API 21)的设备上回退到多 APK 模式 |
dist:instant | false | 非即时应用模块,保留为 false |
dist:title | @string/module_title | 用户可见的模块名称,用于确认对话框 |
3.5 代码隔离与调试
动态交付模块中的代码在安装时不会被加载。这意味着:
- 你不能在 Base 模块中直接
importFeature 模块的类;必须通过反射、接口或 Play Core 的SplitInstallHelper加载。 - 建议在 Base 模块中定义一个接口(contract),Feature 模块实现该接口,以解耦依赖。
- 本地运行时,通过
SplitInstallManager下载模块后,系统会自动将模块中的Activity添加到PackageManager,此时才能安全启动。
常见错误 #1:构建失败 — Manifest 合并冲突。 解决方案:在 Feature 模块的
AndroidManifest.xml 中添加 tools:replace="android:label",并导入 xmlns:tools="http://schemas.android.com/tools"。3.6 性能与稳定性优化建议
- 模块粒度:每个 Feature 模块的 dex 方法数建议控制在 8K 以内,避免超出单个切片限制。
- 懒加载适配:在 Base 模块中缓存 Feature 模块的接口实例,避免重复下载。
- 清单合并:善用
tools:remove和tools:replace解决资源冲突。 - 构建加速:对不常变动的 Feature 模块开启 Gradle 配置缓存。