跳到主要内容

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 APIHook 系统 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 库处理类加载。

相关链接