AGP9.0出来有一段时间了,但一直没有真正去了解它更新了些啥,跟以前有啥不一样,毕竟升级了一个大版本,那么借今天这篇文章,就一起来看下AGP9.0
版本兼容性对比
首先要知道一点,如果想要让AGP升级到9.0,那么你的一些其他组件必须满足以下要求
- Gradle:最低版本必须为9.1.0
- SDK build tools:最低为36.0.0
- NDK:对应版本为28.2.13676358
- 最高支持的API Level:不能超过36.1
DSL类只实现新的公共接口
这个是AGP9.0一个大的变化,在以前的AGP版本中比如7.x或者8.x,既包含着新的接口,也同样包含着旧的DSL类型BaseExtension,这种做法就像是服务端的接口,每次新增功能的同时,老的接口依然保留,为的就是兼容线上老版本,这个AGP也是一样的道理,导致的结果是,我们依然一直在使用旧的DSL类型,至于新的接口,很少有人在用,所以在9.0版本上做了一次类似于强制更新一样的操作,要求所有开发者,只要更新到了9.0,那么就必须使用新的接口,同时旧的Variant API访问也会改变,替代方案如下
| 废弃 API (8.x) | 替换方案 (9.0) |
|---|---|
applicationVariants、libraryVariants、testVariants、unitTestVariants |
androidComponents.onVariants |
variantFilter |
androidComponents.beforeVariants |
deviceProvider、testServer |
Gradle Managed Devices |
sdkDirectory、ndkDirectory、bootClasspath 等路径访问 |
androidComponents.sdkComponents |
dexOptions |
无直接替换(dx 已被 d8 取代) |
generatePureSplits |
Android App Bundle 内置分发 |
迁移要求
当你决定将你的项目的AGP迁移至9.0的时候,那么一定要注意以下几点
- 确保项目与内置 Kotlin 兼容(不再使用
org.jetbrains.kotlin.android) - KMP 项目需切换到
com.android.kotlin.multiplatform.library插件 - 所有自定义构建逻辑中的内部 DSL 引用必须替换为公共 DSL 接口
- 第三方插件必须升级到 AGP 9.0 兼容版本
退出机制
当然谷歌但凡有了一次重大更新,那么势必也会提供一个开关让你平滑过渡,为的是比如一些三方库因使用旧版本的AGP而导致兼容性的问题,方式很简单,在gradle.properties里面将newDsl开关置成false即可

当然这种好事将会在AGP10.0里面取消,将会彻底移除退出机制,据说这个版本将会在2026年中推出,在此之前,在AGP9.4版本中,也允许按模块退出,方式就是在gradle.properties里面加上如下配置

内置 Kotlin 支持
另一个重大更新是9.0里面默认内置了kotlin支持并且是处于启用状态,这个就意味着我们以后没有必要在gradle文件里面手动管理KGP版本,AGP9.0会自动帮你依赖上KGP2.2.10版本,但是如果你的项目的KGP版本比2.2.10要高,那么还是得手动去升级一下内置的KGP或者KSP版本

那么有升级肯定还会有降级,如果项目的KGP版本要求比内置版本要低,我们只能去降级,不过降级之前还必须做一件事情,就是关闭内置kotlin功能,不然开着的话依然还是使用默认的内置版本2.2.10,关闭的方式也很简单,在gradle.properties中加入如下配置即可

降级的方式与升级略有些不同,需要使用严格版本

