Gradle升级避坑实战资料 - 第2节

Gradle 版本演进与重要里程碑

讲升级避坑之前,咱得先摸清楚 Gradle 这些年都干了啥。我入行那会儿还在用 Gradle 1.x,那时候国内 Android 开发刚转 Gradle 不久,各种脚本写出来跟天书似的。后来版本一个接一个往外蹦,每个版本都带来新惊喜(和新坑)。

说白了,Gradle 的演进史就是一部「从慢到快、从纯 Groovy 到多语言、从单模块到大规模」的血泪史。你想想看,如果你从 Gradle 3.x 直接跳到 8.x,中间那些断崖式变化不提前了解,升级完大概率编译就炸了。

所以我专门把这部分拎出来当一章,带你过一遍关键里程碑。不会每个小版本都讲,只挑那些「你不注意就要翻车」的节点。

Gradle 1.x – 开天辟地

2012 年发布,基于 Groovy 的 DSL,主要解决 Maven 和 Ant 的痛点。说实话,那时候功能很简陋,连多模块构建都费劲。我当时在一个遗留项目里试过 1.6,配置里全是坑,比如 startParameter 和现在的完全不一样。

  • 里程碑:引入构建可编程能力(Task、Plugin)
  • 避坑:别想了,没人用 1.x 升级,直接跳到 2.0+

Gradle 2.x – 性能觉醒

2014 年发布,重点优化了增量编译和并行任务执行。我记得当时升级到 2.1 后,编译时间从 3 分钟降到 40 秒,吓得我反复检查是不是配置写错了。

  • 引入 --parallel 标志和守护进程(长期驻留 JVM)
  • 废弃了一些旧 API,比如 org.gradle.api.internal 下的类
⚠ 我曾经遇到过:升级到 2.2 后,某个第三方插件直接报 NoClassDefFoundError。原因是插件引用了内部 API,新版删掉了。所以升级前一定先用 --warning-mode all 检查废弃警告。

Gradle 3.x – 构建缓存(划重点)

2016 年发布,核心亮点是构建缓存。为什么说它重要?因为你本地 build 变化后,编译器可以复用之前成功的 task 输出,尤其对 CI/CD 提升巨大。

// 启用本地构建缓存(gradle.properties)
org.gradle.caching=true

但这里有个坑:早期版本的缓存键计算很粗糙,容易命中错误结果。我有个朋友(别问是谁)就因为缓存命中错误,把 release 包签名信息弄混了,线上 Crash 炸了一周才找到原因。

  • 里程碑:Task 输入输出注解规范化(@Input/@Output)
  • 新增 buildCache 块支持远程缓存(HTTP/S3)

Gradle 4.x – 多模块与 Java 9

2017 年发布,主要服务大型多模块项目。新增复合构建(Composite Builds)和Java 模块系统支持。

我个人最喜欢的是 --build-file 和 --settings-file 可以同时加载多个项目。做微服务拆分的时候特别爽。

💡 实用技巧:升级到 4.0 后,记得把 settings.gradle 里的 include ':module-a' 改成 includeBuild('../library') 来引入外部库,比传统 jar 依赖灵活多了。

Gradle 5.x – 拥抱 Kotlin DSL

2018 年发布,正式支持Kotlin DSL 作为一等公民。不过说实话,当时 Kotlin DSL 的 IDE 提示还很弱,很多人尝鲜后又被 Groovy DSL 劝退。

// build.gradle.kts 示例
plugins {
    id("com.android.application") version "8.0.0"
}
android {
    compileSdk = 33
}

我想想——你是不是也遇到过 val 和 var 在闭包里报错的诡异问题?那是因为 Kotlin DSL 的 lambda 接收器类型和 Groovy 完全两码事。要是你用 5.x 版本,尽量先在 buildSrc 里用纯 Kotlin 写逻辑,主构建脚本缓缓再切。

Gradle 6.x – 配置缓存(终于出来了)

2019 年发布,配置缓存(Configuration Cache)正式 GA。它的目标:让「配置阶段」的结果也能缓存,大幅减少大型项目的配置时间。

