第 3 章:创建动态功能模块 - 模块结构、build.gradle 配置、manifest 声明、分发条件
3.1 动态功能模块的项目结构
在 Android 项目中,动态功能模块是一个独立的 Gradle module,它与主应用模块(app)并列存在。其典型的目录结构如下:
MyApp/
├── app/ # 主应用模块
│ ├── build.gradle.kts
│ └── src/
├── payment_feature/ # 动态功能模块(支付模块)
│ ├── build.gradle.kts
│ └── src/
│ ├── main/
│ │ ├── java/ # 源代码
│ │ ├── res/ # 资源文件
│ │ └── AndroidManifest.xml # 模块清单
└── settings.gradle.kts # 包含模块声明
模块名应遵循小写字母+下划线风格(如
payment_feature),避免使用大写字母,防止安装包名冲突。3.2 build.gradle 配置要点
动态功能模块的 build.gradle.kts 需要使用 com.android.dynamic-feature 插件,并指明主应用模块的依赖关系。以下为支付模块的完整配置:
plugins {
id("com.android.dynamic-feature")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "com.example.payment_feature"
compileSdk = 34
defaultConfig {
minSdk = 21
// 注意:不设置 applicationId,该模块继承主模块的 applicationId
}
buildFeatures {
compose = true
}
}
dependencies {
implementation(project(":app")) // 必须依赖主应用模块
implementation("androidx.core:core:1.12.0")
// 其他业务依赖:支付 SDK、网络库等
}
动态功能模块的
applicationId 切勿自行定义,否则会导致安装冲突。所有 Activity 的 exported 属性需谨慎按需开放。3.3 AndroidManifest 声明要求
每个动态功能模块必须在其 AndroidManifest.xml 中添加 <dist:module> 元素,定义分发类型和条件。支付模块的清单文件示例如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution">
<dist:module
dist:instant="false"
dist:title="@string/payment_module_title">
<dist:delivery>
<dist:on-demand /> <!-- 按需交付(SplitInstall 必备) -->
</dist:delivery>
<dist:fusing dist:include="true" /> <!-- 允许融合到基础APK(Android 5.0 以下兼容) -->
</dist:module>
<application>
<activity android:name=".PaymentActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
| 属性/标签 | 说明 | 推荐值 |
|---|---|---|
dist:instant | 是否为免安装模块 | false(支付模块通常非免安装) |
dist:delivery | 交付方式 | on-demand(动态交付) |
dist:fusing | 是否允许融合到基础APK | true(兼容低版本) |
dist:title | 模块显示名称(用于 Google Play 后台) | 字符串资源 |
3.4 分发条件(Delivery Conditions)
除了按需交付,<dist:conditions> 子标签可以限制模块只在特定设备上可用。支付模块常用的条件包括:
- 设备国家/地区:仅向支持 Google Pay 的国家推送。
- 最小 API 级别:支付 SDK 要求 21 以上。
- 设备特性:如要求 NFC 硬件。
以下是一个带条件分发的示例:
<dist:module ...>
<dist:delivery>
<dist:on-demand />
</dist:delivery>
<dist:conditions>
<dist:country-distribution dist:country="us,gb,de,fr" />
<dist:min-sdk dist:value="21" />
<dist:device-feature dist:name="android.hardware.nfc" dist:required="false" />
</dist:conditions>
</dist:module>
条件分发仅在通过 Google Play 发布时生效;调试阶段可通过 SplitInstall API 强制下载,不受条件限制。
3.5 settings.gradle 模块注册
在项目根目录 settings.gradle.kts 中必须明确包含动态功能模块:
include(":app")
include(":payment_feature")
如果不添加,编译系统将无法识别该模块,SplitInstall 也无法找到对应 ID。
3.6 模块结构与依赖关系总览
3.7 常见配置错误与排查
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
运行时报错 ModuleNotFoundException | 模块未在 settings.gradle.kts 注册 | 添加 include(":payment_feature") |
| 安装时提示“模块冲突” | 动态模块设置了 applicationId | 删除 defaultConfig 中的 applicationId |
| SplitInstall 下载后 Activity 无法启动 | 清单中 exported 为 false | 设置 android:exported="true"(或通过 Intent Filter 匹配) |
| 低版本手机(API < 21)崩溃 | 未开启 dist:fusing=true | 在清单中添加 <dist:fusing dist:include="true" /> |
建议在开发过程中使用 Android Studio 的 Build > Build APK(s) 验证模块是否正确编译,检查生成的 APK 中是否包含
split_config.arm64_v8a.apk 等分片。3.8 本章小结
创建动态功能模块的核心步骤可归纳为:
- 在项目根目录新建 Android Library 模块,插件使用
com.android.dynamic-feature。 - 在
settings.gradle.kts中注册模块。 - 配置
build.gradle.kts,依赖主应用模块(:app)。 - 在
AndroidManifest.xml中声明<dist:module>并设置on-demand交付模式。 - 按需添加
<dist:conditions>限制分发范围。 - 验证融合标志
dist:fusing以保证兼容性。