不过这个降级也是有底线的,最低只能降低到2.0.0版本
默认值变化
以下是 AGP 8.13 到 9.0 默认值翻转的属性,这样可以在升级的时候,评估保留哪些旧版本上的行为
| Gradle 属性 | 8.13 默认值 | 9.0 默认值 | 影响 |
|---|---|---|---|
android.newDsl |
false |
true |
新 DSL 默认启用 |
android.builtInKotlin |
false |
true |
内置 Kotlin 默认启用 |
android.uniquePackageNames |
false |
true |
所有库必须使用唯一包名 |
android.useAndroidx |
false |
true |
强制使用 AndroidX |
android.default.androidx.test.runner |
false |
true |
默认使用 AndroidJUnitRunner |
android.dependency.useConstraints |
true |
false |
影响依赖导入优化 |
android.enableAppCompileTimeRClass |
false |
true |
R class 常量需要重构(switch → if 链) |
android.sdk.defaultTargetSdkToCompileSdkIfUnset |
false |
true |
未设置 targetSdk 时默认等于 compileSdk |
android.onlyEnableUnitTestForTheTestedBuildType |
false |
true |
仅对测试的构建类型启用单元测试 |
android.proguard.failOnMissingFiles |
false |
true |
ProGuard 文件缺失将报错 |
android.r8.optimizedResourceShrinking |
false |
true |
资源压缩默认优化 |
android.r8.strictFullModeForKeepRules |
false |
true |
Keep 规则更严格(需显式保留构造器) |
android.defaults.buildfeatures.resvalues |
true |
false |
仅在需要 resValues 的子项目中启用 |
android.defaults.buildfeatures.shaders |
true |
false |
仅在需要着色器的子项目中启用 |
android.r8.proguardAndroidTxt.disallowed |
false |
true |
只支持 proguard-android-optimize.txt |
android.r8.globalOptionsInConsumerRules.disallowed |
false |
true |
库发布时禁止保留文件中含全局选项 |
android.sourceset.disallowProvider |
false |
true |
必须使用 Sources API 注册生成的源码 |
android.custom.shader.path.required |
false |
true |
必须配置 glslc.dir |
已移除的功能
| 功能 | 8.x 状态 | 9.0 |
|---|---|---|
| Wear OS 嵌入式应用支持 | 可用 | 移除 (wearApp 配置被删除) |
androidDependencies 任务 |
可用 | 移除 |
sourceSets 报告任务 |
可用 | 移除 |
| Density Split APK 支持 | 可用 | 移除(改用 App Bundle) |
已移除的DSL项
AndroidSourceSet.jni(功能从未正常工作)AndroidSourceSet.wearAppConfigurationNameBuildType.isRenderscriptDebuggable(功能从未正常工作)DependencyVariantSelection→ 替换为DependencySelection,后者以kotlin.android.localDependencySelection的形式公开Installation.installOptions(String),它已被Installation.installOptions的可变属性取代- 实验性但从未稳定过的
PostProcessing块 ProductFlavor.setDimension→ 替换为dimension属性LanguageSplitOptions,仅对已弃用的Google Play免安装体验有用DensitySplit,因为该功能不再受支持。 替代方案是使用 App Bundle
已移除的 API
| 8.x API | 9.0 替换 |
|---|---|
AndroidComponentsExtension.finalizeDSl |
finalizeDsl(大小写修正) |
Component.transformClassesWith |
Instrumentation.transformClassesWith |
Component.setAsmFramesComputationMode |
Instrumentation.setAsmFramesComputationMode |
ComponentBuilder.enabled |
ComponentBuilder.enable |
DependenciesInfoBuilder.includedInApk |
includedInApk |
DependenciesInfoBuilder.includedInBundle |
includedInBundle |
GeneratesApk.targetSdkVersion |
targetSdk |
Variant.minSdkVersion / maxSdkVersion / targetSdkVersion |
minSdk / maxSdk / targetSdk |
VariantBuilder.targetSdk或targetSdkPreview |
GeneratesApkBuilder.targetSdk或GeneratesApkBuilder.targetSdkPreview |
VariantOutput.enable |
enabled |
移除了VariantBuilder.unitTestEnabled |
取而代之的是在扩展HasUnitTestBuilder的VariantBuilder子类型上名称更一致的enableUnitTest |
FeaturePlugin、FeatureExtension |
已废弃并停止 |
BaseExtension.registerTransform |
已废弃并停用 |
已移除的 Gradle 属性
android.defaults.buildfeatures.aidl:改为各子项目单独配置buildFeatures { aidl = true }android.defaults.buildfeatures.renderscript:改为各子项目单独配置
强制执行的Gradle属性
android.r8.integratedResourceShrinking: 强制执行,使用即报错android.enableNewResourceShrinker.preciseShrinking: 强制执行
DSL 变化:CommonExtension 形参化移除
这是源码级破坏性变更,旨在帮助避免未来出现源代码级重大变更,但这也意味着,块方法需要从 CommonExtension 移至 ApplicationExtension、LibraryExtension、DynamicFeatureExtension 和 TestExtension
AGP 8.13

AGP 9.0

R8 变化
新选项:-processkotlinnullchecks
配置 R8 如何处理 Kotlin 空值检查:
| 参数值 | 行为 |
|---|---|
keep |
不做任何更改 |
remove_message(默认) |
重写为调用 getClass(),保留空值检查但移除消息 |
remove |
完全移除空值检查 |
Keep规则不再传播到 Companion 方法
- 之前:匹配接口方法的 keep 规则会自动传播到合成的同伴方法上
- 9.0:不再传播,影响
minSdk < 24时的接口反糖化
默认 SourceFile 变更
从 SourceFile 改为 r8-map-id-<MAP_ID>,支持 Logcat 自动堆栈回溯。
合成类名最小化
L8 反脱糖生成的 DEX 中的 j$ 类使用短名称格式(如 $1),不再包含 $$ExternalSynthetic 长编码名。
移除项
-addconfigurationdebugging支持移除(使用会出编译警告)D8Command.builder.setDesugaredLibraryKeepRuleConsumer移除R8Command.Builder.setDesugaredLibraryKeepRuleConsumer移除
最后
不愧是大版本的更新,已经跟之前的版本有了很明显的变化,个人感觉对于大部分项目,要做这个版本的升级还是需要好好规划一下,这可能是有史以来最折腾的一次升级,不过换个角度来想,跨过这道坎以后,项目的构建脚本将会变得更加简洁,可维护,所以长痛不如短痛,趁早把这件事做了吧