执行任何 Gradle 构建的推荐方法是借助 Gradle Wrapper(简称“Wrapper”)。 Wrapper 是一个脚本,它调用声明的 Gradle 版本,必要时预先下载它。因此,开发人员可以快速启动并运行 Gradle 项目,而无需遵循手动安装流程,从而为您的公司节省时间和金钱。

wrapper workflow
图 1. Wrapper 工作流程

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

  • 在给定的 Gradle 版本上标准化项目,从而实现更可靠和健壮的构建。

  • 为不同的用户和执行环境(例如 IDE 或持续集成服务器)提供新的 Gradle 版本就像更改 Wrapper 定义一样简单。

那么它是怎样工作的?对于用户,通常有三种不同的工作流程:

以下部分更详细地解释了这些用例中的每一个。

添加 Gradle 包装器

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

每个 vanilla Gradle 构建都带有一个名为 wrapper 的内置任务。 列出任务 时,您将能够在“构建设置任务”组下找到列出的任务。执行 wrapper 任务会在项目目录中生成必要的 Wrapper 文件。

Running the Wrapper task
$ gradle wrapper
> Task :wrapper

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

要使包装文件可供其他开发人员和执行环境使用,您需要将它们签入版本控制。包括 JAR 文件在内的所有 Wrapper 文件的大小都非常小。将 JAR 文件添加到版本控制是预期的。一些组织不允许项目将二进制文件提交给版本控制。目前,该方法没有其他选择。

生成的 Wrapper 属性文件 gradle/wrapper/gradle-wrapper.properties 存储有关 Gradle 分发的信息。

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

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

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

  • (可选)下载 gradle 分发时使用的超时(以毫秒为单位)。

gradle/wrapper/gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip

所有这些方面都可以在生成包装文件时借助以下命令行选项进行配置。

--gradle-version

用于下载和执行 Wrapper 的 Gradle 版本。

允许使用以下标签:

--distribution-type

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

--gradle-distribution-url

指向 Gradle 分发 ZIP 文件的完整 URL。使用此选项会使 --gradle-version--distribution-type 过时,因为 URL 已包含此信息。如果您想在公司网络内托管 Gradle 发行版,此选项非常有用。

--gradle-distribution-sha256-sum

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

--network-timeout

下载 gradle 分发时使用的网络超时,以毫秒为单位。默认值为 10000

让我们假设以下用例来说明命令行选项的使用。您希望生成版本为 8.1.1 的 Wrapper 并使用 -all 发行版使您的 IDE 能够启用代码完成并能够导航到 Gradle 源代码。这些要求由以下命令行执行捕获:

Providing options to Wrapper task
$ gradle wrapper --gradle-version 8.1.1 --distribution-type all
> Task :wrapper

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

因此,您可以在 Wrapper 属性文件中找到所需的信息。

Example: The generated distribution URL
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip

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

KotlinGroovy
.
├── a-subproject
│   └── build.gradle.kts
├── settings.gradle.kts
├── 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 版本。请注意,更通用的设置,如 配置包装器以使用代理 ,需要进入 不同的文件

gradlew , gradlew.bat

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

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

使用 Gradle 包装器

建议始终使用 Wrapper 执行构建,以确保构建的可靠、受控和标准化执行。使用 Wrapper 看起来几乎与使用 Gradle 安装运行构建完全一样。根据操作系统,您可以运行 gradlewgradlew.bat 而不是 gradle 命令。以下控制台输出演示了在 Windows 机器上为基于 Java 的项目使用 Wrapper。

Executing the build with the Wrapper batch file
$ 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 包装器

项目通常希望与时俱进并升级其 Gradle 版本以从新功能和改进中受益。升级 Gradle 版本的一种方法是手动更改 Wrapper 的 gradle-wrapper.properties 文件中的 distributionUrl 属性。更好的推荐选项是运行 wrapper 任务并提供目标 Gradle 版本,如 添加 Gradle 包装器 中所述。使用 wrapper 任务可确保将使用该特定 Gradle 版本对 Wrapper shell 脚本或批处理文件所做的任何优化应用于项目。像往常一样,您应该将对 Wrapper 文件的更改提交给版本控制。

请注意,运行一次包装器任务将仅更新 gradle-wrapper.properties,但不会影响 gradle-wrapper.jar 中的包装器本身。这通常很好,因为即使使用旧的包装文件也可以运行新版本的 Gradle。如果你仍然想要全部要使包装文件完全最新,您需要再次运行 wrapper 任务。

使用 Gradle wrapper 任务生成包装器,指定一个版本。默认为当前版本。升级包装器后,您可以通过执行 ./gradlew --version 检查它是否是您期望的版本。

Example: Upgrading the Wrapper to the latest version
$ ./gradlew wrapper --gradle-version latest

BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed
Example: Upgrading the Wrapper to a specific version
$ ./gradlew wrapper --gradle-version 8.1.1

BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed

自定义 Gradle 包装器

大多数 Gradle 用户都对 Wrapper 的默认运行时行为感到满意。但是,组织策略、安全约束或个人偏好可能需要您更深入地自定义 Wrapper。值得庆幸的是,内置的 wrapper 任务公开了许多选项,可以根据您的需要调整运行时行为。大多数配置选项由底层任务类型 Wrapper 公开。

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

