第 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是否允许融合到基础APKtrue(兼容低版本)
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 模块结构与依赖关系总览

支付动态功能模块 - 结构 & 配置依赖 主应用 (app) build.gradle.kts 支付动态模块 build.gradle.kts (dynamic-feature) AndroidManifest.xml <dist:module on-demand /> 分发条件 国家 / API / 特性 依赖关系说明 • 支付模块必须 implementation(project(":app")) • 清单 <dist:delivery> 控制分发行为

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 本章小结

创建动态功能模块的核心步骤可归纳为:

  1. 在项目根目录新建 Android Library 模块,插件使用 com.android.dynamic-feature。
  2. 在 settings.gradle.kts 中注册模块。
  3. 配置 build.gradle.kts,依赖主应用模块(:app)。
  4. 在 AndroidManifest.xml 中声明 <dist:module> 并设置 on-demand 交付模式。
  5. 按需添加 <dist:conditions> 限制分发范围。
  6. 验证融合标志 dist:fusing 以保证兼容性。