2. SplitInstall SDK 集成与工程配置
SplitInstall 动态交付的核心是 Play Core SDK。正确集成 SDK、配置清单、初始化管理器并处理好版本兼容性,是后续所有功能稳定运行的基石。本章从原理出发,给出无遗漏的工程配置步骤与稳定性规避策略。
2.1 原理:Play Core 在 SplitInstall 中的角色
Google Play Core 库提供了 SplitInstallManager 接口,App 通过它向 Play 商店请求按需模块的下载、安装与状态监听。整个交互流程如下:
- Gradle 依赖:引入 Play Core 及其 .aab 分包所需插件。
- AndroidManifest 声明:注册 SplitInstallService 相关权限与组件(自动合并)。
- 初始化:通过
SplitInstallManagerFactory.create()获得单例。 - 版本兼容:确保
compileSdk、minSdk、Play Core 版本、Google Play 商店版本四者匹配。
SplitInstallStateUpdatedListener 接口,必须使用 Task 或 Flow 监听。版本选择直接影响初始化代码的写法。
2.2 实现流程:四步稳定集成
Step 1 — 根项目与 Module 的 Gradle 配置
在项目层 build.gradle 中声明 Play Core 插件(仅用于 .aab 分包签名验证);在 App Module 中添加核心依赖。以下为典型配置(Groovy 语法,KT 同理):
// 项目根 build.gradle
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:8.1.4"
classpath "com.google.android.play:core:1.10.3" // Play Core Plugin (可选,用于签名校验)
}
}
// app/build.gradle
android {
compileSdk 34
defaultConfig {
minSdk 21
targetSdk 34
}
// 启用动态交付
dynamicFeatures = [":on_demand_feature"]
}
dependencies {
implementation "com.google.android.play:core-ktx:1.9.1" // KTX 协程版本
// 或使用 Java 版: implementation "com.google.android.play:core:1.10.3"
implementation "com.google.android.play:core-splitinstall:1.0.1" // 部分旧项目需要
}
版本选择建议(2025 年稳定组合):
| Play Core 库版本 | minSdk 最低要求 | 推荐 compileSdk | 说明 |
|---|---|---|---|
| 1.8.x (旧版) | 21 | 31+ | 仍支持 Listener API,但不再更新 |
| 1.9.x ~ 1.10.x | 21 | 33+ | 推荐 core-ktx,协程 + Task 混合 |
| 2.0.0+ | 23 | 34+ | 仅 Kotlin,SplitInstallManager 返回 SplitInstallManagerCompat |
Step 2 — AndroidManifest 配置
Play Core 通过 Manifest 合并自动注入必要组件(如 com.google.android.play.core.splitinstall.testing.FakeSplitInstallManagerService),开发者通常只需在 <application> 标签外保留以下配置(用于 Google Play 商店识别):
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 注意:不需要显式申明 INSTALL_PACKAGES,Play Core 内部通过 split APK 安装机制 -->
<application ...>
<!-- 无额外组件,Play Core 自动合并 -->
</application>
若使用 Test 环境 或 内测 需要 FakeSplitInstallManager,可在 <application> 内添加:
<service
android:name="com.google.android.play.core.splitinstall.testing.FakeSplitInstallManagerService"
android:exported="false" />
Step 3 — SplitInstallManager 初始化
推荐在 Application.onCreate() 或 Activity.onCreate() 中一次性初始化,避免多次创建。以下为 Kotlin + KTX 的标准写法:
class MyApplication : Application() {
lateinit var splitInstallManager: SplitInstallManager
private set
override fun onCreate() {
super.onCreate()
// 使用 SplitInstallManagerFactory 创建实例
splitInstallManager = SplitInstallManagerFactory.create(this)
// 可选:检查是否支持按需下载(判断 Google Play 商店版本)
if (!splitInstallManager.isDeferredInstallSupported) {
Log.w("SplitInstall", "设备不支持 deferred install,将回退全量安装")
}
}
}
onCreate() 中调用 startInstall() 等耗时操作,否则可能触发 ANR。初始化仅创建管理器,不发起网络请求。
Step 4 — 版本兼容性检查与适配
运行时务必判断 isDeferredInstallSupported 和 isStagedInstallSupported,对于不支持设备的需提供降级方案。另外,Play Core 2.0+ 的 API 签名与旧版本不兼容,建议在 gradle.properties 中锁定版本:
// gradle.properties
play.core.version=1.10.3
2.3 集成流程图
2.4 调试与验证方法
- Log 输出:初始化后调用
splitInstallManager.sessionStates(返回Task<Set<SplitInstallSessionState>>),观察状态是否正常。 - adb 测试命令(需安卓 21+):
adb shell am start -n "com.package.yourapp/.TestActivity" --es extra_module "on_demand_feature" - Play Console 内测:上传 .aab 并启用“按需分发”,安装测试版 App 后检查
SplitInstallManager.supportedLanguages是否返回正确。
2.5 常见错误与解决方案
| 错误症状 | 原因 | 解决 |
|---|---|---|
SplitInstallException: -3 (UNAVAILABLE) |
Google Play 商店版本过旧或设备不支持 | 调用 isDeferredInstallSupported 检查,降级为全量安装 |
NoClassDefFoundError: SplitInstallManager |
依赖版本冲突或未引入 core-ktx |
检查 Gradle 依赖树,统一版本号(如 1.10.3) |
Manifest merger failed |
重复申明了 FakeSplitInstallManagerService |
移除 <application> 内的多余 service |
java.lang.IllegalStateException: Single-threaded access required |
在后台线程调用了 SplitInstallManager 非线程安全方法 |
始终在主线程操作 startInstall()、deferredInstall() |
2.6 性能与稳定性优化建议
- 懒初始化:将
SplitInstallManager创建时机推迟到第一次需要按需加载时(如进入 Activity),减少 Application 启动耗时。 - 版本锁定策略:在
gradle.properties中定义playCoreVersion,所有模块统一引用,避免传递依赖导致版本不一致。 - 异常兜底:捕获
SplitInstallException并上报 Crashlytics,但不打断用户主流程。 - 多进程隔离:若 App 有多个进程,只在主进程初始化
SplitInstallManager,其他进程通过 IPC 获取状态。