Gradle 提供了与 Ant 的集成。

Gradle 集成了 Ant,允许您在 Gradle 构建中使用单个 Ant 任务或整个 Ant 构建。在 Gradle 构建脚本中使用 Ant 任务通常比使用 Ant 的 XML 格式更容易、更强大。Gradle 还可以用作强大的 Ant 任务脚本工具。

Ant 可以分为两层

  1. 第 1 层:Ant 语言。它提供了 build.xml 文件的语法、目标的处理、宏定义等特殊构造等。换句话说,这一层包括了除 Ant 任务和类型之外的所有内容。Gradle 理解这种语言,并允许您将 Ant build.xml 直接导入 Gradle 项目。然后,您可以像使用 Gradle 任务一样使用 Ant 构建的目标。

  2. 第 2 层:Ant 任务和类型,如 javaccopyjar。对于这一层,Gradle 提供了使用 Groovy 和 AntBuilder 的集成。

由于构建脚本是 Kotlin 或 Groovy 脚本,您可以将 Ant 构建作为外部进程执行。您的构建脚本可能包含以下语句:"ant clean compile".execute()[1]

Gradle 的 Ant 集成允许您将构建从 Ant 平稳迁移到 Gradle

  1. 首先导入您现有的 Ant 构建。

  2. 然后,将您的依赖项声明从 Ant 脚本迁移到您的构建文件。

  3. 最后,将您的任务移动到您的构建文件,或用 Gradle 的插件替换它们。

此迁移过程可以增量执行,并且您可以在整个迁移过程中保持功能正常的 Gradle 构建。

Ant 集成与配置缓存不完全兼容。在任务操作中使用Task.ant运行 Ant 任务可能有效,但不支持导入 Ant 构建。因此,导入 Ant 构建时会自动禁用配置缓存。

Ant 集成由AntBuilder API 提供。

使用 Ant 任务和类型

Gradle 在您的构建脚本中提供了一个名为 ant 的属性。这是对 AntBuilder 实例的引用。

AntBuilder 用于从您的构建脚本访问 Ant 任务、类型和属性。

您通过调用 AntBuilder 实例上的方法来执行 Ant 任务。您使用任务名称作为方法名称

build.gradle
ant.mkdir(dir: "$STAGE")
ant.copy(todir: "$STAGE/bin") {
    ant.fileset(dir: 'bin', includes: "**")
}
ant.gzip(destfile:"build/file-${VERSION}.tar.gz", src: "build/file-${VERSION}.tar")

例如,您使用 ant.echo() 方法执行 Ant echo 任务。

Ant 任务的属性作为 Map 参数传递给方法。下面是 echo 任务的示例

build.gradle.kts
tasks.register("hello") {
    doLast {
        val greeting = "hello from Ant"
        ant.withGroovyBuilder {
            "echo"("message" to greeting)
        }
    }
}
build.gradle
tasks.register('hello') {
    doLast {
        String greeting = 'hello from Ant'
        ant.echo(message: greeting)
    }
}
$ gradle hello

> Task :hello
[ant:echo] hello from Ant

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
您可以混合 Groovy/Kotlin 代码和 Ant 任务标记。这可以非常强大。

您将嵌套文本作为任务方法调用的参数传递给 Ant 任务。在此示例中,我们将 echo 任务的消息作为嵌套文本传递

build.gradle.kts
tasks.register("hello") {
    doLast {
        ant.withGroovyBuilder {
            "echo"("message" to "hello from Ant")
        }
    }
}
build.gradle
tasks.register('hello') {
    doLast {
        ant.echo('hello from Ant')
    }
}
$ gradle hello

> Task :hello
[ant:echo] hello from Ant

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

您在闭包中将嵌套元素传递给 Ant 任务。嵌套元素的定义方式与任务相同,通过调用与我们想要定义的元素同名的方法

build.gradle.kts
tasks.register("zip") {
    doLast {
        ant.withGroovyBuilder {
            "zip"("destfile" to "archive.zip") {
                "fileset"("dir" to "src") {
                    "include"("name" to "**.xml")
                    "exclude"("name" to "**.java")
                }
            }
        }
    }
}
build.gradle
tasks.register('zip') {
    doLast {
        ant.zip(destfile: 'archive.zip') {
            fileset(dir: 'src') {
                include(name: '**.xml')
                exclude(name: '**.java')
            }
        }
    }
}

您可以像访问任务一样访问 Ant 类型,使用类型名称作为方法名称。方法调用返回 Ant 数据类型,您可以直接在构建脚本中使用它。在以下示例中,我们创建一个 Ant path 对象,然后迭代其内容

build.gradle.kts
import org.apache.tools.ant.types.Path

tasks.register("list") {
    doLast {
        val path = ant.withGroovyBuilder {
            "path" {
                "fileset"("dir" to "libs", "includes" to "*.jar")
            }
        } as Path
        path.list().forEach {
            println(it)
        }
    }
}
build.gradle
tasks.register('list') {
    doLast {
        def path = ant.path {
            fileset(dir: 'libs', includes: '*.jar')
        }
        path.list().each {
            println it
        }
    }
}

