第1章:Gradle 基础——构建工具演进、Gradle 优势与核心概念

做 Android 开发这么多年,我见过不少人一上来就敲 Gradle 脚本,却不知道它到底解决了什么问题。今天咱们先聊聊这个“地基”,把来龙去脉理清楚,后面讲缓存和增量编译时你才不会觉得飘。

1. 构建工具的“三代进化”

构建工具说白了就是帮你把源代码变成可运行包的东西。最早那会儿,大家用 Makefile。我入行时维护过一个老项目,Makefile 写了两千行,改个编译参数得翻半天,心里直骂娘。后来 Java 世界流行 Ant,它好歹是 XML 写的,比 Makefile 可读性强点,但 Ant 没有约定,每个项目都得自己写一堆重复逻辑。

再后来 Maven 出现了,它引入了“约定优于配置”。我记忆特别深,第一次用 Maven 时觉得“哇,终于不用自己定义目录结构了”。但它也有硬伤——XML 实在太啰嗦,而且构建周期是固定的,想自定义个任务?折腾半天。

Gradle 算是第三代构建工具。它站在前人的肩膀上,同时吸收了 Ant 的灵活性和 Maven 的约定能力,最关键的是它用 Groovy(或 Kotlin)作为 DSL,写起来像写程序一样自然。

一句话总结进化路线:

  • Makefile(纯文本,手动控制)
  • Ant(XML,灵活但无约定)
  • Maven(XML,约定但死板)
  • Gradle(DSL,灵活+约定+高性能)

2. 为什么我选择 Gradle?

说实话,当初从 Maven 迁移到 Gradle 时我也犹豫过。但用了两周后就回不去了。Gradle 有几个杀手锏,特别对我们这种天天和构建打交道的人。

  • DSL 表达式力:用 Groovy 或 Kotlin 写构建逻辑,比 XML 直观十倍。举个例子,你想排除某个依赖?一行代码搞定。
  • 增量编译:这是本课程的核心之一。Gradle 会记住每个输入和输出,只有改动过的部分才重新执行。我曾经在某个大项目中把单次构建从 8 分钟压到 40 秒,全靠增量。
  • 构建缓存:能把一次构建结果复用给其他开发者或 CI。我团队里有个同事每次改一行代码就要全量编译,配置好缓存后他再也不抱怨了。
  • 依赖管理:动态版本、冲突解决、传递性依赖控制,比 Maven 更智能。
  • 并行执行与守护进程:多任务并行 + 常驻进程,启动速度比 Maven 快一个数量级。

我的习惯:每个新项目我都会先配好构建缓存和增量编译,这就像给项目买个“加速保险”。后面章节会手把手教你配置。

3. 核心概念:Project、Task、Plugin

刚开始接触 Gradle 的人最容易绕晕的就是这三个东西。我用一个比喻帮你理解:

  • Project 就是你的“项目”本身。一个 Android App 就是一个 Project,一个 Java Library 也是一个 Project。Gradle 构建时,会为每个模块创建一个 Project 对象。
  • Task 是 Gradle 里最小的执行单元。比如编译 Java 源代码是一个 task,打包 APK 是一个 task,运行测试也是一个 task。Task 可以依赖其他 task,形成一张执行图。
  • Plugin 说白了就是一堆 task 的集合。你引入 Android 插件,它就自动帮你注册了 assembleDebug、installDebug 等一系列 task。不用自己一个个写。

我记得刚开始带新人时,有个同事问我:“为什么我明明没写 task,却能执行 assemble?” 我告诉他,这就是 Plugin 干的——它把一堆常见的构建步骤封装好了。你只需要关注业务代码,构建的脏活累活交给 Plugin。

曾经踩过的坑:我刚开始自己写自定义 task 时,忘了设置输入输出,结果每次构建都执行 full rebuild,连缓存都救不了。后面讲了增量编译原理后,你就明白为什么必须精确定义 inputs/outputs 了。

下面这张图把三者的关系串起来了:一个 Project 可以配置多个 Plugin,每个 Plugin 注册若干 Task,Task 之间通过依赖形成有向无环图(DAG)。

Gradle 核心概念关系图 Project Java Plugin Android Plugin Kotlin Plugin 自定义 Plugin compileJava processResources assembleDebug lint 一个 Project 可以应用多个 Plugin 每个 Plugin 注册 Task,Task 有前后依赖

4. 核心概念速览表

概念 作用 对标 Maven 实际例子
Project 构建单元,代表一个模块或应用 pom.xml 对应的模块 settings.gradle 中定义的 app、library
Task 最小执行原子,可配置输入输出 Maven 的 lifecycle phase(但更灵活) ./gradlew compileDebugKotlin
Plugin 打包一组 Task 和配置扩展 Maven 插件 apply plugin: 'com.android.application'

5. 再聊几句 Task 的生命周期

Gradle 构建分三个阶段:初始化(读 settings.gradle)、配置(执行所有 build.gradle,生成 Task 图)、执行(按依赖顺序执行 Task)。

你想想看,为啥有些代码写在 doLast 里,有些写在配置区?配置区的代码在“配置阶段”就跑完了,而 doFirst/doLast 里的代码留到“执行阶段”才跑。我之前一个项目里,有人把网络请求写在配置区,结果每次执行 gradle tasks 都能把远程服务器搞挂——这就是没搞清楚阶段。

避坑指南:千万别在配置阶段做耗时操作(比如下载文件、IO 读写)。配置阶段应该只创建 Task 和设置参数,真正的干活留给 doFirst/doLast。

6. 本课程的路线

这 30 章我打算这么安排:先把 Gradle 基础打牢(今天就干了这事),然后重点攻克增量编译原理(第 2-6 章),接着手把手配置构建缓存(第 7-15 章),后面是实战案例分析、问题排查、CI 集成,最后再来点更底层的字节码和输入快照分析。

嗯,今天到这里刚刚好。你脑子里应该有了三个锚点:Project 是你的锅,Plugin 是菜谱,Task 就是一个个烹饪步骤。下节课咱们就深入 Task,看看 Gradle 是怎么判断“这道菜要不要重新炒”的。