推荐执行任何 Gradle 构建的方式是借助 Gradle Wrapper(称为“Wrapper”)。

Wrapper 是一个脚本,它调用声明的 Gradle 版本,并在必要时事先下载它。因此,开发人员可以快速启动并运行 Gradle 项目。

wrapper workflow

简而言之,您将获得以下好处

  • 将项目标准化为给定的 Gradle 版本,以实现更可靠和健壮的构建。

  • 为不同的用户配置 Gradle 版本只需简单地更改 Wrapper 定义。

  • 为不同的执行环境(例如 IDE 或持续集成服务器)配置 Gradle 版本只需简单地更改 Wrapper 定义。

有三种使用 Wrapper 的方法

  1. 您设置一个新的 Gradle 项目,并添加 Wrapper到其中。

  2. 使用 Wrapper 运行一个项目,该项目已经提供了 Wrapper。

  3. 将 Wrapper 升级到新的 Gradle 版本。

以下部分将更详细地解释这些用例。

添加 Gradle Wrapper

生成 Wrapper 文件需要您机器上安装的 Gradle 运行时版本,如安装中所述。值得庆幸的是,生成初始 Wrapper 文件是一个一次性过程。

每个原生 Gradle 构建都带有一个内置的任务,名为 wrapper。当列出任务时,该任务在“构建设置任务”组下列出。

执行wrapper任务会在项目目录中生成必要的 Wrapper 文件。

$ gradle wrapper
> Task :wrapper

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

为了让其他开发者和执行环境可以使用 Wrapper 文件,您需要将它们检入版本控制系统。Wrapper 文件(包括 JAR 文件)都很小。将 JAR 文件添加到版本控制系统是预期的。一些组织不允许项目将二进制文件提交到版本控制系统,并且没有可用的解决方法。

生成的 Wrapper 属性文件,gradle/wrapper/gradle-wrapper.properties,存储了关于 Gradle 发行版的信息。

  • 托管 Gradle 发行版的服务器。

  • Gradle 发行版的类型。默认情况下,-bin 发行版只包含运行时,不包含示例代码和文档。

  • 用于执行构建的 Gradle 版本。默认情况下,wrapper 任务会选择与生成 Wrapper 文件相同的 Gradle 版本。

  • 可选地,下载 Gradle 发行版时使用的超时时间(以毫秒为单位)。

  • 可选地,一个布尔值,用于设置发行版 URL 的验证。

以下是 gradle/wrapper/gradle-wrapper.properties 中生成的发行版 URL 的示例。

distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip

所有这些方面都可以在使用以下命令行选项生成 Wrapper 文件时进行配置。

--gradle-version

用于下载和执行 Wrapper 的 Gradle 版本。在将发行版 URL 写入属性文件之前,会对其进行验证。

允许使用以下标签:

--distribution-type

用于 Wrapper 的 Gradle 发行版类型。可用的选项是 binall。默认值为 bin

--gradle-distribution-url

指向 Gradle 发行版 ZIP 文件的完整 URL。此选项使 --gradle-version--distribution-type 变得多余,因为 URL 已经包含了这些信息。如果您想在公司网络内部托管 Gradle 发行版,此选项非常有用。在将 URL 写入属性文件之前,会对其进行验证。

--gradle-distribution-sha256-sum

用于验证下载的 Gradle 发行版的 SHA256 哈希值。

--network-timeout

下载 Gradle 发行版时使用的网络超时时间(以毫秒为单位)。默认值为 10000

--no-validate-url

禁用对配置的发行版 URL 的验证。

--validate-url

启用对配置的发布 URL 的验证。默认情况下启用。

如果发布 URL 使用 `--gradle-version` 或 `--gradle-distribution-url` 配置,则通过在 `https` 方案的情况下发送 HEAD 请求或在 `file` 方案的情况下检查文件是否存在来验证 URL。

假设以下用例来说明命令行选项的使用。您希望使用版本 8.7 生成 Wrapper,并使用 `-all` 发布来启用您的 IDE 以启用代码完成并能够导航到 Gradle 源代码。

以下命令行执行捕获了这些要求

$ gradle wrapper --gradle-version 8.7 --distribution-type all
> Task :wrapper

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

结果,您可以在 Wrapper 属性文件中找到所需的信息(生成的发布 URL)

distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip

让我们看一下以下项目布局来说明预期的 Wrapper 文件

.
├── a-subproject
│   └── build.gradle.kts
├── settings.gradle.kts
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
.
├── a-subproject
│   └── build.gradle
├── settings.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat

Gradle 项目通常提供一个 `settings.gradle(.kts)` 文件和每个子项目一个 `build.gradle(.kts)` 文件。Wrapper 文件与项目根目录中的 `gradle` 目录并存。

以下列表解释了它们的用途

gradle-wrapper.jar

包含用于下载 Gradle 发布的代码的 Wrapper JAR 文件。

gradle-wrapper.properties

一个属性文件,负责配置 Wrapper 运行时行为,例如与该版本兼容的 Gradle 版本。请注意,更通用的设置,例如 配置 Wrapper 使用代理,需要进入 不同的文件

gradlew, gradlew.bat

一个 shell 脚本和一个 Windows 批处理脚本,用于使用 Wrapper 执行构建。

您可以继续 使用 Wrapper 执行构建,而无需安装 Gradle 运行时。如果您正在处理的项目不包含这些 Wrapper 文件,则需要 生成它们

使用 Gradle Wrapper

始终建议使用 Wrapper 执行构建,以确保构建的可靠、受控和标准化执行。使用 Wrapper 就像使用 Gradle 安装运行构建一样。根据您的操作系统,您运行 `gradlew` 或 `gradlew.bat` 而不是 `gradle` 命令。

以下控制台输出演示了在 Windows 计算机上使用 Wrapper 的 Java 项目

$ gradlew.bat build
Downloading https://services.gradle.org/distributions/gradle-5.0-all.zip
.....................................................................................
Unzipping C:\Documents and Settings\Claudia\.gradle\wrapper\dists\gradle-5.0-all\ac27o8rbd0ic8ih41or9l32mv\gradle-5.0-all.zip to C:\Documents and Settings\Claudia\.gradle\wrapper\dists\gradle-5.0-al\ac27o8rbd0ic8ih41or9l32mv
Set executable permissions for: C:\Documents and Settings\Claudia\.gradle\wrapper\dists\gradle-5.0-all\ac27o8rbd0ic8ih41or9l32mv\gradle-5.0\bin\gradle

BUILD SUCCESSFUL in 12s
1 actionable task: 1 executed

如果 Gradle 发布在机器上不可用,Wrapper 将下载它并将其存储在本地文件系统中。只要 Gradle 属性中的发布 URL 不变,任何后续的构建调用都会重用现有的本地发布。

Wrapper shell 脚本和批处理文件位于单个或多项目 Gradle 构建的根目录中。如果您想从子项目目录执行构建,例如 `../../gradlew tasks`,则需要引用这些文件的正确路径。

升级 Gradle Wrapper

项目通常希望与时俱进,升级其 Gradle 版本以利用新功能和改进。

升级 Gradle 版本的一种方法是手动更改 Wrapper 的 gradle-wrapper.properties 文件中的 distributionUrl 属性。

更好的推荐方法是运行 wrapper 任务并提供目标 Gradle 版本,如 添加 Gradle Wrapper 中所述。使用 wrapper 任务可确保对 Wrapper shell 脚本或批处理文件进行的任何针对特定 Gradle 版本的优化都将应用于项目。

像往常一样,您应该将对 Wrapper 文件的更改提交到版本控制中。

请注意,运行一次 wrapper 任务只会更新 gradle-wrapper.properties,而不会触及 gradle-wrapper.jar 中的 wrapper 本身。这通常没问题,因为即使使用旧的 wrapper 文件,也可以运行新版本的 Gradle。

如果您希望所有 wrapper 文件完全更新,则需要再次运行 wrapper 任务。

以下命令将 Wrapper 升级到最新版本

$ ./gradlew wrapper --gradle-version latest

BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed

以下命令将 Wrapper 升级到特定版本

$ ./gradlew wrapper --gradle-version 8.7

BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed

升级 Wrapper 后,您可以通过执行 ./gradlew --version 来检查它是否为预期版本。

不要忘记再次运行 wrapper 任务以下载 Gradle 分发二进制文件(如果需要)并更新 gradlewgradlew.bat 文件。

自定义 Gradle Wrapper

