Dynamic Feature Module
问题
什么是 Dynamic Feature Module?如何实现按需下载?
答案
Dynamic Feature Module 概念
Dynamic Feature Module 允许将应用拆分为按需下载的模块,用户安装基础包后,根据需要下载特定功能模块(如相机、AR、大型资源包等)。
模块配置
feature-camera/build.gradle.kts
plugins {
id("com.android.dynamic-feature") // 注意不是 application 或 library
id("org.jetbrains.kotlin.android")
}
android {
namespace = "com.example.feature.camera"
compileSdk = 34
}
dependencies {
// Dynamic Feature 反向依赖 app 模块
implementation(project(":app"))
}
feature-camera/src/main/AndroidManifest.xml
<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/title_camera">
<dist:delivery>
<!-- 按需下载 -->
<dist:on-demand />
</dist:delivery>
<dist:fusing dist:include="true" />
</dist:module>
</manifest>
app/build.gradle.kts
android {
dynamicFeatures += setOf(":feature-camera", ":feature-ar")
}
按需下载与安装
val splitInstallManager = SplitInstallManagerFactory.create(context)
// 请求安装 Dynamic Feature
val request = SplitInstallRequest.newBuilder()
.addModule("feature-camera")
.build()
splitInstallManager.startInstall(request)
.addOnSuccessListener { sessionId ->
// 下载开始,监听状态
}
.addOnFailureListener { exception ->
// 处理错误
}
// 监听安装状态
splitInstallManager.registerListener { state ->
when (state.status()) {
SplitInstallSessionStatus.DOWNLOADING -> {
val progress = state.bytesDownloaded() * 100 / state.totalBytesToDownload()
updateProgress(progress)
}
SplitInstallSessionStatus.INSTALLED -> {
// 安装完成,打开功能
launchCameraFeature()
}
SplitInstallSessionStatus.FAILED -> {
// 安装失败
}
}
}
交付模式
| 模式 | 说明 | 适用场景 |
|---|---|---|
install-time | 安装时一起下载 | 核心功能模块 |
on-demand | 用户触发时下载 | 低频使用功能 |
conditional | 满足设备条件时下载 | 特定硬件(如 AR 模块仅 ARCore 设备) |
限制
Dynamic Feature 仅支持通过 Google Play 分发。国内应用商店不支持此功能,需自行实现插件化方案。
常见面试问题
Q1: Dynamic Feature 和插件化框架(如 RePlugin、Shadow)有什么区别?
答案:
| 维度 | Dynamic Feature | 插件化框架 |
|---|---|---|
| 提供方 | Google 官方 | 第三方开源 |
| 分发方式 | Google Play 托管 | 自有服务器 |
| 安装机制 | SplitInstall API | 自定义 ClassLoader |
| 安全性 | Play 签名验证 | 需自行保证 |
| 国内适用 | ❌ 受限 | ✅ 广泛使用 |
| API 限制 | 标准 Android API | Hook 系统 API,兼容性风险 |
国内项目更多使用插件化框架;Google Play 应用推荐 Dynamic Feature。
Q2: Dynamic Feature 模块如何访问 app 模块的代码?
答案:
Dynamic Feature 模块可以正常依赖 app 模块的代码(implementation(project(":app"))),这是反向依赖。但 app 模块不能直接引用 Dynamic Feature 的代码,需通过反射或 SPI(ServiceLoader)机制发现和调用 Dynamic Feature 的类。Google 推荐使用 Jetpack 的 SplitCompat 库处理类加载。