KotlinGroovy
build.gradle.kts
tasks.wrapper {
    distributionType = Wrapper.DistributionType.ALL
}

配置到位后,运行 ./gradlew wrapper --gradle-version 8.1.1 足以在 Wrapper 属性文件中生成一个 distributionUrl 值,该值将请求 -all 分发。

The generated distribution URL
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip

查看 API 文档以获得可用配置选项的更多详细描述。您还可以在 Gradle 发行版中找到用于配置 Wrapper 的各种示例。

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

Gradle Wrapper 可以使用 HTTP 基本身份验证从服务器下载 Gradle 发行版。这使您能够在受保护的私有服务器上托管 Gradle 发行版。您可以根据您的用例以两种不同的方式指定用户名和密码:作为系统属性或直接嵌入到 distributionUrl 中。系统属性中的凭据优先于 distributionUrl 中嵌入的凭据。

安全警告

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

可以在用户主目录的 .gradle/gradle.properties 文件中使用系统属性,或者通过其他方式,请参阅 Gradle 配置属性

Specifying the HTTP Basic Authentication credentials using system properties
systemProp.gradle.wrapperUser=username
systemProp.gradle.wrapperPassword=password

gradle/wrapper/gradle-wrapper.properties 文件的 distributionUrl 中嵌入凭据也可以。请注意,此文件将提交到您的源代码控制系统中。 distributionUrl 中嵌入的共享凭据只能在受控环境中使用。

Specifying the HTTP Basic Authentication credentials in distributionUrl
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 分发校验和列表

配置校验和验证

使用 distributionSha256Sum 属性或在命令行上使用 --gradle-distribution-sha256-sum 将下载的哈希和添加到 gradle-wrapper.properties

Configuring SHA-256 checksum verification
distributionSha256Sum=371cb9fbebbe9880d147f59bab36d61eee122854ef8c9ee1ecf12b82368bcf10

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

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

验证 Gradle Wrapper JAR 的完整性

Wrapper JAR 是一个二进制文件,将在开发人员和构建服务器的计算机上执行。与所有此类文件一样,您应该在执行之前确保它是可信的。由于 Wrapper JAR 通常被签入项目的版本控制系统,恶意行为者有可能通过提交看似只升级 Gradle 版本的拉取请求,用修改后的 JAR 替换原始 JAR 。

为了验证 Wrapper JAR 的完整性,Gradle 创建了一个 GitHub 动作,它根据已知的良好校验和列表自动检查拉取请求中的 Wrapper JAR。 Gradle 还发布了 所有版本的校验和(3.3 到 4.0.2 版本除外,它们不生成可重现的 JAR),因此您可以手动验证 Wrapper JAR 的完整性。

在 GitHub 上自动验证 Gradle Wrapper JAR

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

手动验证 Gradle Wrapper JAR

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

Manually verifying the checksum of the Wrapper JAR on Linux
$ cd gradle/wrapper
$ curl --location --output gradle-wrapper.jar.sha256 \
       https://services.gradle.org/distributions/gradle-8.1.1-wrapper.jar.sha256
$ echo "  gradle-wrapper.jar" >> gradle-wrapper.jar.sha256
$ sha256sum --check gradle-wrapper.jar.sha256
gradle-wrapper.jar: OK
Manually verifying the checksum of the Wrapper JAR on macOS
$ cd gradle/wrapper
$ curl --location --output gradle-wrapper.jar.sha256 \
       https://services.gradle.org/distributions/gradle-8.1.1-wrapper.jar.sha256
$ echo "  gradle-wrapper.jar" >> gradle-wrapper.jar.sha256
$ shasum --check gradle-wrapper.jar.sha256
gradle-wrapper.jar: OK
Manually verifying the checksum of the Wrapper JAR on Windows (using PowerShell)
> $expected = Invoke-RestMethod -Uri https://services.gradle.org/distributions/gradle-8.1.1-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 的实际校验和的命令:

Generating the actual checksum of the Wrapper JAR on Linux
$ sha256sum gradle/wrapper/gradle-wrapper.jar
d81e0f23ade952b35e55333dd5f1821585e887c6d24305aeea2fbc8dad564b95  gradle/wrapper/gradle-wrapper.jar
Generating the actual checksum of the Wrapper JAR on macOS
$ shasum --algorithm=256 gradle/wrapper/gradle-wrapper.jar
d81e0f23ade952b35e55333dd5f1821585e887c6d24305aeea2fbc8dad564b95  gradle/wrapper/gradle-wrapper.jar
Generating the actual checksum of the Wrapper JAR on Windows (using PowerShell)
> (Get-FileHash gradle\wrapper\gradle-wrapper.jar -Algorithm SHA256).Hash.ToLower()
d81e0f23ade952b35e55333dd5f1821585e887c6d24305aeea2fbc8dad564b95

知道实际校验和后,检查它是否列在 https://gradle.org/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 遭到破坏,请发送电子邮件至 security@gradle.com 告知 Gradle 团队。