第 1 章:Gradle 入门基础

  • Gradle 到底负责什么,和 Maven、Ant 有什么区别。
  • 一个 Gradle 项目里 settings.gradlebuild.gradlegradle.properties 分别干什么。
  • Task、Plugin、Dependency、Repository 这些核心概念如何配合完成一次构建。
  • Groovy DSL 和 Kotlin DSL 的写法差异在哪里。
  • Gradle Wrapper、Toolchain、User Home、增量构建分别解决什么问题。
  • 如何诊断构建问题(调试参数、日志级别)。

1. Gradle 是什么

Gradle 是一个构建自动化工具。构建不是简单的"编译代码",而是一组稳定、可重复的工程动作:

  • 下载依赖。
  • 编译源码。
  • 处理资源。
  • 执行测试。
  • 生成构建产物。
  • 发布产物。
  • 执行代码检查、安全扫描、版本生成等自动化动作。

Gradle 的核心特点是"声明式配置 + 可编程扩展"。你可以像 Maven 一样声明依赖和插件,也可以用 Groovy 或 Kotlin 写逻辑扩展构建流程。

Gradle 解决的核心问题

问题 Gradle 怎么解决
依赖管理复杂 声明式依赖 + 自动解析传递依赖
构建步骤繁琐 Task 图 + 插件标准化常用流程
多模块协作困难 原生多模块支持
构建太慢 增量构建 + 构建缓存 + 并行执行
团队规范不统一 Convention Plugin 统一配置

2. Gradle 和 Maven、Ant 的区别

对比项 Ant Maven Gradle
配置语言 XML XML Groovy DSL 或 Kotlin DSL
构建模型 命令式 task 固定生命周期 有向无环图(DAG)task
生命周期 完全自定义 固定生命周期更强 task 图更灵活
扩展能力 完全自由但无规范 插件扩展为主 插件、task、脚本、构建逻辑都可扩展
性能能力 无内置缓存 相对传统 增量构建、构建缓存、配置缓存支持更强
依赖管理 无内置(需 Ivy) 内置 Maven 仓库 内置,支持 Maven/Ivy/自定义仓库
学习成本 低入门、低天花板 入门较稳定 入门简单,深入后需要理解模型

核心理解:Maven 更像"按固定流程填表",Gradle 更像"给你默认流程,也允许你改造流水线"。Ant 则是"完全空白画布,你自己定义所有步骤"。


3. 使用 gradle init 初始化项目

Gradle 内置 init 命令,可以交互式创建项目骨架,是学习 Gradle 最快的起点。

bash 复制代码
mkdir my-project && cd my-project
gradle init

gradle init 会提示选择:

  • 项目类型:applicationlibraryGradle pluginbasic
  • 实现语言:JavaKotlinGroovyScalaC++Swift
  • DSL 语言:GroovyKotlin
  • 测试框架:JUnit JupiterSpockTestNG

非交互模式(适合脚本):

bash 复制代码
gradle init \
  --type java-application \
  --dsl groovy \
  --test-framework junit-jupiter \
  --package com.example \
  --project-name my-app \
  --no-incubating

生成后的典型结构:

text 复制代码
my-app/
├── settings.gradle         # 项目声明
├── build.gradle            # 构建脚本
├── gradle.properties       # 构建参数
├── gradle/
│   ├── wrapper/            # Gradle Wrapper
│   └── libs.versions.toml  # Version Catalog
├── gradlew                 # Unix 启动脚本
├── gradlew.bat             # Windows 启动脚本
└── app/
    └── src/
        ├── main/java/
        └── test/java/

4. Gradle 项目基本结构

text 复制代码
project-root/
├── settings.gradle          # 项目声明
├── build.gradle             # 构建脚本
├── gradle.properties        # 构建参数
├── gradle/
│   └── libs.versions.toml   # Version Catalog(Gradle 7.4+)
└── src/
    ├── main/java
    └── test/java

