Gradle 提供了与 Ant 的出色集成。您可以在 Gradle 构建中使用单个 Ant 任务或整个 Ant 构建。事实上,您会发现在 Gradle 构建脚本中使用 Ant 任务比使用 Ant 的 XML 格式更容易、更强大。您甚至可以将 Gradle 简单地用作强大的 Ant 任务脚本工具。

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

Ant 的第二层是其丰​​富的 Ant 任务和类型,例如javaccopyjar。对于这一层,Gradle 只需依赖 Groovy 和出色的AntBuilder.

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

您可以使用 Gradle 的 Ant 集成作为将构建从 Ant 迁移到 Gradle 的路径。例如,您可以首先导入现有的 Ant 构建。然后,您可以将依赖项声明从 Ant 脚本移至构建文件。最后,您可以将任务移至构建文件,或用 Gradle 的一些插件替换它们。这个过程可以随着时间的推移分部分完成,并且您可以在整个过程中构建一个有效的 Gradle。

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

在构建中使用 Ant 任务和类型

ant在您的构建脚本中, Gradle 提供了一个名为 的属性。这是对AntBuilder实例的引用。这AntBuilder用于从构建脚本访问 Ant 任务、类型和属性。从 Antbuild.xml格式到 Groovy 有一个非常简单的映射,如下所述。

您可以通过调用实例上的方法来执行 Ant 任务AntBuilder。您使用任务名称作为方法名称。例如,您echo通过调用该ant.echo()方法来执行 Ant 任务。 Ant 任务的属性作为 Map 参数传递给该方法。下面是该任务的示例echo。请注意,我们还可以混合 Groovy 代码和 Ant 任务标记。这可能非常强大。

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
> gradle hello

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

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

您可以将嵌套文本作为任务方法调用的参数传递给 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
> 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 数据类型,然后您可以直接在构建脚本中使用该数据类型。在下面的示例中,我们创建一个 Antpath对象,然后迭代它的内容。

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
        }
    }
}

有关更多信息,AntBuilder请参阅“Groovy in Action”8.4 或Groovy Wiki

在构建中使用自定义 Ant 任务

要使自定义任务在您的构建中可用,您可以使用taskdef(通常更容易)或typedefAnt 任务,就像在文件中一样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
> gradle hello

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

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

您可以添加依赖于 Ant 目标的任务:

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
> 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
> 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
> 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
> 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 提供。您还可以使用 Antproperty任务。以下是如何执行此操作的一些示例。

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']

蚂蚁日志记录

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

表1. Ant消息优先级映射
蚂蚁消息优先级 Gradle 日志级别

详细

DEBUG

调试

DEBUG

信息

INFO

警告

WARN

错误

ERROR

微调 Ant 日志记录

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

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

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

例如,以下更改映射,以便在日志级别公开Ant INFOLIFECYCLE优先级消息。

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
> 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级别,并且默认情况下将被抑制。

应用程序编程接口

Ant 集成由AntBuilder提供。


1 .在 Groovy 中,您可以执行字符串。要了解有关使用 Groovy 执行外部进程的更多信息,请参阅“Groovy in Action”9.3.2 或 Groovy wiki