大多数 Gradle 用户对 Wrapper 的默认运行时行为感到满意。但是,组织策略、安全约束或个人偏好可能要求您深入了解 Wrapper 的自定义。

值得庆幸的是,内置的 wrapper 任务公开了许多选项,可以根据您的需要调整运行时行为。大多数配置选项由底层任务类型 Wrapper 公开。

假设您厌倦了每次升级 Wrapper 时都在命令行上定义 -all 分发类型。您可以通过重新配置 wrapper 任务来节省一些键盘操作。

build.gradle.kts
tasks.wrapper {
    distributionType = Wrapper.DistributionType.ALL
}
build.gradle
tasks.named('wrapper') {
    distributionType = Wrapper.DistributionType.ALL
}

配置完成后,运行 ./gradlew wrapper --gradle-version 8.7 即可在 Wrapper 属性文件中生成 distributionUrl 值,该值将请求 -all 分发版。

distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip

查看 API 文档 以获取有关可用配置选项的更详细说明。您还可以在 Gradle 分发版中找到 配置 Wrapper 的各种示例

经过身份验证的 Gradle 分发版下载

Gradle Wrapper 可以使用 HTTP 基本身份验证从服务器下载 Gradle 分发版。这使您能够将 Gradle 分发版托管在受保护的私有服务器上。

您可以根据您的用例以两种不同的方式指定用户名和密码:作为系统属性或直接嵌入到 distributionUrl 中。系统属性中的凭据优先于嵌入到 distributionUrl 中的凭据。

HTTP 基本身份验证仅应与 HTTPS URL 结合使用,而不应与普通 HTTP URL 结合使用。使用基本身份验证,用户凭据将以明文形式发送。

系统属性可以在用户主目录中的 .gradle/gradle.properties 文件中指定,也可以通过其他 方式 指定。

要指定 HTTP 基本身份验证凭据,请将以下行添加到系统属性文件

systemProp.gradle.wrapperUser=username
systemProp.gradle.wrapperPassword=password

gradle/wrapper/gradle-wrapper.properties 文件中的 distributionUrl 中嵌入凭据也有效。请注意,此文件将被提交到您的源代码控制系统中。

嵌入到 distributionUrl 中的共享凭据仅应在受控环境中使用。

要在 distributionUrl 中指定 HTTP 基本身份验证凭据,请添加以下行

distributionUrl=https://username:password@somehost/path/to/gradle-distribution.zip

这可以与代理一起使用,无论代理是否经过身份验证。有关如何配置 Wrapper 以使用代理的更多信息,请参阅 通过代理访问网络

下载的 Gradle 分发版的验证

Gradle Wrapper 允许通过 SHA-256 哈希和比较来验证下载的 Gradle 分发版。这通过防止中间人攻击者篡改下载的 Gradle 分发版来提高安全性。

要启用此功能,请下载与您要验证的 Gradle 分发版关联的 .sha256 文件。

下载 SHA-256 文件

您可以从 稳定版本候选版本和夜间版本 下载 .sha256 文件。该文件的格式为单行文本,即对应 zip 文件的 SHA-256 哈希值。

您还可以参考 Gradle 分发版校验和列表

配置校验和验证

将下载的(SHA-256 校验和)哈希值添加到 gradle-wrapper.properties 中,使用 distributionSha256Sum 属性,或者在命令行中使用 --gradle-distribution-sha256-sum

distributionSha256Sum=371cb9fbebbe9880d147f59bab36d61eee122854ef8c9ee1ecf12b82368bcf10

如果配置的校验和与托管分发的服务器上找到的校验和不匹配,Gradle 将报告构建失败。只有在配置的 Wrapper 分发尚未下载的情况下才会执行校验和验证。

如果 gradle-wrapper.properties 包含 distributionSha256Sum,但任务配置未定义校验和,则 Wrapper 任务将失败。当 Gradle 版本没有改变时,执行 Wrapper 任务会保留 distributionSha256Sum 配置。

验证 Gradle Wrapper JAR 的完整性

Wrapper JAR 是一个二进制文件,将在开发人员和构建服务器的计算机上执行。与所有此类文件一样,您应该在执行它之前确保它是可信的。

