1. SplitInstall 核心价值:按需交付、减少安装包体积、用户按需下载

核心论点:SplitInstall 是 Android App Bundle 动态交付的核心机制,它允许应用将功能模块作为独立的“分块”发布,用户仅下载初始必需的部分,后续按需加载其余模块。这直接带来安装包体积减小、用户按需下载、发布灵活性提升三大价值。
传统安装包 vs 动态交付(SplitInstall) 传统 APK 发布 一次性包含所有模块 用户必须下载完整包体 安装后占用大量存储空间 更新需重新下载全量包 × 动态交付(SplitInstall) 基础模块(base)先安装 功能模块按需下载 用户仅获取必要功能 更新模块无需重装base ✓ 演进 按需下载流程 用户点击功能入口 (如OCR、AR) SplitInstall请求 (模块名+监听器) Play/内测分发下载 (网络安装包块) 回 调 基础模块始终优先安装,动态模块仅在需要时触发下载

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 实现流程概览

  1. 项目配置:在 Android Studio 中创建 App Bundle 项目,在基础模块的 build.gradle 中添加动态功能模块依赖。
  2. 定义功能模块:创建 feature-xxx 模块,设置 dist:install-time="on-demand"(或 install-time="fusing" 用于即时跟随基础包)。
  3. 请求模块:在业务代码中使用 SplitInstallManager.startInstall() 传入模块名和任务监听器。
  4. 处理回调:监听 onError、onComplete、onProgress 等状态,更新 UI 提示。
  5. 加载模块:安装完成后,通过 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() 释放存储空间,但需要注意不可卸载基础模块。