AGP升级与迁移:版本演进、DSL变更与API废弃处理
AGP(Android Gradle Plugin)的升级,说白了就是一场「基建改造」。我见过太多团队,因为AGP版本落后,导致新特性用不上、构建速度慢、甚至无法适配最新的Android API。今天咱们就来聊聊,怎么平稳地完成这场升级。
AGP版本演进:这些年我们都经历了什么
AGP从3.0到8.x,每个大版本都有标志性的变化。我整理了一张核心演进图,你先感受下整体脉络:
你看,每个版本都不是简单的数字增加。AGP 7.0那次DSL大重构,我印象特别深——我们团队当时有30多个模块,迁移花了整整两周。
DSL变更:从Groovy到Kotlin的阵痛
DSL的变更,是AGP升级中最「疼」的部分。我个人习惯是:先理解变更背后的设计意图,再动手改代码。
1. 命名空间与配置方式的变化
AGP 7.0之前,我们这样写:
android {
compileSdkVersion 31
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.example.app"
minSdkVersion 21
targetSdkVersion 31
}
}
AGP 7.0之后,变成了这样:
android {
namespace "com.example.app"
compileSdk 34
defaultConfig {
applicationId "com.example.app"
minSdk 21
targetSdk 34
}
}
关键变化点:
compileSdkVersion→compileSdk(去掉了Version后缀)buildToolsVersion不再需要显式声明namespace从AndroidManifest.xml移到了build.gradle中
嗯,这里要注意:namespace的迁移,如果你有多个模块,每个模块都要单独设置。我曾经遇到一个坑——某个library模块忘了加namespace,结果R资源引用全部报错。
2. 变体过滤API的变更
AGP 7.0之前,过滤变体用variantFilter:
android {
variantFilter { variant ->
if (variant.buildType.name == "debug" && variant.flavorName == "china") {
setIgnore(true)
}
}
}
AGP 8.0之后,推荐使用onVariants:
android {
onVariants { variant ->
if (variant.buildType == "debug" && variant.flavorName == "china") {
variant.ignore = true
}
}
}
注意:variantFilter在AGP 8.0中已被标记为废弃,建议尽早迁移到onVariants。我建议你在升级AGP版本时,同步检查所有变体相关的API。
API废弃处理:别等到编译报错才动手
AGP的API废弃,通常有一个「软废弃→硬废弃→移除」的过程。我的经验是:在软废弃阶段就处理掉,别拖到硬废弃。
常见的废弃API清单
| 废弃API | 废弃版本 | 替代方案 | 移除版本 |
|---|---|---|---|
variant.getOutputs() |
AGP 7.0 | variant.outputs 属性 |
AGP 9.0(预计) |
BaseVariant.getApplicationId() |
AGP 7.2 | variant.applicationId |
AGP 8.0 |
BuildType.isDebuggable() |
AGP 8.0 | buildType.debuggable |
AGP 9.0(预计) |
Dependency.getArtifact() |
AGP 7.4 | Dependency.artifact |
AGP 8.1 |
你可能会问:「怎么知道哪些API被废弃了?」其实很简单——编译时会有@Deprecated警告。我习惯在gradle.properties中开启:
android.deprecationPrinter.level=WARN
这样所有废弃API的警告都会显示出来,方便你逐个排查。
小技巧:如果你有自定义插件,建议在插件代码中加上@Suppress("DEPRECATION")注解,明确标记哪些地方使用了废弃API,方便后续统一清理。
迁移工具:AGP官方给的「救命稻草」
Google其实提供了不少迁移工具,但很多人不知道。我整理了几个最实用的:
1. Android Studio的AGP升级助手
在Android Studio中,打开 Tools → AGP Upgrade Assistant。它会自动分析你的项目,列出所有需要修改的地方。我个人觉得这个工具对中小型项目特别友好,但大型项目(比如超过50个模块)可能会卡顿。
2. 命令行迁移工具
AGP 8.0之后,官方提供了android-gradle-plugin-migration工具:
./gradlew :app:checkDeprecation --warning-mode all
这个命令会输出所有废弃API的使用位置,精确到文件和行号。我曾经用它一次性定位了47个废弃调用,效率非常高。
3. 自动迁移脚本
对于DSL变更,我写过一个简单的Gradle任务:
tasks.register("migrateNamespace") {
doLast {
fileTree(".").include("**/build.gradle*").each { file ->
def content = file.text
// 替换 compileSdkVersion → compileSdk
content = content.replaceAll("compileSdkVersion", "compileSdk")
// 替换 minSdkVersion → minSdk
content = content.replaceAll("minSdkVersion", "minSdk")
// 替换 targetSdkVersion → targetSdk
content = content.replaceAll("targetSdkVersion", "targetSdk")
file.text = content
}
}
}
注意:自动脚本只能处理简单的文本替换。像namespace这种需要从AndroidManifest.xml中提取的逻辑,还是得手动处理。我建议你跑完脚本后,再用git diff仔细检查一遍。
兼容性矩阵:版本匹配的「黄金法则」
AGP和Gradle、JDK、Kotlin之间有严格的版本对应关系。我见过太多人因为版本不匹配,编译时各种诡异报错。
| AGP版本 | 最低Gradle版本 | 最低JDK版本 | 推荐Kotlin版本 |
|---|---|---|---|
| 7.0.x | 7.0 | 11 | 1.5.x |
| 7.1.x | 7.1 | 11 | 1.6.x |
| 7.2.x | 7.3 | 11 | 1.6.x |
| 7.3.x | 7.4 | 11 | 1.7.x |
| 7.4.x | 7.5 | 11 | 1.8.x |
| 8.0.x | 8.0 | 17 | 1.9.x |
| 8.1.x | 8.1 | 17 | 1.9.x |
| 8.2.x | 8.2 | 17 | 1.9.x |
这里有个容易忽略的点:JDK版本。AGP 8.0强制要求JDK 17,如果你还在用JDK 11,升级后编译会直接报错。我建议你在升级前,先检查CI环境和开发机的JDK版本。
我的升级流程:
- 先升级Gradle到目标版本
- 再升级AGP到目标版本
- 运行
./gradlew :app:checkDeprecation --warning-mode all检查废弃API - 逐个修复废弃调用
- 运行完整测试用例
- 提交代码,观察CI构建是否正常
这个流程我用了好几年,基本没出过大的问题。当然,如果你项目特别大,建议先在一个分支上试水,别直接在主干上搞。
避坑指南:那些年我踩过的坑
最后分享几个我亲身经历的坑,希望能帮你少走弯路:
- 坑一:升级AGP后,
BuildConfig默认关闭了。如果你依赖BuildConfig.DEBUG之类的字段,记得在build.gradle中显式开启:buildFeatures { buildConfig = true }。 - 坑二:AGP 8.0之后,
R.class不再是传递性的。如果你有多个模块,每个模块的R资源必须显式引用。我有个同事因为这个,排查了整整一天。 - 坑三:配置缓存(Configuration Cache)在AGP 8.0中默认开启。如果你的自定义插件没有做好序列化,构建会报错。建议在
gradle.properties中先关闭:org.gradle.configuration-cache=false,等插件适配后再开启。
升级AGP,说白了就是一场「有计划的风险管理」。别怕,按照流程一步步来,大部分问题都能解决。如果遇到实在搞不定的,欢迎来公众号找我聊聊。
公众号:蓝海资料掘金营,微信deep3321