Apache Ant是一个在 Java 世界中历史悠久的构建工具,尽管团队数量在减少,但仍然被广泛使用。虽然很灵活,但它缺乏约定以及 Gradle 提供的许多强大功能。迁移到 Gradle 是值得的,这样您的构建可以变得更精简、更简单、更快,同时仍然保留您在 Ant 中享受的灵活性。您还将受益于对多项目构建的强大支持以及易于使用、灵活的依赖关系管理。

从 Ant 迁移到 Gradle 的最大挑战是不存在标准 Ant 构建之类的东西。这使得提供具体指示变得困难。幸运的是,Gradle 与 Ant 具有一些出色的集成功能,可以使该过程相对顺利。从基于Ivy的依赖管理迁移并不困难,因为 Gradle 有一个基于依赖配置的类似模型,可与 Ivy 兼容的存储库配合使用。

我们将首先概述将构建从 Ant 迁移到 Gradle 时应考虑的事项,并提供一些有关如何进行的一般指南。

一般准则

当您将构建从 Ant 迁移到 Gradle 时,您应该记住您已经拥有的内容的性质以及您希望最终的结果。您想要一个反映现有 Ant 构建结构的 Gradle 构建吗?或者你想转向 Gradle 更惯用的东西?您正在寻找的主要好处是什么?

为了更好地理解,请考虑以下相反的场景:

  • 导入的构建通过ant.importBuild()

    这种方法快速、简单,并且适用于许多基于 Ant 的构建。您最终得到的构建实际上与原始 Ant 构建相同,只是您的 Ant 目标变成了 Gradle 任务。甚至目标之间的依赖关系也被保留。

    缺点是您仍在使用 Ant 构建,您必须继续维护它。您还会失go Gradle 约定、许多插件、依赖管理等的优势。您仍然可以使用增量构建信息来增强构建,但这比普通 Gradle 构建需要更多的努力。

  • 惯用的 Gradle 构建

    如果您想让您的构建面向未来,那么这就是您想要的结果。利用 Gradle 的约定和插件将产生更小、更易于维护的构建,并具有许多 Java 开发人员熟悉的结构。您还会发现更容易利用 Gradle 的强大功能来提高构建性能。

    主要缺点是执行迁移需要额外的工作,特别是如果现有构建很复杂并且具有许多项目间依赖项。然而,这些构建通常会从转向惯用的 Gradle 中获益最多。此外,Gradle 提供了许多可以简化迁移的功能,例如直接从 Gradle 构建使用核心和自定义 Ant 任务的能力。

理想情况下,从长远来看,你希望最终能接近第二种选择,但你不必一举实现这一目标。

