第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 模块一致。
Dynamic Feature 模块结构图 Base APK (主模块) 包含核心功能与入口 Feature A on-demand 模块 Feature B on-demand 模块 运行时:按需下载+延迟加载 模块内部结构 AndroidManifest.xml (dist:module 声明) 源代码 / 资源 build.gradle (模块级) 依赖关系 Feature → Base (implementation 依赖) Base 不反向依赖 Feature V1 关键约定 模块之间不能有 双向依赖

3.2 创建 Dynamic Feature 模块

使用 Android Studio 内置向导可以在几秒内完成模块创建:

  1. 右键点击项目根目录 → New → Module。
  2. 在面板中选择 Dynamic Feature Module,点击 Next。
  3. 设置模块名称(例如 feature_payment)、包名(通常以 .feature_payment 结尾)以及最低 API 等级。
  4. 选择基础模块(Base application module),通常为 app。
  5. 在 Module Title 中输入用户可见的模块名(例如“高级支付功能”),该名称会在安装确认对话框中显示。
  6. 设定 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 includetrue允许在低于 Android 5.0(API 21)的设备上回退到多 APK 模式
dist:instantfalse非即时应用模块,保留为 false
dist:title@string/module_title用户可见的模块名称,用于确认对话框

3.5 代码隔离与调试

动态交付模块中的代码在安装时不会被加载。这意味着:

  • 你不能在 Base 模块中直接 import Feature 模块的类;必须通过反射、接口或 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 配置缓存。