第3章 动态功能模块清单配置
动态功能模块(Dynamic Feature Module)的清单配置是 SplitInstall 策略的核心起点。正确配置 AndroidManifest.xml 中的 dist:module 相关属性,决定了模块的安装时机、分发范围以及与基础模块的融合方式。本章将逐一剖析这些关键属性,并结合实际案例说明其作用机制。
3.1 dist:module 属性概述
dist:module 是 xmlns:dist 命名空间下用于描述模块分发策略的根元素。一个动态功能模块的清单文件中必须包含此元素,并至少指定 name 属性。完整属性集包括:
| 属性 | 必填 | 取值 | 说明 |
|---|---|---|---|
dist:name | 是 | 字符串 | 模块的唯一标识,用于区分不同功能模块 |
dist:title | 否 | 字符串资源引用 | 模块的面向用户显示名称,用于安装对话框等场景 |
dist:onDemand | 是 | true / false | 控制模块是否为按需下载;false 表示安装时默认一起安装 |
dist:fusing | 是 | true / false | 是否允许模块合并到基础 APK 中(用于旧设备兼容) |
3.2 安装时间控制:onDemand 与 install-time
dist:onDemand 属性直接决定模块的安装时机:
- onDemand="false":模块在应用安装时即被下载并安装,用户无法手动卸载,体验上类似传统静态模块。
- onDemand="true":模块不会在安装时下载,而是由应用运行时通过 SplitInstall API 按需触发下载。这是 SplitInstall 策略的主要应用场景。
下表对比两种模式的关键差异:
| 维度 | install-time(onDemand=false) | on-demand(onDemand=true) |
|---|---|---|
| 下载时机 | 应用安装时 | 运行时按需触发 |
| 用户感知 | 安装包体积增大 | 按需动态下载 |
| 卸载能力 | 不可卸载 | 可卸载(SplitInstall API 支持删除) |
| 典型用途 | 核心功能必须随安装存在 | 高阶功能、低频功能、地区化内容 |
设计建议:将基础业务逻辑放在 install-time 模块中,将非核心功能(主题包、语言包、扩展工具)设置为 on-demand,最大限度地控制初始安装包体积。
3.3 fusing 配置:旧设备兼容性门控
dist:fusing 属性控制模块在设备不支持 Split APK 或动态安装时的行为:
- fusing="true":当设备不支持动态功能模块时(例如 Android 4.x 系统),此模块会被合并入基础 APK,随主安装包一起分发。反之,支持动态功能的设备则按 onDemand 策略行为。
- fusing="false":模块仅通过 Google Play 的动态分发机制传递;若设备不支持,该模块将不可用,应用需自行降级或提示。
注意事项:如果模块内包含不可延迟的关键资源(如支付相关类),请务必设置 fusing="true",避免旧设备上出现功能缺失;但 fusing 会增加基础 APK 的体积,需权衡利弊。
3.4 分割名称(split name)
每个动态功能模块编译后生成独立的 APK,其文件名和内部标识由 dist:name 决定。但部分模块需要与基础模块共享资源或依赖特定构建变体,此时可借助 dist:split 属性(或构建脚本中的 dist 配置)指定分割名称。通常默认分割名称等于 dist:name,但以下场景需显式指定:
- 多个模块共享同一个资源类型(需同分割名下合并)。
- 模块在不同构建变体(如 free/paid)中名称不同,但分割名需一致。
- 自定义分割名称以匹配旧有分发机制。
3.5 完整配置示例
以下演示一个典型按需加载模块的 AndroidManifest.xml 配置:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.example.app.feature_ar">
<dist:module
dist:name="ar_mod"
dist:title="@string/module_ar_title"
dist:onDemand="true"
dist:fusing="true" />
<!-- 其他组件声明,例如 Activity、Service -->
<application>
<activity android:name=".ArActivity" />
</application>
</manifest>
在该示例中,ar_mod 模块将在运行时按需下载,若设备不支持动态功能则合并入基础 APK。模块标题引用字符串资源,可在安装对话框展示。
3.6 常见错误与调试
- 名称冲突:两个动态功能模块使用了相同的
dist:name,导致 Google Play 无法区分。务必保持模块名称唯一。 - fusing 与 install-time 矛盾:设置
onDemand="false"且fusing="false"会导致基础 APK 不包含模块,设备也无法动态安装,功能缺失。请确保至少一个为 true。 - 缺失
dist:module元素:模块清单中未声明<dist:module>,编译时可能不产生分割 APK。 - 混淆分割名称:构建脚本中
split名称与清单中dist:name不一致,导致资源找不到。建议保持完全一致。
调试建议:使用
再通过
bundletool 检查生成的 AAB 文件中模块列表:java -jar bundletool-all.jar get-device-spec --output=spec.json再通过
java -jar bundletool-all.jar build-apks --bundle=app.aab --device-spec=spec.json 验证分割 APK 是否按预期生成。
图中清晰展示了四个核心属性如何从清单文件出发,分别影响模块的安装时机、分发方式和设备兼容性。在实践中,应根据模块的功能定位和用户场景,合理组合这些配置。