以下是一系列步骤,可帮助您决定要采取的方法以及如何实施:

  1. 并排保留旧的 Ant 构建和新的 Gradle 构建。

    您知道 Ant 构建是有效的,因此您应该保留它,直到您确信 Gradle 构建会生成所有相同的工件并且在其他方​​面可以满足您的需要。这也意味着用户可以尝试 Gradle 构建,而无需创建源树的新副本。

    在准备好进行切换之前,请勿尝试更改构建的目录和文件结构。

  2. 开发一种机制来验证两个构建是否生成相同的工件。

    这是确保您的部署和测试不会中断的至关重要的一步。即使是很小的更改(例如 JAR 中清单文件的内容)也可能会导致问题。如果您的 Gradle 构建产生与 Ant 构建相同的输出,这将使您和其他人有信心进行切换,并更轻松地实施可带来最大收益的重大更改。

  3. 决定是否有多项目构建。

    多项目构建通常比单项目构建更难迁移并且需要更多工作。我们在迁移多项目构建部分提供了一些专门的建议来帮助完成该过程。

  4. 弄清楚每个项目要使用哪些插件。

    我们预计绝大多数 Ant 构建都是针对基于 JVM 的项目,其中有大量插件可以提供您需要的大量功能。 Gradle 插件包括随 Gradle 打包的核心插件以及插件门户上有用的社区插件。

    即使Java 插件或其衍生产品之一(例如Java 库插件)不太适合您的构建,您至少应该考虑使用基本插件来执行其生命周期任务。

  5. 导入 Ant 构建或从头开始创建 Gradle 构建。

    此步骤很大程度上取决于您构建的要求。如果选择的 Gradle 插件可以完成 Ant 构建所做的绝大多数工作,那么创建一个不依赖于 Ant 构建的全新 Gradle 构建脚本可能是有意义的。您可以自己实现缺失的部分,也可以使用现有的 Ant 任务

    另一种方法是将Ant 构建导入到 Gradle 构建脚本中,并逐步替换 Ant 构建功能。这允许您在每个阶段都有一个有效的 Gradle 构建,但需要一些工作才能使 Gradle 任务与 Ant 任务正常工作。您可以在使用导入的构建中了解更多相关信息。

  6. 配置现有目录和文件结构的构建

    Gradle 利用约定来消除与旧版本相关的大部分样板,并让用户在熟悉这些约定后更轻松地使用新版本。但这并不意味着您必须遵循它们。

    Gradle 提供了许多配置选项,可以进行良好程度的自定义。这些选项通常通过提供约定的插件提供。例如,生产Java代码的标准源目录结构—— src/main/java由Java Plugin提供,它允许您配置不同的源路径。许多路径可以通过项目对象的属性进行修改。

  7. 如果您愿意,可以迁移到标准 Gradle 约定

    一旦您确信 Gradle 构建会生成与 Ant 构建相同的工件和其他资源,您就可以考虑迁移到标准约定,例如源目录路径。这样做将允许您删除覆盖这些约定所需的额外配置。新的团队成员还会发现更改后的构建工作更加容易。

    由您决定这一步是否值得付出努力和潜在的破坏,而这又取决于您的具体构建和团队。

本章的其余部分介绍了您在迁移过程中可能会遇到的一些常见场景,例如依赖项管理和使用 Ant 任务。

使用导入的构建

配置缓存 不支持导入 Ant 构建。您需要完成到 Gradle 的转换才能获得缓存的好处。

许多迁移的第一步将涉及使用ant.importBuild().那么如何在不立即替换所有内容的情况下转向标准 Gradle 构建呢?

要记住的重要一点是,Ant 目标成为真正的 Gradle 任务,这意味着您可以执行诸如修改其任务依赖项、附加额外任务操作等操作。这允许您用本机 Gradle 任务替换等效的 Ant 任务,并维护与其他现有任务的任何链接。

举个例子,假设您有一个 Java 库项目想要从 Ant 迁移到 Gradle。 Gradle 构建脚本具有导入 Ant 构建的行,现在想要使用标准 Gradle 机制来编译 Java 源文件。但是,您希望继续使用package创建库的 JAR 文件的现有任务。

以图表的形式,该场景如下所示,其中每个框代表一个目标/任务:

蚂蚁任务迁移

这个想法是用标准 GradlecompileJava任务替代 Antbuild任务。此替换涉及几个步骤:

  1. 应用Java 库插件

    这提供了compileJava图中所示的任务。

  2. 重命名旧build任务。

    该名称与基本插件(通过 Java 库插件)提供的build标准任务冲突。build

  3. 配置编译以使用现有的目录结构。

    Ant 构建很可能不符合标准 Gradle 目录结构,因此您需要告诉 Gradle 在哪里可以找到源文件以及在哪里放置已编译的类,以便package可以找到它们。

  4. 更新任务依赖关系。

    compileJava必须依赖preparepackage必须依赖compileJava而不是ant_build、并且assemble必须依赖package而不是标准 Gradlejar任务。

应用该插件就像plugins {}在 Gradle 构建脚本的开头(即 before )插入一个块一样简单ant.importBuild()。以下是应用 Java 库插件的方法:

build.gradle.kts
plugins {
    `java-library`
}
build.gradle
plugins {
    id 'java-library'
}

要重命名任务,请使用接受转换器的AntBuilder.importBuild()build变体,如下所示:

build.gradle.kts
ant.importBuild("build.xml") { oldTargetName ->
    if (oldTargetName == "build") "ant_build" else oldTargetName  (1)
}
build.gradle
ant.importBuild('build.xml') { String oldTargetName ->
    return oldTargetName == 'build' ? 'ant_build' : oldTargetName  (1)
}
1 将目标重命名buildant_build并保持所有其他目标不变

构建 Java 和 JVM 项目中描述了为源配置不同的路径。您可以以类似的方式更改已编译类的输出目录。

例如,如果原始 Ant 构建将这些路径存储在 Ant 属性中;src.dir用于 Java 源文件和classes.dir输出。以下是配置 Gradle 使用这些路径的方法:

build.gradle.kts
sourceSets {
    main {
        java.setSrcDirs(listOf(ant.properties["src.dir"]))
        java.destinationDirectory = file(ant.properties["classes.dir"] ?: layout.buildDirectory.dir("classes"))
    }
}
build.gradle
sourceSets {
    main {
        java {
            srcDirs = [ ant.properties['src.dir'] ]
            destinationDirectory = file(ant.properties['classes.dir'])
        }
    }
}

您最终应该切换到适合您的项目类型的标准目录结构,以便能够删除此自定义。

最后一步很简单,涉及使用Task.dependsOn属性和Task.dependsOn()方法来分离和链接任务。属性适合替换依赖项,而方法是添加到现有依赖项的首选方式。

以下是示例场景所需的任务依赖项配置,应在 Ant 构建导入之后进行:

build.gradle.kts
tasks {
    compileJava {
        dependsOn("prepare")  (1)
    }
    named("package") {
        setDependsOn(listOf(compileJava))  (2)
    }
    assemble {
        setDependsOn(listOf("package"))  (3)
    }
}
build.gradle
compileJava.dependsOn 'prepare'  (1)
tasks.named('package') { dependsOn = [ 'compileJava' ] }  (2)
assemble.dependsOn = [ 'package' ]  (3)
1 使编译取决于prepare任务
2 脱离package任务ant_build并使其依赖于compileJava
3 assemble与标准 Gradle任务分离jar并使其package依赖

这四个步骤将成功地将旧的 Ant 编译替换为 Gradle 实现。即使是这个小迁移也会让您受益于 Gradle增量 Java 编译的优势,从而实现更快的构建。

这是分阶段迁移的一个示例。在此阶段的编译中包含资源处理(例如属性文件)和打包可能更有意义。

您必须问自己的一个重要问题是每个阶段要迁移多少任务。一次性迁移的内容越多越好,但风险来自于 Ant 构建中受更改影响的自定义步骤数量。

例如,如果 Ant 构建遵循相当标准的编译、静态资源、打包和单元测试方法,那么可能值得将所有这些一起迁移。但是,如果构建对已编译的类执行一些额外的处理,或者在处理静态资源时执行一些独特的操作,则可能值得将这些任务拆分为单独的阶段。

管理依赖关系

Ant 构建通常采用两种方法之一来处理二进制依赖项(例如库):

  • 将它们与项目一起存储在本地“lib”目录中

  • 使用Apache Ivy来管理它们

它们各自需要不同的技术来迁移到 Gradle,但无论哪种情况,您都会发现该过程都很简单。让我们在以下各节中详细了解每种情况。

从目录提供依赖项

当您尝试迁移将其依赖项存储在本地或网络上的文件系统上的构建时,您应该考虑是否希望最终迁移到使用远程存储库的托管依赖项。这是因为您可以通过以下两种方式之一将文件系统依赖项合并到 Gradle 构建中:

如果您采用第一种方法,那么迁移到由 Maven 或 Ivy 兼容存储库提供的托管依赖项会更容易,但这样做需要所有文件都符合命名约定“<moduleName>-<version>.<extension>” 。

如果您将依赖项存储在标准 Maven 存储库布局中—— <repoDir>/<group>/<module>/<version>那么您可以使用URL 定义自定义 Maven 存储库file://