由于 Wrapper JAR 通常被检入项目的版本控制系统,因此恶意攻击者有可能通过提交仅升级 Gradle 版本的拉取请求来替换原始 JAR。

为了验证 Wrapper JAR 的完整性,Gradle 创建了一个 GitHub Action,它会自动检查拉取请求中的 Wrapper JAR 与已知良好校验和列表的匹配情况。

Gradle 还发布了 所有版本的校验和(除了版本 3.3 到 4.0.2,它们没有生成可重复的 JAR),因此您可以手动验证 Wrapper JAR 的完整性。

在 GitHub 上自动验证 Gradle Wrapper JAR

GitHub Action 是与 Gradle 分开发布的,因此请查看其文档以了解如何将其应用于您的项目。

手动验证 Gradle Wrapper JAR

您可以手动验证 Wrapper JAR 的校验和,以确保它没有被篡改,方法是在主要操作系统之一上运行以下命令。

手动验证 Wrapper JAR 在 Linux 上的校验和

$ cd gradle/wrapper
$ curl --location --output gradle-wrapper.jar.sha256 \
       https://services.gradle.org/distributions/gradle-{gradleVersion}-wrapper.jar.sha256
$ echo " gradle-wrapper.jar" >> gradle-wrapper.jar.sha256
$ sha256sum --check gradle-wrapper.jar.sha256
gradle-wrapper.jar: OK

手动验证 Wrapper JAR 在 macOS 上的校验和

$ cd gradle/wrapper
$ curl --location --output gradle-wrapper.jar.sha256 \
       https://services.gradle.org/distributions/gradle-{gradleVersion}-wrapper.jar.sha256
$ echo " gradle-wrapper.jar" >> gradle-wrapper.jar.sha256
$ shasum --check gradle-wrapper.jar.sha256
gradle-wrapper.jar: OK

手动验证 Windows 上 Wrapper JAR 的校验和(使用 PowerShell)

> $expected = Invoke-RestMethod -Uri https://services.gradle.org/distributions/gradle-8.7-wrapper.jar.sha256
> $actual = (Get-FileHash gradle\wrapper\gradle-wrapper.jar -Algorithm SHA256).Hash.ToLower()
> @{$true = 'OK: Checksum match'; $false = "ERROR: Checksum mismatch!`nExpected: $expected`nActual:   $actual"}[$actual -eq $expected]
OK: Checksum match

解决校验和不匹配问题

如果校验和与预期不符,则很可能是 wrapper 任务未使用升级后的 Gradle 发行版执行。

您应该首先检查实际校验和是否与其他 Gradle 版本匹配。

以下是在主要操作系统上生成 Wrapper JAR 实际校验和的命令。

生成 Linux 上 Wrapper JAR 的校验和

$ sha256sum gradle/wrapper/gradle-wrapper.jar
d81e0f23ade952b35e55333dd5f1821585e887c6d24305aeea2fbc8dad564b95 gradle/wrapper/gradle-wrapper.jar

生成 macOS 上 Wrapper JAR 的实际校验和

$ shasum --algorithm=256 gradle/wrapper/gradle-wrapper.jar
d81e0f23ade952b35e55333dd5f1821585e887c6d24305aeea2fbc8dad564b95 gradle/wrapper/gradle-wrapper.jar

生成 Windows 上 Wrapper JAR 的实际校验和(使用 PowerShell)

> (Get-FileHash gradle\wrapper\gradle-wrapper.jar -Algorithm SHA256).Hash.ToLower()
d81e0f23ade952b35e55333dd5f1821585e887c6d24305aeea2fbc8dad564b95

一旦您知道实际校验和,请检查它是否列在 https://gradle.org.cn/release-checksums/ 上。如果它被列出,您已验证 Wrapper JAR 的完整性。如果生成 Wrapper JAR 的 Gradle 版本与 gradle/wrapper/gradle-wrapper.properties 中的版本不匹配,则可以安全地再次运行 wrapper 任务以更新 Wrapper JAR。

如果校验和未在页面上列出,则 Wrapper JAR 可能来自里程碑、候选发布版或每日构建,或者可能由 Gradle 3.3 到 4.0.2 生成。尝试找出它是如何生成的,但在得到证实之前将其视为不可信。如果您认为 Wrapper JAR 已被破坏,请通过发送电子邮件至 [email protected] 告知 Gradle 团队。