JCenter 关闭对 Gradle 构建的影响

目录

简介

ℹ️ 2024 年 7 月 15 日更新
请参阅 我们最近的博文,了解关于插件门户和 JCenter 的最新信息。

2021 年 2 月 3 日,JFrog 宣布他们将关闭 Bintray 和 JCenter。这篇文章告诉您需要了解和采取哪些措施,以避免对您的构建管道造成中断。

您的构建可能会受到此次关闭的多种方式的影响

此外,您应该注意从一个仓库迁移到另一个仓库时的 安全注意事项

更新:JFrog 已决定无限期地将 JCenter 保留为只读仓库。JCenter 不再接受新的软件包和版本。所有 Bintray 服务均已关闭。

背景 #

JCenter 是一个中央构件仓库,类似于 Maven Central。软件项目使用 JCenter 将他们的软件分发给其他人。JCenter 也充当 Maven Central 的镜像,因此 Maven Central 上可用的任何依赖项在 JCenter 上也可用(但反之则不然)。

Bintray 是一个管理层,软件项目使用它来发布和推广软件包到 JCenter。Bintray 还允许用户创建与 JCenter 隔离的公共用户特定仓库。

这些服务都受到了关闭的影响。

对构建的影响 #

默认情况下,Gradle 不会向您的项目添加构件仓库;但是,Gradle 确实提供了一个 便捷的 API 用于使用 JCenter 仓库。

Gradle Build Init 插件 生成使用 JCenter 仓库来解析依赖项的构建模板。在许多代码示例和文档中,JCenter 被用作示例仓库。

您的构建很可能依赖于 JCenter。我们已经在 GitHub 上找到了超过一百万个使用 JCenter 和 Gradle 的 Git 仓库。

为了阻止新项目使用 JCenter,我们将从我们的示例和 init 模板中删除 JCenter。新的默认设置将是 Maven Central。Gradle 本身与 JCenter 或 Maven Central 没有固有的联系,因此您始终可以切换到您选择的任何其他仓库。此更改将在下一个 Gradle 版本 – Gradle 7.0 中生效。

Gradle 7.0 还将弃用使用 jcenter() 来解析依赖项。您仍然可以使用 JCenter 作为仓库,但 Gradle 将发出弃用警告。jcenter() 方法将在下一个主要版本中删除。

Example of deprecation message in a build scan

托管在 JCenter 上的软件包需要在 2021 年 3 月 31 日之后找到替代仓库来提供更新。许多软件包可能会迁移到 Maven Central,但有些软件包可能根本不会迁移,有些可能只会发布新版本。废弃的项目可能会在其他维护者接管后更改其坐标。这意味着从 JCenter 迁移到另一个仓库将比简单地使用不同的仓库 URL 更困难。

根据当前的计划,使用 JCenter 的构建将能够在 2022 年 2 月 1 日之前解析依赖项而无需更改。在那之后,如果您继续使用 JCenter,则无法保证您能够构建您的软件。

您该怎么做? #

请按照以下步骤操作,为 JCenter 关闭做好构建准备

  1. 确定您的构建是否使用 JCenter
  2. 从您的构建中删除 JCenter,并将其替换为 Maven Central。Gradle 也为该仓库提供了一个 便捷的 API
  3. 运行您的构建管道,看看一切是否仍然正常工作。

如何知道您是否正在使用 JCenter? #

您可以通过几种不同的方式检查您是否正在使用 JCenter。

多年来,JCenter 一直是 Android 项目的默认仓库。如果您正在构建 Android 应用程序,您可能正在使用 JCenter。

Gradle 插件门户目前隐式地镜像 JCenter。如果您正在使用插件门户(通过 gradlePluginPortal() 或 URL plugins.gradle.org/m2)来解析您的应用程序的依赖项,您可能依赖于 JCenter。您应该避免将插件门户用作仓库,除非是 Gradle 插件项目。

请注意,Bintray 还允许任何用户运行他们自己的带有自定义 URL 的公共仓库。这也受到了关闭的影响。您应该检查您是否正在使用 URL 以 dl.bintray.com 开头的仓库。由于这些仓库可能包含任何内容,您需要弄清楚您从这些仓库中使用了哪些依赖项,以及它们可能迁移到哪里。

检查您的构建扫描 #

如果您正在使用 Gradle Enterprise 或公共 构建扫描 服务,您可以检查哪个仓库被 用于解析您的依赖项

Repositories in a build scan

这将帮助您识别哪些依赖项最有可能受到关闭的影响。

检查您的构建文件 #

如果您在构建脚本中声明了您的仓库,您可以查找 jcenter() 或 URL jcenter.bintray.com。

您正在寻找类似这样的内容

repositories {
    jcenter()
}

repositories {
    maven {
       url = "https://jcenter.bintray.com"
    }
}

repositories {
    maven {
       url = "https://dl.bintray.com/<some user name>"
    }
}

检查您的插件 #

任何自定义插件都可能向您的项目添加仓库。内置的 Gradle 插件(如 java-library)不会向您的项目添加仓库。

您正在寻找使用 jcenter() API 以编程方式添加 JCenter 作为仓库的插件。

与您的团队核实 #

您可能在您的构建脚本或插件中找不到任何对 JCenter 的引用,但您可能仍然在使用 JCenter。如果您有您使用的内部镜像或公司代理仓库,您需要检查该仓库是否使用 JCenter。