使用自定义 Ant 任务

为了使自定义任务在您的构建中可用,请使用 taskdef(通常更容易)或 typedef Ant 任务,就像在 build.xml 文件中一样。然后,您可以像引用内置 Ant 任务一样引用自定义 Ant 任务

build.gradle.kts
tasks.register("check") {
    val checkstyleConfig = file("checkstyle.xml")
    doLast {
        ant.withGroovyBuilder {
            "taskdef"("resource" to "com/puppycrawl/tools/checkstyle/ant/checkstyle-ant-task.properties") {
                "classpath" {
                    "fileset"("dir" to "libs", "includes" to "*.jar")
                }
            }
            "checkstyle"("config" to checkstyleConfig) {
                "fileset"("dir" to "src")
            }
        }
    }
}
build.gradle
tasks.register('check') {
    def checkstyleConfig = file('checkstyle.xml')
    doLast {
        ant.taskdef(resource: 'com/puppycrawl/tools/checkstyle/ant/checkstyle-ant-task.properties') {
            classpath {
                fileset(dir: 'libs', includes: '*.jar')
            }
        }
        ant.checkstyle(config: checkstyleConfig) {
            fileset(dir: 'src')
        }
    }
}

您可以使用 Gradle 的依赖管理来为自定义任务组装类路径。为此,您需要为类路径定义一个自定义配置并向其添加一些依赖项。这在声明依赖项中有更详细的描述

build.gradle.kts
val pmd = configurations.create("pmd")

dependencies {
    pmd(group = "pmd", name = "pmd", version = "4.2.5")
}
build.gradle
configurations {
    pmd
}

dependencies {
    pmd group: 'pmd', name: 'pmd', version: '4.2.5'
}

要使用类路径配置,请使用自定义配置的 asPath 属性

build.gradle.kts
tasks.register("check") {
    doLast {
        ant.withGroovyBuilder {
            "taskdef"("name" to "pmd",
                      "classname" to "net.sourceforge.pmd.ant.PMDTask",
                      "classpath" to pmd.asPath)
            "pmd"("shortFilenames" to true,
                  "failonruleviolation" to true,
                  "rulesetfiles" to file("pmd-rules.xml").toURI().toString()) {
                "formatter"("type" to "text", "toConsole" to "true")
                "fileset"("dir" to "src")
            }
        }
    }
}
build.gradle
tasks.register('check') {
    doLast {
        ant.taskdef(name: 'pmd',
                    classname: 'net.sourceforge.pmd.ant.PMDTask',
                    classpath: configurations.pmd.asPath)
        ant.pmd(shortFilenames: 'true',
                failonruleviolation: 'true',
                rulesetfiles: file('pmd-rules.xml').toURI().toString()) {
            formatter(type: 'text', toConsole: 'true')
            fileset(dir: 'src')
        }
    }
}

导入 Ant 构建

您可以使用 ant.importBuild() 方法将 Ant 构建导入您的 Gradle 项目。

当您导入 Ant 构建时,每个 Ant 目标都被视为一个 Gradle 任务。这意味着您可以像操作 Gradle 任务一样操作和执行 Ant 目标

build.gradle.kts
ant.importBuild("build.xml")
build.gradle
ant.importBuild 'build.xml'
build.xml
<project>
    <target name="hello">
        <echo>Hello, from Ant</echo>
    </target>
</project>
$ gradle hello

> Task :hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

您可以添加一个依赖于 Ant 任务的 Gradle 任务

build.gradle.kts
ant.importBuild("build.xml")

tasks.register("intro") {
    dependsOn("hello")
    doLast {
        println("Hello, from Gradle")
    }
}
build.gradle
ant.importBuild 'build.xml'

tasks.register('intro') {
    dependsOn("hello")
    doLast {
        println 'Hello, from Gradle'
    }
}
$ gradle intro

> Task :hello
[ant:echo] Hello, from Ant

> Task :intro
Hello, from Gradle

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

或者,您可以向 Ant 目标添加行为

build.gradle.kts
ant.importBuild("build.xml")

tasks.named("hello") {
    doLast {
        println("Hello, from Gradle")
    }
}
build.gradle
ant.importBuild 'build.xml'

hello {
    doLast {
        println 'Hello, from Gradle'
    }
}
$ gradle hello

> Task :hello
[ant:echo] Hello, from Ant
Hello, from Gradle

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

Ant 目标也可以依赖于 Gradle 任务

build.gradle.kts
ant.importBuild("build.xml")

tasks.register("intro") {
    doLast {
        println("Hello, from Gradle")
    }
}
build.gradle
ant.importBuild 'build.xml'

tasks.register('intro') {
    doLast {
        println 'Hello, from Gradle'
    }
}
build.xml
<project>
    <target name="hello" depends="intro">
        <echo>Hello, from Ant</echo>
    </target>
</project>
$ gradle hello

> Task :intro
Hello, from Gradle

> Task :hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

有时,可能需要“重命名”为 Ant 目标生成的任务,以避免与现有 Gradle 任务发生命名冲突。为此,请使用 AntBuilder.importBuild(java.lang.Object, org.gradle.api.Transformer) 方法

