1. SplitInstall 核心价值:按需交付、减少安装包体积、用户按需下载
核心论点:SplitInstall 是 Android App Bundle 动态交付的核心机制,它允许应用将功能模块作为独立的“分块”发布,用户仅下载初始必需的部分,后续按需加载其余模块。这直接带来安装包体积减小、用户按需下载、发布灵活性提升三大价值。
1.1 什么是 SplitInstall
SplitInstall 是 Google Play 动态交付(Dynamic Delivery)中用于按需安装功能模块的 API。应用通过 Android App Bundle 发布后,可以定义多个“动态功能模块”(dynamic feature module),每个模块对应一组独立的功能(例如相机滤镜、语音识别、付费内容等)。这些模块不会随基础 APK 一同下载,而是在用户首次触发该功能时,应用通过 SplitInstallManager 发起请求,系统从 Play 商店或内部测试渠道下载并安装对应的拆分。
| 对比维度 | 传统 APK(含所有功能) | 动态交付(SplitInstall) |
|---|---|---|
| 安装包体积 | 大(全部功能打包) | 小(仅基础模块) |
| 用户下载体验 | 必须等待完整下载 | 快速进入,后续按需加载 |
| 更新策略 | 全量更新 | 仅更新变动模块 |
| 功能使用率 | 低(用户可能从不使用) | 高(只安装被调用的功能) |
| 发布灵活性 | 一次发布,无法动态拆分 | 可动态配置模块分发策略 |
1.2 核心价值详解
- 按需交付:应用无需提前包含所有功能,用户可在使用时临时下载。适合低频高价值功能(如专业滤镜、AR 测量、多语言包)。
- 减少安装包体积:基础 APK 只包含必要代码和资源,功能模块独立拆分。以 OCR 模块为例,可能节省 20-50 MB 的初始安装包。
- 用户按需下载:给予用户选择权——只有在尝试使用某功能时才触发下载,避免强制捆绑。下载过程通过
SplitInstallStateUpdatedListener实时通知进度,支持前台/后台下载。
最佳实践:在应用启动时,通过
SplitInstallManager.getInstalledModules() 获取已安装的模块列表,避免重复请求。对于经常使用的模块(如支付组件),可考虑在首次启动时提前下载。
1.3 实现流程概览
- 项目配置:在 Android Studio 中创建 App Bundle 项目,在基础模块的
build.gradle中添加动态功能模块依赖。 - 定义功能模块:创建
feature-xxx模块,设置dist:install-time="on-demand"(或install-time="fusing"用于即时跟随基础包)。 - 请求模块:在业务代码中使用
SplitInstallManager.startInstall()传入模块名和任务监听器。 - 处理回调:监听
onError、onComplete、onProgress等状态,更新 UI 提示。 - 加载模块:安装完成后,通过
ClassLoader或 Android 资源机制载入模块中的 Activity/Service。
// 基础 Kotlin 示例:请求下载动态模块 "ocr"
val splitInstallManager = SplitInstallManagerFactory.create(context)
val request = SplitInstallRequest.newBuilder()
.addModule("ocr")
.build()
splitInstallManager.startInstall(request)
.addOnSuccessListener { sessionId ->
Log.d("SplitInstall", "模块下载已开始,会话ID: $sessionId")
}
.addOnFailureListener { exception ->
Log.e("SplitInstall", "下载请求失败: ${exception.message}")
}
// 监听进度
val listener = SplitInstallStateUpdatedListener { state ->
when (state.status()) {
SplitInstallSessionStatus.INSTALLED -> {
// 模块已可用,可跳转至功能界面
startActivity(Intent(this, OcrActivity::class.java))
}
SplitInstallSessionStatus.FAILED -> {
// 处理错误,可依据 errorCode 给出重试提示
}
SplitInstallSessionStatus.DOWNLOADING -> {
val progress = state.bytesDownloaded() * 100L / state.totalBytesToDownload()
Log.d("SplitInstall", "下载进度: $progress%")
}
}
}
splitInstallManager.registerListener(listener)
1.4 调试与常见陷阱
常见错误 1:模块未在 AndroidManifest 中声明为 on-demand。
如果在
如果在
build.gradle 中将 install-time 设为 fusing 或 install-time 缺失,模块会被强制包含在基础包中,失去动态交付效果。务必在动态功能模块的 AndroidManifest.xml 中设置 dist:install-time="on-demand"。
<dist:module
dist:onDemand="true"
dist:title="@string/module_ocr_title">
<dist:delivery>
<dist:install-time />
</dist:delivery>
<dist:fusing dist:include="true" />
</dist:module>
调试技巧:在开发阶段可以使用
adb shell am start -n "com.your.package/com.google.android.play.core.splitinstall.testing.FakeSplitInstallManagerService" 或使用 Play Core 测试库中的 FakeSplitInstallManager 模拟安装过程,避免每次都需要从 Play 商店下载。
1.5 性能与稳定性优化
- 优先使用后台下载:通过
SplitInstallRequest.setCallbackOnMainThread(false)(仅 Kotlin 协程)或异步监听,避免阻塞 UI 线程。 - 断点续传与重试:利用
SplitInstallManager.getSessionState()获取已有会话状态,失败后自动重试(通过监听FAILED并调用retryInstall())。 - 模块预下载:对于高频功能,在应用空闲时通过
startInstall并设置deferredUninstall(延迟卸载),使用户入口极速响应。 - 资源卸载:当用户明确不再需要模块时,可调用
deferredUninstall()释放存储空间,但需要注意不可卸载基础模块。