对付费 JFrog Cloud 客户的影响可能有所不同,因此请直接联系 JFrog 以了解如果您的内部镜像由 JFrog 提供,您是否可以继续使用 JCenter。

解决来自 JCenter 的依赖项问题 #

您可以使用 gradle dependencies(或构建扫描)来确定哪些依赖项未被解析或它们可能发生了怎样的变化。如果 Gradle 无法从任何仓库解析依赖项,构建也会因解析错误而失败。

在下面的示例中,您可以看到在切换到 Maven Central 后,Gradle 无法解析 trove4j 依赖项。

在控制台中: 控制台上未解析的依赖项

在构建扫描中: 构建扫描中未解析的依赖项

此时,如果该软件包仅在 JCenter 上可用,您的选择是

  • 等待维护者迁移到另一个仓库(例如,Maven Central)
  • 找到另一个在 Maven Central 上可用的等效软件包
  • 完全删除您对该软件包的依赖
  • 将软件包复制到您自己的内部仓库

如果您的构建可以从另一个仓库解析其大部分依赖项,您可以继续使用 JCenter 来处理少数仅在那里可用的软件包。您可以使用 内容过滤器,防止仅在 JCenter 上可用的新软件包被引入到您的构建中。这可以防止 Gradle 在 JCenter 中查找所有软件包。

例如,许多 Android 项目依赖于 Trove4J 库,在撰写本文时,该库仅可从 JCenter 获得。我们可以使用 内容过滤器,仅允许来自 JCenter 的 org.jetbrains.trove4j 组中的构件。我们还将 jcenter() 放在最后,以便首先搜索 Maven Central。

repositories {
    mavenCentral()
    jcenter {
        content {
            //  org.jetbrains.trove4j is only available in JCenter
            includeGroup("org.jetbrains.trove4j")
        }
    }
}

对 Gradle 插件的影响 #

在幕后,Gradle 插件门户 使用 JCenter 来解析插件的依赖项。我们将在最终关闭之前将插件门户从 JCenter 迁移出来。在插件门户从 JCenter 迁移出来期间,构建无需进行更改。

解决现有插件 #

现有插件将继续以与今天相同的方式解析。您的构建无需进行任何更改。

发布新的或更新的插件 #

如果您正在使用 com.gradle.plugin-publish 发布您的插件,则您不会受到影响。只需仔细检查您的构建是否没有直接使用 JCenter。

如果您正在将您的插件发布到 Bintray,您将需要使用 com.gradle.plugin-publish 插件 来发布您的插件的新版本。您越早这样做越好。如果您有疑问或问题,我们可以提供帮助。

我们将在 2021 年 3 月 31 日自动迁移所有发布到 Bintray 的插件。在那之后,我们将不再同步发布到 Bintray 的插件。此迁移对于解析依赖项的用户应该是透明的。

对发布到 Bintray 的软件包的影响 #

如果您正在使用 com.jfrog.bintray 插件将您的构建发布到 Bintray,您需要找到另一个仓库来托管您的软件包。您也许可以使用 内置的 maven-publish 进行发布。

如果您正在迁移到 Maven Central,io.github.gradle-nexus.publish-plugin 插件可以自动执行发布到 Nexus 和 Maven Central 的过程。

安全注意事项 #

在从 JCenter 迁移到另一个仓库之前,您应该考虑一些安全注意事项。

正如我们在最近几年看到的那样,依赖项混淆命名空间冲突 可能是供应链攻击的严重危险。这些漏洞都依赖于使用不受信任的构件来代替受信任的构件。

当您更改用于解析依赖项的仓库列表时,您可能会在不经意间将自己暴露于这些类型的攻击。

例如,假设您的构建使用 JCenter 和另一个不太流行的仓库(又名 LessPopularCenter)来解析依赖项(按此顺序),并且您的构建依赖于 com.example:foo:1.0。软件包 com.example:foo 仅发布到 JCenter,但其他人已设法将 com.example:foo:1.0 的副本放在 LessPopularCenter 上。只要 JCenter 是 Gradle 检查依赖项的第一个位置,您的构建将始终获得官方软件包。

如果您删除 JCenter 并将其替换为 Maven Central(其中没有 com.example:foo 的副本),您的构建可能仍然能够解析 com.example:foo,因为 LessPopularCenter 有它的副本。不幸的是,无法保证 LessPopularCenter 上的副本与官方软件包相同。

如果您想要强烈保证您现在依赖的构件是相同的,或者来自同一受信任方,您应该启用 依赖项验证。启用后,Gradle 会自动对从仓库解析的所有依赖项执行依赖项验证。这将帮助您检测依赖项构件的意外更改、被破坏的构件或新的不受信任的构件来源。

依赖项验证需要一些前期设置。您需要指定一个受信任密钥列表,用于验证签名的构件。对于未签名的构件,您需要为每个构件指定预期的校验和。

依赖项验证失败并不一定意味着发生了邪恶的事情。依赖项元数据和构件很混乱。有时,对于同一版本的软件包,来自两个仓库的构件不同是有合法原因的。如果软件包分别发布到 JCenter 和 Maven Central,则它可能被构建了两次,并生成了行为相同的不同构件。这意味着即使您从两个仓库解析“相同”版本,当您逐字节比较构件时,您也会得到不同的结果。在这种情况下,您可以告诉 Gradle 接受两个校验和都有效

反馈 #

如果您有任何问题,请在我们的 论坛Gradle 社区 Slack 上告知我们。

讨论