最近的 AGP 9.0 更新,可以说使用又炸出来了一批大坑,对于 Android 可能还好,但是对于 KMP 等用户来说,可能接近“天塌了”的情况,那么这次 AGP 更新了什么?其实大家关心的可能主要就三核心大变动:
- 彻底切到“新 DSL 接口”,旧实现和旧 Variant API 被无情切割
- 内置 Kotlin(Built-in Kotlin)
- KMP plugin 不再能和
com.android.application/com.android.library同模块共存
newDsl
首先就是 newDsl,AGP 9.0 开始只暴露新的 public DSL interfaces,旧的 DSL 类型(比如历史上很多插件/脚本会强转到 BaseExtension 之类)不再提供,并且旧的 variant API(applicationVariants 等)也一起被切断,要迁移到 androidComponents API 。
从 Google 的角度会是,终于可以在主版本把“历史兼容层”拔掉了,扔掉了一个历史包袱,但是对于用户来说,可能会有:
- 自己写的 Gradle 插件或 buildSrc 里强转旧类型直接崩
- 依赖
applicationVariants、libraryVariants的逻辑要改成androidComponents
当然,也不是完全就不行了,官方也提供了 android.newDsl=false 回退,但 AGP 10 会移除这个退路,所以虽然可以过渡,但是适配是必然的。
包括使用了 Hilt、 KSP 的老版本的都可能会无法编译,只能说过渡期还是有的,但是如果对应的插件作者不玩了,那就只能你自己过渡了。
Built-in Kotlin
Built-in Kotlin 现在默认开启,AGP 9.0 会默认启用 built-in Kotlin:目标就是你不需要再给 Android module 单独 apply org.jetbrains.kotlin.android 就能编译 Kotlin,不再需要声明 KGP 版本 。
但副作用是:项目/插件生态里“默认的 KGP/Kotlin Android 插件”的假设会被打破,生态惨局?也就是引用和依赖可能会有冲突,比如你会看到:
Failed to apply plugin 'org.jetbrains.kotlin.android'.
> Cannot add extension with name 'kotlin', as there is an extension already registered with that name.
Failed to apply plugin 'com.jetbrains.kotlin.android'
> The 'org.jetbrains.kotlin.android' plugin is no longer required for Kotlin support since AGP 9.0.
所以,正常来说你需要:
- 移除
kotlin-android插件,移除org.jetbrains.kotlin.android(或kotlin-android),删除所有 apply - 迁移
kotlin-kapt插件,建议迁移到 KSP ,虽然不一定有问题,但是不保证没问题,如果暂时无法迁移到 KSP,可以将kotlin-kapt插件替换为:com.android.legacy-kapt来尝试适配 - 迁移
android.kotlinOptions{}DSL,将android.kotlinOptions{}DSL 迁移到kotlin.compilerOptions{} - 迁移
kotlin.sourceSets{}DSL ,另外可以使用 variant API 的addStaticSourceDirectory或addGeneratedSourceDirectory方法:
除此之外,而且 AG 9.0 还引入了对特定 Kotlin Gradle Plugin 版本运行时依赖:
如果使用的 KGP 版本低于 2.2.10,Gradle 会自动将其升级到 2.2.10,同样如果使用的 KSP 版本低于 2.2.10-2.0.2,AGP 也会将其升级到 2.2.10-2.0.2 以匹配 KGP 版本。
当然,你可以选择 enableKotlin 关闭这个默认支持,然后使用较低版本的 KGP 或 KSP :
android {
enableKotlin = false
}
buildscript {
dependencies {
// For KGP
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") {
version { strictly("KGP_VERSION") }
}
// For KSP
classpath("com.google.devtoolsksp:symbol-processing-gradle-plugin") {
version { strictly("KSP_VERSION") }
}
}
}
但是官方也说了,最低 2.0 ,并且降级带来的不兼容问题,自己负责:
另外,也可以通过
gradle.properties文件中设置android.builtInKotlin=false禁用 built-in Kotlin 。
KMP
最后就是 KMP ,KMP plugin 不再能和 com.android.application / com.android.library 同模块共存,composeApp 必须拆 androidApp 才能工作。
对于 KMP,使用 AGP 9.0+ 时,KMP Gradle plugin 不再兼容 com.android.application / com.android.library 同模块,而解决方案就是:
把 Android 入口(Activity/Application 等)抽到单独的 Android app module,共享代码 module 改成使用新的 Android-KMP library plugin:
com.android.kotlin.multiplatform.library。
也就是:
androidApp:纯 Android Application 模块(打包 APK 的入口在这里)composeApp:共享代码模块(变成 Android Library,并进一步迁移到 Google 的 Android-KMP library plugin)
更准确说法是:
- 把 Android Application 的那部分(Activity/Application/manifest/打包配置) 提出去
- shared module 仍然可以保留
androidMainsource set 放 Android-only 的共享实现,但它只能是“library 语义”,不能再同时承担 application plugin 的职责
简单来说主要有:
-
把
composeApp/src/androidMain整个挪到androidApp/src/,AGP 9 要求 Android 应用入口(比如MainActivity.kt)不再待在 KMP + Android Application 同模块中,入口必须属于androidApp这种 application module 才能正常打包与运行,不过-
有
expect/actual声明必须继续留在共享模块(composeApp)的 source sets 里,保证其它平台也能用如果你的
actual实现严重依赖 Activity 级别的 Context 或生命周期,可能需要重构为依赖注入或回调接口,否则在 Library 级别的 Shared Module 中很难处理。
-
-
把
androidApp/src/androidMain重命名为main,androidApp是一个普通 Android application module,它不走 KMP 的 source set 命名体系 -
清理
composeApp里原本的androidMain.dependencies,在composeApp/build.gradle.kts删除kotlin.sourceSets.androidMain.dependencies {}这块,也就是基于 build variants 的依赖(如 debug/release)需要搬迁或重构,同时按 Android-KMP library plugin 的规则重新组织androidMain相关依赖 -
IDE Run Configuration 里,把以前的
composeApp改成androidApp
当然,目前还能暂时用
android.enableLegacyVariantApi=true苟住,但这个“legacy”也会在 AGP 10 被彻底移除,同时记得android.newDsl=false。
另外, Android-KMP library plugin 对 shared module 的 Android 部分不提供传统的 variant-aware 依赖配置(debugImplementation/releaseImplementation 等会失效),因此需要改用其提供的 classpath/配置方式来注入依赖:
- 你以前在 shared module 用
debugImplementation/releaseImplementation或者依赖 buildType/flavor 来注入不同实现/依赖 ,就需要搬家 - 很多只在 debug 才需要的东西(tooling、调试依赖、某些开关)在 shared module 没法按 variant 优雅区分,只能换策略
实际上我记得,KMP 早期就是推荐 Shared Module + Android App Module ,后来为了简化上手难度,特别是 JetBrains 的 Wizard 向导,推广了 Single Module (Umbrella) 模式,可以一个模块既是共享库又是安卓应用,现在又是一个轮回。
另外,Android Studio 需要 Otter 3 Feature Drop 2025.2.3 才支持 AGP 9.0.0,IntelliJ IDEA 预计要 2026 年第一季度。
为什么
为什么会有“大变动”? 这大概是谷歌想把“把多年技术债一次性结账”,说人话就是:维护成本太高了,开猿节流,把上面三点合起来,你会发现 AGP 9 的目标非常一致:
- 控制公共 API 面:旧 DSL/旧 Variant API 太开放,导致外部插件、buildSrc、脚本到处用内部实现,AGP 团队成本 UP
- 为更稳定的构建模型铺路:Gradle 9 的大方向之一是把 Configuration Cache 推成“首选执行模式”,并逐步淘汰不兼容的老 API/模式,AGP 9 的“新 DSL + 新 Variant API(androidComponents)”正好是顺势而为
- Kotlin 集成:把 Kotlin 编译集成进 AGP(built-in Kotlin),减少过去 KGP/AGP 之间的“脆弱耦合点”
所以可以看到 ,AGP 9 就像是 Google 在做断舍离,所以对于开发者来说,也会是一个被动断舍离的过程,不过话又说回来,不更新就不会有问题,能苟则苟果然还是真理,谁知道过几个版本是不是又抽回来了呢?
所以,你试了 AGP 9 了吗?
参考链接
developer.android.com/build/relea…