settings.gradle

settings.gradle 描述"这个构建里有哪些项目"。单模块工程通常只设置根项目名,多模块工程会通过 include 注册子模块。

groovy 复制代码
pluginManagement {
    repositories {
        gradlePluginPortal()
        mavenCentral()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        mavenCentral()
    }
}

rootProject.name = 'hello-gradle'
include 'app'

Kotlin DSL 版本(settings.gradle.kts):

kotlin 复制代码
pluginManagement {
    repositories {
        gradlePluginPortal()
        mavenCentral()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        mavenCentral()
    }
}

rootProject.name = "hello-gradle"
include("app")

build.gradle

build.gradle 描述"项目如何构建"。它通常包含插件、依赖、任务、测试、打包等配置。

groovy 复制代码
plugins {
    id 'java'
    id 'application'
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
}

application {
    mainClass = 'com.example.Main'
}

test {
    useJUnitPlatform()
}

gradle.properties

gradle.properties 用于放构建参数,例如 JVM 参数、并行构建、缓存开关。

properties 复制代码
org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.warning.mode=all

常用参数说明:

参数 作用 推荐值
org.gradle.jvmargs Gradle 守护进程 JVM 参数 -Xmx2g -Dfile.encoding=UTF-8
org.gradle.parallel 并行构建 true(多模块项目)
org.gradle.caching 构建缓存 true
org.gradle.warning.mode 警告显示级别 all
org.gradle.daemon 是否使用 Daemon true(默认)
org.gradle.configuration-cache 配置缓存 true(Gradle 8.x)

5. Groovy DSL vs Kotlin DSL

Gradle 支持两种 DSL:Groovy(.gradle)和 Kotlin(.gradle.kts)。

语法对比

特性 Groovy DSL Kotlin DSL
文件扩展名 .gradle .gradle.kts
字符串 单引号或双引号 双引号
插件 id id 'java' id("java")
属性赋值 mainClass = '...' mainClass.set("...")= "..."
IDE 支持 有限 IntelliJ 完整补全
类型安全 动态类型 静态类型

完整对比示例

Groovy DSL(build.gradle):

groovy 复制代码
plugins {
    id 'java'
    id 'application'
}

group = 'com.example'
version = '1.0.0'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.google.guava:guava:33.2.1-jre'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
}

application {
    mainClass = 'com.example.Main'
}

test {
    useJUnitPlatform()
}

Kotlin DSL(build.gradle.kts):

kotlin 复制代码
plugins {
    id("java")
    id("application")
}

group = "com.example"
version = "1.0.0"

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("com.google.guava:guava:33.2.1-jre")
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
}

application {
    mainClass.set("com.example.Main")
}

tasks.test {
    useJUnitPlatform()
}

推荐:新项目优先使用 Kotlin DSL,有更好的 IDE 自动补全和类型检查。


6. Gradle Wrapper

Wrapper 是团队项目中非常重要的机制。它把 Gradle 版本固定在项目里,避免每个人本机 Gradle 版本不同导致构建结果不同。

生成 Wrapper:

bash 复制代码
gradle wrapper --gradle-version 8.8

生成后通常会出现:

text 复制代码
gradlew
gradlew.bat
gradle/wrapper/gradle-wrapper.properties
gradle/wrapper/gradle-wrapper.jar

gradle-wrapper.properties 内容:

properties 复制代码
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

团队成员直接执行:

bash 复制代码
./gradlew clean test

升级 Wrapper 版本:

bash 复制代码
./gradlew wrapper --gradle-version 8.10
# 提交 gradle-wrapper.properties 即可

最佳实践

  • gradlewgradlew.batgradle/wrapper/ 目录都要提交到 Git。
  • 不要把 gradle-wrapper.jar 加入 .gitignore

7. Gradle User Home(缓存目录)

Gradle 会把下载的依赖、Wrapper、构建缓存存放在 GRADLE_USER_HOME 目录,默认为:

