Android Gradle Plugin 9.0 升级指南:告别十年技术债,你准备好了吗?

0 阅读5分钟

如果你最近有关注Android开发动态,一定听说了——Android Gradle Plugin(AGP)9.0正式发布了。这不是一次小修小补,而是一次伤筋动骨的大版本升级。用一句话来形容:Google终于下决心把过去十年攒下的技术债给清了。

本文将从背景、核心变更、迁移步骤到新特性,为你呈现一份完整的AGP 9.0升级指南,并附上详细的代码示例。

一、升级背景:为什么这次不一样?

从AGP最初版本开始,为了保持向后兼容性,Google一直在内部保留着大量过时API(如applicationVariants.allBaseExtension等)。这些“老家具”虽然能用,但让构建系统负重前行。

AGP 9.0相当于直接把你搬到了一栋全新的大楼里——布局更合理、结构更先进,但你之前那些老家具可能塞不进新房间了。Google一刀切删除了所有已废弃API,彻底清理技术债。

二、核心变更之一:Kotlin正式成为“内建居民”

1. 不再需要手动应用Kotlin插件

// 以前(需要手动引入)
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'  // 这行现在可以删除了
}

// AGP 9.0
plugins {
    id 'com.android.application'
    // Kotlin支持已内置,无需显式声明
}

新建Android模块后,什么都不用配置,直接就能写Kotlin代码。

2. Kotlin版本管理

AGP 9.0默认自带的Kotlin版本是2.2.10。如果你的项目Kotlin版本低于此,Gradle会自动升级。

想用更高版本Kotlin?

// 顶层 build.gradle.kts
buildscript {
    dependencies {
        // 指定更高版本的KGP
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.0")
        // KSP也要同步升级
        classpath("com.google.devtools.ksp:symbol-processing-gradle-plugin:2.3.0-1.0.0")
    }
}

想强制降级到低版本? (不推荐,但可能有必要)

# 先在 gradle.properties 中关闭内置Kotlin
android.builtInKotlin=false
// 然后在顶层build.gradle中用strictly锁定版本
buildscript {
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") {
            version { strictly("2.1.0") }
        }
    }
}

实用技巧:如果某个模块是纯Java代码,可以单独关闭内置Kotlin避免编译开销

# 在纯Java模块的 gradle.properties 中
android.builtInKotlin=false

三、核心变更之二:DSL接口彻底更换

在AGP 9.0中,老的DSL实现类被完全替换,只暴露新的公开接口。

❌ 错误写法(会报错)

// 这种写法在AGP 9.0中直接报 ClassCastException
val extension = project.extensions.getByType(BaseExtension::class.java)

错误信息:

java.lang.ClassCastException: 
class com.android.build.gradle.internal.dsl.ApplicationExtensionImpl
cannot be cast to class com.android.build.gradle.BaseExtension

✅ 正确写法

// 改用 CommonExtension
val android = project.extensions.findByType(CommonExtension::class.java)

四、Variant API 彻底重做

以前我们用applicationVariants.all做各种自定义操作,现在必须迁移到新的androidComponents API。

1. 修改APK输出名称

// 以前(已废弃)
android.applicationVariants.all { variant ->
    variant.outputs.all {
        outputFileName = "app-${variant.name}-${variant.versionName}.apk"
    }
}

// AGP 9.0 新写法
androidComponents {
    onVariants { variant ->
        // 新API采用懒加载设计
        variant.signingConfig.enableV1Signing.set(false)
        // 注意:修改输出名称的方式也变了,需要通过artifact API
    }
}

2. 禁用特定构建变体

// 以前
android {
    variantFilter { variant ->
        if (variant.buildType.name == "debug" && variant.flavors[0].name == "blue") {
            setIgnore(true)
        }
    }
}

// AGP 9.0 替代方案
androidComponents {
    beforeVariants(
        selector()
            .withBuildType("debug")
            .withFlavor("color", "blue")
    ) { variantBuilder ->
        variantBuilder.enable = false
    }
}

3. 主要API变更对照表

废弃的旧API用途AGP 9.0 新方案
applicationVariants/libraryVariants自定义构建行为androidComponents.onVariants
variantFilter禁用特定变体androidComponents.beforeVariants
sdkDirectory/ndkDirectory获取SDK组件路径androidComponents.sdkComponents
dexOptionsdx工具配置已无替代(d8不需要)
deviceProvider/testServer自定义测试环境Gradle-managed devices