libs为了演示这两种技术,请考虑一个在其目录中具有以下库 JAR 的项目:

libs
├── our-custom.jar
├── awesome-framework-2.0.jar
└── utility-library-1.0.jar

该文件our-custom.jar没有版本号,因此必须将其添加为文件依赖项。另外两个 JAR 符合所需的命名约定,并且可以声明为从平面目录存储库检索的正常模块依赖项。

以下示例构建脚本演示了如何将所有这些库合并到构建中:

build.gradle.kts
repositories {
    flatDir {
        name = "libs dir"
        dir(file("libs"))  (1)
    }
}

dependencies {
    implementation(files("libs/our-custom.jar"))  (2)
    implementation(":awesome-framework:2.0")     (3)
    implementation(":utility-library:1.0")  (3)
}
build.gradle
repositories {
    flatDir {
        name = 'libs dir'
        dir file('libs')  (1)
    }
}

dependencies {
    implementation files('libs/our-custom.jar')  (2)
    implementation ':awesome-framework:2.0'  (3)
    implementation ':utility-library:1.0'  (3)
}
1 指定包含 JAR 文件的目录的路径
2 声明无版本 JAR 的文件依赖性
3 使用标准依赖坐标声明依赖关系 - 请注意,没有指定组,但每个标识符都有一个前导:,意味着一个空组

上面的示例将在配置中添加our-custom.jar,awesome-framework-2.0.jar和,用于编译项目的代码。utility-library-1.0.jarimplementation

您还可以在这些模块依赖项中指定一个组,即使它们实际上没有组。这是因为平面目录存储库只是忽略此信息。然后,如果您稍后添加一个普通的 Maven 或 Ivy 兼容存储库,Gradle 将下载该存储库中的一组声明的模块依赖项,而不是平面目录依赖项。

迁移ivy依赖

Apache Ivy 是一个独立的依赖管理工具,广泛与 Ant 一起使用。它的工作原理与 Gradle 类似。事实上,它们都允许您:

  • 定义您自己的配置

  • 相互扩展配置

  • 将依赖项附加到配置

  • 解决与 Ivy 兼容的存储库的依赖关系

  • 将工件发布到 Ivy 兼容的存储库

最显着的区别是 Gradle 对于特定类型的项目有标准配置。例如,Java 插件implementation定义了、testImplementation和等配置runtimeOnly。如果需要,您可以定义自己的依赖项配置。

因此,从 Ivy 迁移到 Gradle 通常很简单:

  • 将模块描述符中的依赖项声明转录到Gradle 构建脚本的依赖项 {}块中,最好使用您应用的任何插件提供的标准配置。

  • 对于无法被 Gradle 标准配置替换的任何自定义配置,将模块描述符中的任何配置声明转录到构建脚本的配置 {}块中。

  • 将 Ivy 设置文件中的解析器转录到构建脚本的repositories {}块中。

有关更多信息,请参阅管理依赖项配置声明依赖项声明存储库章节。

Ivy 提供了几个 Ant 任务来处理 Ivy 获取依赖项的过程。该过程的基本步骤包括:

  1. 配置— 应用 Ivy 设置文件中定义的配置

  2. Resolve — 找到声明的依赖项并在必要时将它们下载到缓存

  3. 检索— 将缓存的依赖项复制到另一个目录

Gradle 的过程类似,但您不必显式调用前两个步骤,因为它会自动执行。第三步根本不会发生——除非您创建一个任务来执行它——因为 Gradle 通常直接在类路径中使用依赖项缓存中的文件,并将其作为组装应用程序包的源。

让我们更详细地看看 Ivy 的步骤如何映射到 Gradle:

配置

Gradle 的大部分依赖相关配置都已融入构建脚本中,正如您在dependencies {}块等元素中看到的那样。另一个特别重要的配置元素是resolutionStrategy,可以从依赖项配置中访问它。这提供了您可以从 Ivy 冲突管理器获得的许多功能,并且是控制传递依赖项和缓存的强大方法。