text 复制代码
~/.gradle/
├── caches/          # 依赖缓存、构建缓存
├── wrapper/         # Gradle 各版本二进制
├── gradle.properties # 全局属性(所有项目生效)
└── init.d/          # 全局 init 脚本

查看缓存大小:

bash 复制代码
du -sh ~/.gradle/caches

清理旧缓存(Gradle 8.x 内置):

bash 复制代码
gradle --stop                        # 停止 Daemon
./gradlew clean                      # 清理构建输出
rm -rf ~/.gradle/caches/modules-*/files-*  # 清理依赖缓存(谨慎)

全局 ~/.gradle/gradle.properties(对所有项目生效):

properties 复制代码
# 所有项目通用代理配置
systemProp.http.proxyHost=proxy.example.com
systemProp.http.proxyPort=8080
systemProp.https.proxyHost=proxy.example.com
systemProp.https.proxyPort=8080

8. Task:Gradle 的最小执行单元

Gradle 中所有构建动作最终都会落到 task 上。例如:

  • compileJava:编译 Java 源码。
  • processResources:处理资源文件。
  • test:执行测试。
  • jar:生成 jar 包。
  • build:执行完整构建。

查看所有 task:

bash 复制代码
gradle tasks
gradle tasks --all    # 包含隐藏 task

查看某个 task 依赖了哪些 task:

bash 复制代码
gradle build --dry-run

自定义一个 task:

groovy 复制代码
tasks.register('helloGradle') {
    group = 'learning'
    description = 'Print a simple Gradle message'
    doLast {
        println 'Hello Gradle'
    }
}

运行:

bash 复制代码
gradle helloGradle

Task 依赖关系

dependsOn:A 执行前必须先执行 B。

groovy 复制代码
tasks.register('packageAll') {
    dependsOn 'compileJava', 'processResources'
    doLast {
        println 'Packaging...'
    }
}

mustRunAfter:如果 A 和 B 都被请求,A 必须在 B 之后运行(不强制执行 B)。

groovy 复制代码
tasks.named('test') {
    mustRunAfter tasks.named('lint')
}

finalizedBy:A 执行完后(不管成功还是失败)必须执行 B。

groovy 复制代码
tasks.named('test') {
    finalizedBy tasks.named('generateReport')
}

shouldRunAfter:建议顺序,不强制。常见于 CI 排序优化。


9. 增量构建(UP-TO-DATE)

Gradle 会追踪每个 task 的输入和输出。如果自上次执行以来输入和输出都没变化,task 就会跳过,标记为 UP-TO-DATE

bash 复制代码
gradle compileJava       # 第一次:EXECUTED
gradle compileJava       # 第二次:UP-TO-DATE(跳过)

输出示例:

text 复制代码
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE

如果想强制重新执行(忽略缓存和增量):

bash 复制代码
gradle compileJava --rerun

自定义 task 要声明输入输出才能享受增量构建:

groovy 复制代码
abstract class GenerateBuildInfo extends DefaultTask {
    @Input
    abstract Property<String> getVersionName()

    @OutputFile
    abstract RegularFileProperty getOutputFile()

    @TaskAction
    void generate() {
        outputFile.get().asFile.text = "version=${versionName.get()}\nbuildTime=${new Date()}"
    }
}

tasks.register('generateBuildInfo', GenerateBuildInfo) {
    versionName = project.version.toString()
    outputFile = layout.buildDirectory.file('generated/build-info.properties')
}

10. Plugin:复用构建能力

Plugin 是 Gradle 构建能力的封装。比如 java 插件会自动添加 Java 编译、测试、打包相关 task。

groovy 复制代码
plugins {
    id 'java'
}

应用 java 插件后,Gradle 会自动提供:

  • compileJava
  • processResources
  • classes
  • test
  • jar
  • assemble
  • check
  • build