build.gradle.kts
ant.importBuild("build.xml") { antTargetName ->
    "a-" + antTargetName
}
build.gradle
ant.importBuild('build.xml') { antTargetName ->
    'a-' + antTargetName
}
build.xml
<project>
    <target name="hello">
        <echo>Hello, from Ant</echo>
    </target>
</project>
$ gradle a-hello

> Task :a-hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
尽管此方法的第二个参数应为 Transformer,但在 Groovy 中编程时,由于 Groovy 支持将闭包自动强制转换为单抽象方法类型,因此可以使用闭包而不是匿名内部类(或类似类)。

使用 Ant 属性和引用

有几种方法可以设置 Ant 属性,以便 Ant 任务可以使用该属性。

您可以直接在 AntBuilder 实例上设置属性。Ant 属性也可以作为 Map 使用,您可以更改它。

您也可以使用 Ant property 任务

build.gradle.kts
ant.setProperty("buildDir", buildDir)
ant.properties.set("buildDir", buildDir)
ant.properties["buildDir"] = buildDir
ant.withGroovyBuilder {
    "property"("name" to "buildDir", "location" to "buildDir")
}
build.gradle
ant.buildDir = buildDir
ant.properties.buildDir = buildDir
ant.properties['buildDir'] = buildDir
ant.property(name: 'buildDir', location: buildDir)

许多 Ant 任务在执行时会设置属性。有几种方法可以获取这些属性的值。您可以直接从 AntBuilder 实例获取属性。Ant 属性也可以作为 Map 使用

build.xml
<property name="antProp" value="a property defined in an Ant build"/>
build.gradle.kts
println(ant.getProperty("antProp"))
println(ant.properties.get("antProp"))
println(ant.properties["antProp"])
build.gradle
println ant.antProp
println ant.properties.antProp
println ant.properties['antProp']

有几种方法可以设置 Ant 引用

build.gradle.kts
ant.withGroovyBuilder { "path"("id" to "classpath", "location" to "libs") }
ant.references.set("classpath", ant.withGroovyBuilder { "path"("location" to "libs") })
ant.references["classpath"] = ant.withGroovyBuilder { "path"("location" to "libs") }
build.gradle
ant.path(id: 'classpath', location: 'libs')
ant.references.classpath = ant.path(location: 'libs')
ant.references['classpath'] = ant.path(location: 'libs')
build.xml
<path refid="classpath"/>

有几种方法可以获取 Ant 引用

build.xml
<path id="antPath" location="libs"/>
build.gradle.kts
println(ant.references.get("antPath"))
println(ant.references["antPath"])
build.gradle
println ant.references.antPath
println ant.references['antPath']

使用 Ant 日志

Gradle 将 Ant 消息优先级映射到 Gradle 日志级别,以便从 Ant 记录的消息出现在 Gradle 输出中。默认情况下,这些映射如下

Ant 消息优先级 Gradle 日志级别

VERBOSE

DEBUG

DEBUG

DEBUG

INFO

INFO

WARN

WARN

ERROR

ERROR

微调 Ant 日志

Ant 消息优先级到 Gradle 日志级别的默认映射有时可能存在问题。例如,没有消息优先级直接映射到 LIFECYCLE 日志级别,这是 Gradle 的默认日志级别。许多 Ant 任务以 INFO 优先级记录消息,这意味着要从 Gradle 公开这些消息,构建必须在日志级别设置为 INFO 的情况下运行,这可能会记录比预期更多的输出。

相反,如果 Ant 任务记录的消息级别过高,则抑制这些消息将需要构建在更高的日志级别(例如 QUIET)下运行。但是,这可能会导致其他所需的输出被抑制。

为了解决这个问题,Gradle 允许用户微调 Ant 日志并控制消息优先级到 Gradle 日志级别的映射。这通过使用 AntBuilder.setLifecycleLogLevel(java.lang.String) 方法设置应映射到默认 Gradle LIFECYCLE 日志级别的优先级来完成。设置此值后,以配置的优先级或更高优先级记录的任何 Ant 消息将至少以 LIFECYCLE 级别记录。低于此优先级的任何 Ant 消息将最多以 INFO 级别记录。

例如,以下更改映射,使得 Ant INFO 优先级消息以 LIFECYCLE 日志级别公开

build.gradle.kts
ant.lifecycleLogLevel = AntBuilder.AntMessagePriority.INFO

tasks.register("hello") {
    doLast {
        ant.withGroovyBuilder {
            "echo"("level" to "info", "message" to "hello from info priority!")
        }
    }
}
build.gradle
ant.lifecycleLogLevel = "INFO"

tasks.register('hello') {
    doLast {
        ant.echo(level: "info", message: "hello from info priority!")
    }
}
$ gradle hello

> Task :hello
[ant:echo] hello from info priority!

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

另一方面,如果 lifecycleLogLevel 设置为 ERROR,则以 WARN 优先级记录的 Ant 消息将不再以 WARN 日志级别记录。它们现在将以 INFO 级别记录,并默认被抑制。


1. 在 Groovy 中可以执行字符串。