某些 Ivy 配置选项在 Gradle 中没有等效项。例如,没有锁策略,因为 Gradle 保证其依赖项缓存是并发安全的。不存在“最新策略”方法,因为采用可靠的单一策略来解决冲突会更简单。如果选择了“错误”版本,您可以使用强制版本或其他解决方案选项覆盖它。

有关更多信息,请参阅有关控制传递依赖项的章节。

解决

在构建开始时,Gradle 将自动解析您声明的任何依赖项并将它们下载到其缓存中。 Gradle 在存储库中搜索这些依赖项,搜索顺序由存储库声明的顺序定义。

值得注意的是,Gradle 支持与 Ivy 相同的动态版本语法,因此您仍然可以使用1.0.+.您还可以使用特殊latest.integrationlatest.release标签。如果您决定使用此类动态不断变化的依赖项,则可以通过解析策略为其配置缓存行为。

如果您使用动态和/或更改依赖项,您可能还需要考虑依赖项锁定。这是一种使构建更加可靠并确保可重复性的方法。

恢复

如前所述,Gradle 不会自动从依赖项缓存中复制文件。其标准任务通常直接使用文件。如果要将依赖项复制到本地目录,可以在构建脚本中使用如下复制任务:

build.gradle.kts
tasks.register<Copy>("retrieveRuntimeDependencies") {
    into(layout.buildDirectory.dir("libs"))
    from(configurations.runtimeClasspath)
}
build.gradle
tasks.register('retrieveRuntimeDependencies', Copy) {
    into layout.buildDirectory.dir('libs')
    from configurations.runtimeClasspath
}

配置也是一个文件集合,因此可以在from()配置中使用它。您可以使用类似的技术将配置附加到编译任务或生成文档的任务。有关 Gradle 文件 API 的更多示例和信息,请参阅“使用文件”一章。

发布工件

使用 Ivy 管理依赖项的项目通常也使用它来将 JAR 和其他工件发布到存储库。如果您正在迁移这样的构建,那么您会很高兴知道 Gradle 内置了对将工件发布到 Ivy 兼容存储库的支持。

在尝试迁移构建的这一特定方面之前,请阅读发布章节以了解 Gradle 的发布模型。本章示例基于 Maven 存储库,但 Ivy 存储库使用相同的模型。

基本的迁移过程如下所示:

一旦这一切完成,您将能够为每个出版物生成一个 Ivy 模块描述符,并将它们发布到一个或多个存储库。

假设您定义了一个名为“myLibrary”的发布和一个名为“myRepo”的存储库。然后,Ivy 的 Ant 任务将映射到 Gradle 任务,如下所示:

  • <deliver>generateDescriptorFileForMyLibraryPublication

  • <publish>publishMyLibraryPublicationToMyRepoRepository

还有一个方便的publish任务,将所有出版物发布到所有存储库。如果您想将发布限制到特定存储库,请查看“发布”一章的相关部分

关于依赖版本

默认情况下,ivy 在生成模块描述符时会自动将依赖项的动态版本替换为已解析的“静态”版本。 Gradle 不会模仿这种行为,声明的依赖版本保持不变。

您可以使用Nebula Ivy Resolved Plugin复制默认的 Ivy 行为。或者,您可以自定义描述符文件,使其包含您想要的版本。

处理自定义 Ant 任务

Ant 的优点之一是创建自定义任务并将其合并到构建中相当容易。如果您有此类任务,那么有两个主要选项可将它们迁移到 Gradle 构建:

第一个选项通常快速且简单。如果要将任务集成到增量构建中,则必须使用增量构建运行时 API。您还经常需要使用 Ant 路径和文件集,这可能很不方便。

从长远来看,第二种选择更可取。 Gradle 任务类型往往比 Ant 任务更简单,因为它们不必使用基于 XML 的界面。您还可以获得 Gradle 丰富的 API 的好处。这种方法支持基于类型化属性的类型安全增量构建 API 。

处理文件