常用核心插件:

插件 ID 作用
java Java 编译、测试、打包
java-library Java 库(支持 api 配置)
application Java 可执行程序(提供 run task)
maven-publish 发布到 Maven 仓库
base 基础 task(cleanassemblecheckbuild

11. Java Toolchain(工具链)

Java Toolchain 允许你在 build.gradle 中声明所需的 JDK 版本,Gradle 会自动查找或下载对应版本。好处是不依赖机器上默认的 JDK。

groovy 复制代码
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

Kotlin DSL:

kotlin 复制代码
java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
    }
}

也可以对单个 task 指定:

groovy 复制代码
tasks.withType(JavaCompile).configureEach {
    javaCompiler = javaToolchains.compilerFor {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

查看 Gradle 发现的 Toolchain:

bash 复制代码
gradle -q javaToolchains

为什么要用 Toolchain?

  • 团队成员本机 JDK 版本可能不同。
  • CI 服务器 JDK 版本可能随系统升级变化。
  • Toolchain 能保证编译 JDK 版本稳定,和 Wrapper 一样是可重复构建的关键。

12. Dependency 和 Repository

Repository 负责告诉 Gradle 去哪里找依赖,Dependency 负责声明项目需要什么依赖。

groovy 复制代码
repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.google.guava:guava:33.2.1-jre'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
}

常见依赖范围:

依赖范围 含义 典型用途
implementation 编译和运行需要,但不暴露给下游模块 大多数业务依赖
api 编译和运行需要,并暴露给下游模块 公共 API 模块
compileOnly 编译需要,运行不打包 注解、Servlet API
runtimeOnly 编译不需要,运行需要 数据库驱动
testImplementation 测试编译和运行需要 JUnit、Mockito
testCompileOnly 仅测试编译需要 测试注解处理器
testRuntimeOnly 仅测试运行需要 JUnit Platform Launcher

13. Gradle 构建生命周期

一次 Gradle 构建大致分为三个阶段:

阶段 作用 例子
Initialization 确定参与构建的项目 读取 settings.gradle
Configuration 配置项目和 task 读取各模块 build.gradle
Execution 执行被请求的 task 执行 testbuildrun

常见误区是把复杂逻辑直接写在配置阶段。配置阶段越重,所有命令都会变慢,即使你只是执行一个简单 task。

groovy 复制代码
// ❌ 错误:println 在配置阶段执行,任何命令都会触发
println "Configuring project..."

tasks.register('hello') {
    // ❌ 错误:这里也在配置阶段
    println "Setting up hello task..."
    doLast {
        // ✅ 正确:doLast 在执行阶段
        println "Hello from execution phase"
    }
}

14. 调试参数和日志级别

Gradle 提供丰富的调试参数,遇到问题时是排查的第一手段。

参数 作用
--stacktrace 显示完整异常堆栈
--info 显示 INFO 级别日志
--debug 显示 DEBUG 级别日志(非常详细)
--scan 生成在线 Build Scan 报告
--profile 生成本地 HTML 性能报告
--dry-run 只打印会执行的 task,不真正执行
--rerun 强制重新执行指定 task
--refresh-dependencies 强制重新下载依赖
-x taskName 跳过指定 task
--continue 某个 task 失败后继续执行其他 task
--parallel 并行执行(也可在 properties 中设)

常用组合:

bash 复制代码
# 构建失败排查
./gradlew clean build --stacktrace

# 依赖下载失败排查
./gradlew build --refresh-dependencies --info

# 构建变慢排查
./gradlew build --profile
./gradlew build --scan

# 只看 task 执行计划
./gradlew build --dry-run

# 跳过测试
./gradlew build -x test

15. 入门实操

实操 1:查看 Gradle 版本

bash 复制代码
gradle --version

验证点:

  • 能看到 Gradle 版本。
  • 能看到 JVM 版本。
  • 能看到操作系统信息。

实操 2:查看项目 task

进入本仓库 demo:

bash 复制代码
cd demo/gradle-multi-module-demo
gradle tasks
gradle tasks --all

验证点:

  • 能看到 applicationbuildverification 等分组。
  • 能看到自定义 task printProjectInfo
  • --all 能看到所有内部 task。

实操 3:执行完整构建

bash 复制代码
gradle clean build

验证点:

  • BUILD SUCCESSFUL
  • app/build/libsservice/build/libscommon/build/libs 下出现构建产物。

实操 4:查看 task 执行计划

bash 复制代码
gradle build --dry-run

验证点:

  • 输出每个将要执行的 task 前缀为 :模块:task名
  • 不会真正编译或执行测试。

实操 5:体验增量构建

bash 复制代码
gradle compileJava        # 第一次:EXECUTED
gradle compileJava        # 第二次:UP-TO-DATE

验证点:

  • 第二次执行时看到 UP-TO-DATE,构建几乎立即完成。

实操 6:使用调试参数排查

bash 复制代码
gradle build --info 2>&1 | head -60

验证点:

  • 能看到每个 task 的详细状态(UP-TO-DATE / EXECUTED / SKIPPED)。

16. 常见问题

问题 1:为什么有时命令是 gradle,有时是 ./gradlew

gradle 使用本机安装的 Gradle,./gradlew 使用项目固定的 Gradle 版本。真实团队项目优先使用 ./gradlew

问题 2:为什么依赖下载很慢

常见原因:

  • 仓库访问慢。
  • 公司网络代理限制。
  • 依赖版本不存在。
  • 动态版本导致频繁检查远程仓库。

建议优先使用固定版本,企业内部项目可以接入 Nexus、Artifactory 或公司 Maven 镜像。

问题 3:为什么执行 gradle build 会先跑测试

build 生命周期包含 check,而 check 默认依赖 test。如果临时跳过测试可以执行:

bash 复制代码
gradle build -x test

但在 CI 中不建议长期跳过测试。

问题 4:Groovy DSL 和 Kotlin DSL 能混用吗

同一个项目中,settings.gradlebuild.gradle 必须保持一致(都用 Groovy 或都用 Kotlin)。buildSrcbuild-logic 中可以选择不同的 DSL,互不影响。

问题 5:为什么修改 gradle.properties 不生效

  • 检查文件位置:项目根目录下的 gradle.properties 只对当前项目生效。
  • 全局配置放在 ~/.gradle/gradle.properties
  • 修改后需要重启 Gradle Daemon:gradle --stop

问题 6:UP-TO-DATE 但结果不对

说明 task 的输入声明不完整,Gradle 没有把某个影响输出的输入纳入追踪。常见原因:

  • task 依赖了环境变量或系统时间但没声明为 @Input
  • task 读取了某个文件但没声明为 @InputFile

解决方法:用 --info 查看 task 的 UP-TO-DATE 判断依据,补充缺失的输入输出声明。

相关推荐
空中海6 小时前
第 4 章:Gradle 专家级实践
gradle
黄林晴1 天前
警惕!AGP 9.2 别只改版本号,R8 规则与构建链路全线收紧
android·gradle
followYouself7 天前
Gradle、AGP、Plugin插件基本知识
android·gradle·plugin·agp
千码君201610 天前
Flutter:在win10上第一次安装和尝试开发记录
flutter·gradle·android-studio·安卓模拟器
Ww.xh19 天前
Flutter配置Gradle完整教程
flutter·gradle·android studio
vortex520 天前
Gradle 从入门到实战
java·gradle
蜡台23 天前
Android Studio Gradlew JDK配置
java·gradle·android studio·intellij-idea
spencer_tseng25 天前
java.net.SocketTimeoutException: Connect timed out
gradle
蜡台1 个月前
Android Studio 高版本兼容低版本项目配置
android·ide·jdk·gradle·android studio