4. 动态功能模块创建:新建module、build.gradle中的dist:delivery、dist:instant、dist:condition属性

动态功能模块(Dynamic Feature Module)是 Android App Bundle 实现按需交付的核心单元。一个 AAB 可以包含一个基础模块(base)和零个或多个动态功能模块。本章将演示如何从零创建一个动态功能模块,并解析 build.gradle 中 dist:delivery、dist:instant 与 dist:condition 三个关键属性的作用与配置方法。

4.1 新建动态功能模块

在 Android Studio 中,通过菜单 File → New → New Module,选择 Dynamic Feature Module 模板。填写模块名称(例如 feature_video)、包名、最小 SDK 版本以及基础模块依赖。AS 会自动生成以下关键文件:

  • src/main/AndroidManifest.xml —— 包含 <dist:module> 标签
  • src/main/java/... —— 业务代码
  • build.gradle —— 动态功能模块的 Gradle 配置

手动创建时,需确保在项目根目录的 settings.gradle 中包含该模块:

include ':app', ':feature_video'
提示:基础模块(:app)必须将 dynamicFeatures 属性指向动态功能模块,否则打包时会被忽略。

4.2 build.gradle 核心配置:dist 命名空间

动态功能模块的 build.gradle 必须声明 android.dynamicFeatures(在基础模块的 build.gradle 中)以及本模块内部的 dist 属性。以下是完整配置示例:

// 基础模块 :app 的 build.gradle
android {
    ...
    dynamicFeatures = [':feature_video']
}

// 动态功能模块 :feature_video 的 build.gradle
apply plugin: 'com.android.dynamic-feature'

android {
    compileSdk 33

    defaultConfig {
        minSdk 21
    }

    // 关键区域:dist 配置块
    dist {
        delivery {
            // 安装时分发
            installTime
        }
        instant {
            enabled true
        }
        conditions {
            // 仅在设备拥有摄像头时下载
            deviceFeature "android.hardware.camera"
            // 国家或地区条件
            countryCode "US", "DE"
            // 应用版本范围
            minSdkVersion 21
            maxSdkVersion 33
        }
    }
}

dependencies {
    implementation project(':app')
    // 其他依赖
}

4.3 属性详解

属性 作用 可选值
dist:delivery 定义模块的分发时机 installTime(安装时一起下载)
onDemand(按需下载)
/* 空 */(默认 installTime)
dist:instant 是否支持免安装体验(Instant App) enabled true/false
dist:condition 条件分发:按设备特征、国家、API 等级等触发下载 deviceFeature、countryCode、minSdkVersion、maxSdkVersion
警告:dist:delivery = installTime 的模块会随基础模块一起打包进 universal APK,但不会出现在按需下载的动态功能列表中。如果希望模块只在特定条件下下载,必须使用 onDemand 并配合 conditions。

4.4 动态交付条件组合逻辑

条件分发支持多个条件同时配置,默认逻辑为 AND(所有条件满足时才触发分发)。例如上例中,模块仅在 API 21~33、设备有摄像头、且国家为 US 或 DE 时才会被下载。若需要 OR 逻辑,需在 Play Console 中使用高级配置。

4.5 内部结构图:动态功能模块声明流程

动态功能模块声明流程 动态功能模块 Gradle 声明流程 base build.gradle dynamicFeatures = ['..'] settings.gradle include ':feature_video' feature_video build.gradle apply plugin: 'dynamic-feature' dist { ... } delivery: installTime instant: enabled true conditions: {deviceFeature ...} Android App Bundle 打包 条件满足 → 生成独立 APK 否则该模块不包含在 AAB 中

4.6 模块分割规则与注意事项

  • 资源与代码隔离:每个动态功能模块拥有独立的 src/main/res 和 src/main/java,模块之间不能直接引用资源 ID,必须通过基础模块暴露接口或使用 R.* 全路径引用。
  • MinSdk 同步:动态模块的 minSdk 必须 >= 基础模块的 minSdk。
  • 清单合并:AndroidManifest.xml 中的 <dist:module> 标签是必需的,且 dist:onDemand 属性必须与 Gradle 中的 delivery 配置一致。
  • 命名规范:模块名称建议使用小写+下划线,避免使用驼峰,否则在 Play Console 中可能出现识别问题。
最佳实践:对于大型功能(如视频播放、支付、地图),建议使用 onDemand 分发以减小初始安装包体积;对于核心功能(如登录、首页),使用 installTime 确保用户立即拥有。

4.7 验证模块声明

完成配置后,执行 ./gradlew :bundleRelease 生成 AAB 文件。使用 bundletool 查看模块信息:

java -jar bundletool-all.jar dump manifest --bundle app/build/outputs/bundle/release/app-release.aab

输出中应包含类似以下内容:

<dist:module dist:name="feature_video" dist:onDemand="false">
    <dist:delivery>
        <dist:install-time/>
    </dist:delivery>
    <dist:instant>
        <dist:enabled>true</dist:enabled>
    </dist:instant>
    <dist:conditions>
        <dist:device-feature name="android.hardware.camera"/>
        <dist:country-code code="US"/>
        <dist:country-code code="DE"/>
    </dist:conditions>
</dist:module>

若未看到对应模块,说明配置缺失或基础模块的 dynamicFeatures 未正确指向。

4.8 常见错误及解决

错误现象 可能原因 解决方案
Gradle 构建失败:Module not specified settings.gradle 缺少模块引用 添加 include ':feature_video'
无法生成 AAB:Dynamic feature without base 模块 build.gradle 未 apply com.android.dynamic-feature 检查插件声明是否正确
bundletool 输出缺少模块 基础模块 dynamicFeatures 未包含该模块 在 :app 的 build.gradle 中补全
按需下载失败:Module not found dist:delivery 配置为 installTime 导致模块不在按需列表 改为 onDemand

通过以上步骤,你可以成功创建一个满足动态交付条件的 Android 动态功能模块,并在 AAB 打包时精确控制其分发策略。