Ant 有许多处理文件的任务,其中大多数都有 Gradle 等效项。与 Ant 到 Gradle 迁移的其他领域一样,您可以在 Gradle 构建中使用这些 Ant 任务。但是,我们强烈建议尽可能迁移到本机 Gradle 构造,以便构建受益于:

  • 增量构建

  • 更轻松地与构建的其他部分集成,例如依赖项配置

  • 更惯用的构建脚本

使用没有直接等效项的 Ant 任务(例如<checksum>和 )会很方便<chown>。然而,从长远来看,最好将它们转换为使用标准 Java API 或第三方库的本机 Gradle 任务类型。

以下是 Ant 构建中最常见的与文件相关的元素,以及 Gradle 的等效元素:

  • <copy>— 更喜欢 Gradle Copy任务类型

  • <zip>(加上 Java 变体)——更喜欢Zip任务类型(加上JarWarEar

  • <unzip>— 更喜欢在任务中使用Project.zipTree()方法Copy

关于路径和文件集

Ant 利用类似路径的结构和文件集的概念来使用户能够使用文件和目录的集合。 Gradle 有一个基于FileCollectionFileTree的更简单、更强大的模型,可以将其视为构建中的对象。两种类型都允许基于 Ant 的 glob 语法进行过滤,例如**/books_*.您可以在使用文件一章中了解有关这些类型以及 Gradle 文件 API 其他方面的更多信息。

ant如果您需要与需要它们的 Ant 任务进行交互,您可以通过该对象在构建中构建 Ant 路径和文件集。关于Ant 集成的章节提供了同时使用<path>和的示例<fileset>。还有一种方法FileCollection可以将文件集合转换为文件集或类似的 Ant 类型。

迁移 Ant 属性

Ant 使用属性映射来存储可以在整个构建过程中重复使用的值。这种方法的最大缺点是属性值都是字符串,并且属性本身的行为类似于全局变量。

与 Gradle 中的 Ant 属性交互

有时,您会希望直接从 Gradle 构建中使用 Ant 任务,并且该任务需要设置一个或多个 Ant 属性。

如果是这种情况,您可以通过对象轻松设置这些属性ant,如在 Gradle 中使用 Ant章节中所述。

Gradle 确实以项目属性的形式使用了类似的东西,这是参数化构建的合理方法。这些可以从命令行、文件中gradle.properties通过专门命名的系统属性和环境变量进行设置。

如果您有现有的 Ant 属性文件,则可以将其内容复制到项目的gradle.properties文件中。请注意:

  • 设置的属性gradle.properties 不会覆盖构建脚本中定义的同名额外项目属性

  • 导入的 Ant 任务不会自动“查看”Gradle 项目属性 — 您必须将它们复制到 Ant 属性映射中才能发生这种情况

另一个需要理解的重要因素是 Gradle 构建脚本与面向对象的 API 一起使用,并且通常最好尽可能使用任务、源集和其他对象的属性。例如,此构建脚本片段创建用于将 Javadoc 文档打包为 JAR 并将其解包的任务,通过其属性链接任务:

build.gradle.kts
val tmpDistDir = layout.buildDirectory.dir("dist")

tasks.register<Jar>("javadocJarArchive") {
    from(tasks.javadoc)  (1)
    archiveClassifier = "javadoc"
}

tasks.register<Copy>("unpackJavadocs") {
    from(zipTree(tasks.named<Jar>("javadocJarArchive").get().archiveFile))  (2)
    into(tmpDistDir)  (3)
}
build.gradle
def tmpDistDir = layout.buildDirectory.dir('dist')

tasks.register('javadocJarArchive', Jar) {
    from javadoc  (1)
    archiveClassifier = 'javadoc'
}

tasks.register('unpackJavadocs', Copy) {
    from zipTree(javadocJarArchive.archiveFile)  (2)
    into tmpDistDir  (3)
}
1 打包所有javadoc的输出文件——相当于from javadoc.destinationDir
2 javadocJar使用任务保存的 Javadoc JAR 的位置
3 使用名为的项目属性tmpDistDir来定义“dist”目录的位置

从示例中可以看出tmpDistDir,经常需要通过属性来定义路径,这就是为什么 Gradle 还提供了可以附加到项目、任务和一些其他类型的对象的额外属性。

迁移多项目构建

多项目构建对于迁移来说是一个特殊的挑战,因为 Ant 中没有标准方法来构建它们或处理项目间依赖关系。

幸运的是,Gradle 的多项目支持可以处理相当多样化的项目结构,并且它为构建和维护多项目构建提供了比 Ant 更强大、更有用的支持。该ant.importBuild()方法还透明地处理<ant><antcall>任务,从而允许分阶段迁移。

以下步骤重点介绍了迁移多项目构建的建议方法:

  1. 首先学习Gradle 如何配置多项目构建

  2. 在构建的每个项目中创建一个 Gradle 构建脚本,将其内容设置为这一行:

    ant.importBuild 'build.xml'
    ant.importBuild("build.xml")

    替换build.xml为与项目对应的实际 Ant 构建文件的路径。如果没有相应的 Ant 构建文件,请将 Gradle 构建脚本留空。即使您的构建不适合此迁移方法,也请继续执行这些步骤,看看是否仍有办法进行分阶段迁移。

  3. 创建一个设置文件,其中包含现在具有 Gradle 构建脚本的所有项目。

  4. 实现项目间的依赖关系。

    多项目构建中的某些项目将依赖于该构建中的一个或多个其他项目生成的工件。此类项目需要确保它们所依赖的项目已生成其工件,并且这些工件的路径是已知的。

    确保生成所需的工件通常意味着通过任务调用其他项目的构建<ant>。不幸的是,这会绕过 Gradle 构建,从而否定您对 Gradle 构建脚本所做的任何更改。您需要将使用<ant>任务的目标替换为 Gradle任务依赖项

    例如,您的 Web 项目依赖于属于同一构建的一部分的“util”库。 “web”的 Ant 构建文件可能有这样的目标:

    web/build.xml
    <target name="buildRequiredProjects">
        <ant dir="${root.dir}/util" target="build"/>  (1)
    </target>
    1 root.dir必须由构建定义

    这可以替换为相应 Gradle 构建脚本中的项目间任务依赖项,如以下示例所示,假设“web”项目的“compile”任务需要预先构建“util”:

    web/build.gradle.kts
    ant.importBuild("build.xml")
    
    tasks {
        named<Task>("compile") {
            setDependsOn(listOf(":util:build"))
        }
    }
    web/build.gradle
    ant.importBuild 'build.xml'
    
    compile.dependsOn = [ ':util:build' ]

    这不像 Gradle 的项目依赖项那样健壮或强大,但它解决了眼前的问题,而无需对构建进行大的更改。只需要小心删除或覆盖委托给其他子项目的任务(例如buildRequiredProjects任务)的任何依赖项。

  5. 识别不依赖于其他项目的项目,并将它们迁移到惯用的 Gradle 构建脚本。

    请遵循本指南其余部分的建议来迁移单个项目构建。如前所述,您应该尽可能使用 Gradle 标准插件。这可能意味着您需要向每个构建添加额外的复制任务,将生成的工件复制到其余 Ant 构建所需的位置。

  6. 当项目仅依赖于完全迁移的 Gradle 构建的项目时迁移项目。

    此时,您应该能够切换到使用附加到适当依赖项配置的正确项目依赖项。

  7. 一旦 Ant 构建的任何部分都不依赖于项目,就清理项目。

    我们在步骤 5 中提到,您可能需要添加复制任务以满足依赖 Ant 构建的要求。一旦这些构建被迁移,这样的构建逻辑将不再需要,应该被删除。

在该过程结束时,您应该有一个 Gradle 构建,您确信它可以正常工作,并且构建逻辑比以前少得多。

进一步阅读

本章涵盖了特定于将 Ant 构建迁移到 Gradle 的主要主题。剩下的就是迁移后可能有用的其他一些领域:

最后一点,本指南仅涉及 Gradle 的一些功能,我们鼓励您从用户手册的其他章节中了解其余功能。