// 在 gradle.properties 中开启
org.gradle.configuration-cache=true
  • 注意:很多插件(比如老版 ButterKnife、Dagger 编译器)会在配置阶段读取文件或系统属性,配置缓存会标记为不稳定,然后降级回退。
  • 我踩过的坑:用了某个 Room 代码生成插件,开启配置缓存后,每次改实体类都要 clean 后才生成 DAO 代码。后来发现是插件没有正确声明输出文件。

Gradle 7.x – 性能大跃进

2020 年发布:文件系统监控(File System Watching)、并行下载依赖、Kotlin DSL 1.0。AGP(Android Gradle Plugin)也要求最低 Gradle 7.0。

我自己最直观的感受:以前打开 Android Studio 后第一次 build 要等得泡茶,7.0 之后因为文件系统监控,热启动基本秒开。

🛠 避坑建议:升级 7.0 后,一定要检查所有自定义 Task 的 @OutputFiles 和 @InputFiles 是否合理。Gradle 7 对校验更严格,哪怕漏掉一个输入声明,可能就会导致 up-to-date 判断出错。

Gradle 8.x – Kotlin DSL 默认,配置缓存稳定

2022 年底发布:Kotlin DSL 成为默认构建脚本语言,配置缓存默认开启(可手动关闭),清理了大量废弃 API。也就是说,如果你现在新建一个项目,build.gradle.kts 是标配了。

  • 新增 gradle check 可以自动检测不安全的配置
  • 移除了对 Java 8 之前的支持,最低 Java 17

但注意:很多企业还在用 Java 11,升级 8.x 后可能需要同时升级 JDK 版本。


版本演进对照表

下面这个表是我这些年攒下来的「升级对照清单」。每次接老旧项目升级,我都会先对着它划一遍风险项。

Gradle 版本 核心里程碑 踩坑高频点
1.x – 2.x 增量编译、守护进程 内部 API 大幅变动
3.x 构建缓存 缓存键碰撞,需要显式声明 @Input
4.x 复合构建,多项目 settings.gradle 语法变更
5.x Kotlin DSL 试验性支持 闭包接收器不兼容 Groovy
6.x 配置缓存(GA) 插件未适配导致降级
7.x 文件监控,性能提升 Task 校验更严格
8.x Kotlin DSL 默认,配置缓存默认开启 最低 Java 17,废弃 API 多

看到这你可能会问:「这么多版本,我怎么知道我项目该停在哪个版本?」我的建议是:能上 7.x 就别用 6.x,能上 8.x 就别纠结。但前提是检查所有依赖的插件是否已经兼容新版 Gradle API。

🔍 检查插件兼容性小技巧:在 Gradle 8.x 上执行 gradle build --warning-mode=fail,如果没有任何废弃警告,那基本稳了。如果出现一堆 deprecation warning,可以先降回 7.6 等新版插件发布。
Gradle 版本演进与里程碑(2012-2023) 1.x 2012 基础 DSL 2.x 2014 增量编译 3.x 2016 构建缓存 4.x 2017 复合构建 5.x 2018 Kotlin DSL 6.x 2019 配置缓存 7.x 2020 文件监控 8.x 2022 Kotlin DSL默认 关键升级原则 1. 不要跳跃太多大版本(如 3.x → 8.x),中间需要逐版本验证。 2. 每个升级前跑一次 --warning-mode=all 检查废弃 API。 3. 升级后优先测试自定义 Task 和第三方插件的兼容性。

本章小结

Gradle 版本演进的每个关键节点都不是拍脑袋想出来的。从 1.x 到 8.x,它其实一直在回答两个问题:

  • 如何让构建更快? → 增量编译、缓存、守护进程、配置缓存
  • 如何让构建更清晰? → Kotlin DSL、复合构建、废弃 API 清理

下几章我们会一个个核心特性深挖,到时候你会发现:这些「里程碑」背后映射的,其实就是你每天写 build.gradle 时碰到的那些痛苦。