五、Kotlin Multiplatform (KMP) 项目的特殊迁移

如果你正在做KMP开发,AGP 9.0的影响最大

1. Android库模块必须换插件

// 以前(混搭)
plugins {
    id 'com.android.library'
    id 'org.jetbrains.kotlin.multiplatform'
}

// AGP 9.0
plugins {
    id 'com.android.kotlin.multiplatform.library'  // 专用插件
}

2. Android应用模块必须独立

严禁在同一个子项目中同时使用KMP插件和com.android.application插件。必须:

  1. 创建独立的Android应用模块(如androidApp
  2. MainActivityApplication类、AndroidManifest.xml等移过去
  3. 让新模块依赖共享的KMP模块

六、默认行为变更(容易踩坑)

1. R类不再是final(重要!)

# 默认值从false变为true
android.enableAppCompileTimeRClass=true

这意味着R类字段不再是编译时常量。如果你在switch-case中用了R.id.xxx,必须改为if-else

// 以前(现在会编译报错)
when (view.id) {
    R.id.button_ok -> handleOk()
    R.id.button_cancel -> handleCancel()
}

// 现在必须改成
if (view.id == R.id.button_ok) {
    handleOk()
} else if (view.id == R.id.button_cancel) {
    handleCancel()
}

2. targetSdk默认对齐compileSdk

android.targetSdkDefaultToCompileSdk=true

如果未显式设置targetSdk,现在默认使用compileSdk的值,而不是以前的minSdk

3. 唯一包名校验

android.uniquePackageNames=true

所有Android库模块必须有唯一的包名,否则构建失败。

七、好消息:Fused Library插件来了

对于SDK或组件库开发者,这是个期盼已久的功能:把多个模块融合成一个AAR文件发布

// 在需要合并的模块中应用插件
plugins {
    id 'com.android.fused.library'
}

// 配置要合并的模块
fusedLibrary {
    // 自动合并依赖的所有本地模块
}

以前需要各种hack手段才能实现的多模块合并,现在原生支持了。

八、R8更新

1. 处理Kotlin空检查代码

新增配置-processkotlinnullchecks,有三个选项:

  • keep:保留原样
  • remove_message:保留空检查但去掉错误消息(默认值
  • remove:完全移除空检查(极致包体积优化,需确保空安全)

2. ProGuard规则文件变更

不再支持proguard-android.txt,只能使用proguard-android-optimize.txt

九、环境要求升级

依赖最低版本要求
JDK17(重要!CI/CD流水线必须检查)
Gradle9.1.0
SDK Build Tools36.0.0
Android StudioOtter 3 Feature Drop (2025.2.3)+

十、分步升级实战指南

第一步:环境预检

  • 确认JDK版本 ≥ 17(包括CI/CD环境)
  • 检查Android Studio版本
  • 确认第三方插件(Hilt、KSP、Firebase等)是否已适配AGP 9.0

第二步:使用AGP升级助手

千万不要手动改版本号!  通过菜单栏 Tools → AGP Upgrade Assistant 自动处理基础迁移。

第三步:设置临时回退(可选)

如果遇到大量编译错误,可在gradle.properties中添加:

# 临时恢复旧DSL行为(仅用于缓冲,AGP 10.0将移除)
android.newDsl=false
# 临时关闭内置Kotlin(如果需要)
android.builtInKotlin=false

第四步:迁移自定义构建逻辑

对照前面的API变更表,逐步将自定义插件和构建脚本迁移到新API。

第五步:渐进式验证

  1. 先升级AGP版本,配合临时回退保持项目可运行
  2. 逐个模块迁移到新DSL和API
  3. 每迁移完一个模块就编译测试
  4. 全部完成后移除临时回退标志

写在最后

AGP 9.0是一次典型的“阵痛型”升级。短期看迁移成本不低,但清理掉积累十年的技术债,对Android构建系统的长远健康至关重要。

建议:不要急着第一时间升级,先仔细评估项目受影响范围,等核心三方插件都适配后再动手。但也不要拖太久——临时回退标志在AGP 10.0(预计明年年中)就会被移除,留给我们的时间窗口约一年。

参考资源:Google官方Gradle Recipes示例
developer.android.com/build/exten…