Gradle 构建生命周期中的初始化阶段使用设置文件查找您的 项目根目录 中包含的根项目和子项目。

author gradle 6

然后,对于设置文件中包含的每个项目,Gradle 会创建一个 Project 实例。

接着,Gradle 查找相应的构建脚本文件,该文件在配置阶段使用。

构建脚本

每个 Gradle 构建都包含一个或多个项目;一个项目和一些子项目

一个项目通常对应于需要构建的软件组件,如库或应用程序。它可能代表一个库 JAR、一个 Web 应用程序或一个由其他项目生成的 JAR 组装而成的分发 ZIP。

另一方面,它可能代表一个待办事项,例如将您的应用程序部署到预演或生产环境。

Gradle 脚本使用 Groovy DSL 或 Kotlin DSL(领域特定语言)编写。

构建脚本配置一个项目,并与类型为 Project 的对象关联。

Build

构建脚本执行时,它会配置 Project 对象。

构建脚本可以是 Groovy 的 *.gradle 文件,也可以是 Kotlin 的 *.gradle.kts 文件。

构建脚本配置 Project 对象及其子对象。

Project 对象

Project 对象是 Gradle API 的一部分。

  • 在 Groovy DSL 中,Project 对象的文档位于此处

  • 在 Kotlin DSL 中,Project 对象的文档位于此处

构建脚本中的许多顶级属性和块是 Project API 的一部分。

例如,以下构建脚本使用 Project.name 属性打印项目名称:

build.gradle.kts
println(name)
println(project.name)
build.gradle
println name
println project.name
$ gradle -q check
project-api
project-api

两个 println 语句都打印出相同的属性。

第一个使用了对 Project 对象 name 属性的顶级引用。第二个语句使用了对任何构建脚本都可用的 project 属性,该属性返回关联的 Project 对象。

标准项目属性

Project 对象在您的构建脚本中公开了一组标准属性。

下表列出了一些常用属性:

名称 类型 描述

name

String

项目目录的名称。

path

String

项目的完全限定名称。

description

String

项目的描述。

dependencies

DependencyHandler

返回项目的依赖处理器。

repositories

RepositoryHandler

返回项目的仓库处理器。

layout

ProjectLayout

提供对项目中几个重要位置的访问。

group

Object

此项目的组。

version

Object

此项目的版本。

下表列出了一些常用方法:

名称 描述

uri()

将文件路径解析为 URI,相对于此项目的项目目录。

task()

创建具有给定名称的任务并将其添加到此项目。

构建脚本结构

构建脚本由 { …​ } 组成,这是 Groovy 和 Kotlin 中一个特殊的对象。在 Kotlin 中称为lambda,在 Groovy 中称为闭包(closure)

简单来说,plugins{ } 块是一个方法调用,其中 Kotlin lambda 对象或 Groovy closure 对象作为参数传递。它是以下形式的缩写:

plugins(function() {
    id("plugin")
})

块映射到 Gradle API 方法。

函数内部的代码针对一个 this 对象执行,该对象在 Kotlin lambda 中称为接收者(receiver),在 Groovy closure 中称为委托(delegate)。Gradle 确定正确的 this 对象并调用正确的对应方法。方法调用 id("plugin") 对象的 this 类型是 PluginDependenciesSpec

构建脚本本质上由基于 DSL 构建的 Gradle API 调用组成。Gradle 从上到下逐行执行脚本。

让我们看一个示例并对其进行分解:

build.gradle.kts
plugins {   (1)
    id("application")
}

repositories {  (2)
    mavenCentral()
}

dependencies {  (3)
    testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.3")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    implementation("com.google.guava:guava:32.1.1-jre")
}

application {   (4)
    mainClass = "com.example.Main"
}

tasks.named<Test>("test") { (5)
    useJUnitPlatform()
}

tasks.named<Javadoc>("javadoc").configure {
    exclude("app/Internal*.java")
    exclude("app/internal/*")
}

tasks.register<Zip>("zip-reports") {
    from("Reports/")
    include("*")
    archiveFileName.set("Reports.zip")
    destinationDirectory.set(file("/dir"))
}
build.gradle
plugins {   (1)
    id 'application'
}

repositories {  (2)
    mavenCentral()
}

dependencies {  (3)
    testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.3'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    implementation 'com.google.guava:guava:32.1.1-jre'
}

application {   (4)
    mainClass = 'com.example.Main'
}

tasks.named('test', Test) { (5)
    useJUnitPlatform()
}

tasks.named('javadoc', Javadoc).configure {
    exclude 'app/Internal*.java'
    exclude 'app/internal/*'
}

tasks.register('zip-reports', Zip) {
    from 'Reports/'
    include '*'
    archiveFileName = 'Reports.zip'
    destinationDirectory = file('/dir')
}
1 应用插件到构建。
2 定义可以找到依赖项的位置。
3 添加依赖项。
4 设置属性。
5 注册和配置任务。

1. 应用插件到构建

插件用于扩展 Gradle。它们也用于模块化和重用项目配置。

可以使用 PluginDependenciesSpec plugins 脚本块应用插件。

推荐使用 plugins 块:

build.gradle.kts
plugins {   (1)
    id("application")
}
build.gradle
plugins {   (1)
    id 'application'
}

在示例中,应用了 Gradle 内置的 application 插件,将我们的项目描述为一个 Java 应用程序。

2. 定义可以找到依赖项的位置

一个项目通常需要一些依赖项来完成其工作。依赖项包括插件、库或 Gradle 必须下载以使构建成功的组件。

构建脚本告诉 Gradle 在哪里查找依赖项的二进制文件。可以提供多个位置:

build.gradle.kts
repositories {  (2)
    mavenCentral()
}
build.gradle
repositories {  (2)
    mavenCentral()
}

在示例中,guava 库和 JetBrains Kotlin 插件(org.jetbrains.kotlin.jvm)将从 Maven Central Repository 下载。

3. 添加依赖项

一个项目通常需要一些依赖项来完成其工作。这些依赖项通常是预编译类的库,在项目的源代码中被导入。

依赖项通过 配置 进行管理,并从仓库中检索。

使用 Project.getDependencies() 方法返回的 DependencyHandler 来管理依赖项。使用 Project.getRepositories() 方法返回的 RepositoryHandler 来管理仓库。

build.gradle.kts
dependencies {  (3)
    testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.3")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    implementation("com.google.guava:guava:32.1.1-jre")
}
build.gradle
dependencies {  (3)
    testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.3'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    implementation 'com.google.guava:guava:32.1.1-jre'
}

在示例中,应用程序代码使用了 Google 的 guava 库。Guava 提供了用于集合、缓存、基本类型支持、并发、常用注解、字符串处理、I/O 和验证的实用方法。

4. 设置属性

插件可以使用扩展向项目添加属性和方法。

Project 对象有一个关联的 ExtensionContainer 对象,其中包含已应用于项目的所有插件的设置和属性。

在示例中,application 插件添加了一个 application 属性,用于详细说明我们的 Java 应用程序的主类:

build.gradle.kts
application {   (4)
    mainClass = "com.example.Main"
}
build.gradle
application {   (4)
    mainClass = 'com.example.Main'
}

5. 注册和配置任务

任务执行一些基本工作,例如编译类、运行单元测试或压缩 WAR 文件。

任务通常在插件中定义,但您可能需要在构建脚本中注册或配置任务。

注册任务将其添加到您的项目。

您可以使用 TaskContainer.register(java.lang.String) 方法在项目中注册任务:

build.gradle.kts
tasks.register<Zip>("zip-reports") {
    from("Reports/")
    include("*")
    archiveFileName.set("Reports.zip")
    destinationDirectory.set(file("/dir"))
}
build.gradle
tasks.register('zip-reports', Zip) {
    from 'Reports/'
    include '*'
    archiveFileName = 'Reports.zip'
    destinationDirectory = file('/dir')
}

您可能见过 TaskContainer.create(java.lang.String) 方法的使用,应避免使用该方法

tasks.create<Zip>("zip-reports") { }
register() 方法(可实现任务配置规避)优于 create()

您可以使用 TaskCollection.named(java.lang.String) 方法找到并配置任务:

build.gradle.kts
tasks.named<Test>("test") { (5)
    useJUnitPlatform()
}
build.gradle
tasks.named('test', Test) { (5)
    useJUnitPlatform()
}

下面的示例配置了 Javadoc 任务,使其能够自动从 Java 代码生成 HTML 文档:

build.gradle.kts
tasks.named<Javadoc>("javadoc").configure {
    exclude("app/Internal*.java")
    exclude("app/internal/*")
}
build.gradle
tasks.named('javadoc', Javadoc).configure {
    exclude 'app/Internal*.java'
    exclude 'app/internal/*'
}

构建脚本编写

构建脚本由零个或多个语句和脚本块组成:

println(project.layout.projectDirectory);

语句可以包括方法调用、属性赋值和局部变量定义。

version = '1.0.0.GA'

脚本块是一个方法调用,它将闭包/lambda 作为参数。

configurations {
}

闭包/lambda 在执行时会配置某个委托对象。

repositories {
    google()
}

构建脚本也是 Groovy 或 Kotlin 脚本。

build.gradle.kts
tasks.register("upper") {
    doLast {
        val someString = "mY_nAmE"
        println("Original: $someString")
        println("Upper case: ${someString.toUpperCase()}")
    }
}
build.gradle
tasks.register('upper') {
    doLast {
        String someString = 'mY_nAmE'
        println "Original: $someString"
        println "Upper case: ${someString.toUpperCase()}"
    }
}
$ gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME

它可以包含 Groovy 或 Kotlin 脚本中允许的元素,例如方法定义和类定义。

build.gradle.kts
tasks.register("count") {
    doLast {
        repeat(4) { print("$it ") }
    }
}
build.gradle
tasks.register('count') {
    doLast {
        4.times { print "$it " }
    }
}
$ gradle -q count
0 1 2 3 

灵活的任务注册

利用 Groovy 或 Kotlin 语言的功能,您可以在循环中注册多个任务:

build.gradle.kts
repeat(4) { counter ->
    tasks.register("task$counter") {
        doLast {
            println("I'm task number $counter")
        }
    }
}
build.gradle
4.times { counter ->
    tasks.register("task$counter") {
        doLast {
            println "I'm task number $counter"
        }
    }
}
$ gradle -q task1
I'm task number 1

Gradle 类型

在 Gradle 中,类型属性提供者是管理和配置构建逻辑的基础。

  • 类型:Gradle 定义了类型(如 TaskConfigurationFile 等)来表示构建组件。您可以扩展这些类型以创建自定义任务或领域对象。

  • 属性:Gradle 属性(例如 Property<T>ListProperty<T>SetProperty<T>)用于构建配置。它们支持延迟求值,这意味着只有在需要时才计算它们的值,从而提高了灵活性和性能。

  • 提供者Provider<T> 表示一个延迟计算或检索的值。提供者通常与属性一起使用,以将值计算推迟到必要时。这对于将动态运行时值集成到构建中特别有用。

您可以在理解 Gradle 属性和提供者 中了解更多信息。

声明变量

构建脚本可以声明两种变量:局部变量额外属性

局部变量

使用 val 关键字声明局部变量。局部变量仅在其声明的范围内可见。它们是底层 Kotlin 语言的特性。

使用 def 关键字声明局部变量。局部变量仅在其声明的范围内可见。它们是底层 Groovy 语言的特性。

build.gradle.kts
val dest = "dest"

tasks.register<Copy>("copy") {
    from("source")
    into(dest)
}
build.gradle
def dest = 'dest'

tasks.register('copy', Copy) {
    from 'source'
    into dest
}

额外属性

Gradle 的增强对象,包括项目、任务和源集,可以持有用户定义的属性。

通过拥有对象的 extra 属性添加、读取和设置额外属性。或者,您可以使用 Kotlin 委托属性 by extra 访问额外属性。

通过拥有对象的 ext 属性添加、读取和设置额外属性。或者,您可以使用 ext 块同时添加多个属性。

build.gradle.kts
plugins {
    id("java-library")
}

val springVersion by extra("3.1.0.RELEASE")
val emailNotification by extra { "build@master.org" }

sourceSets.all { extra["purpose"] = null }

sourceSets {
    main {
        extra["purpose"] = "production"
    }
    test {
        extra["purpose"] = "test"
    }
    create("plugin") {
        extra["purpose"] = "production"
    }
}

tasks.register("printProperties") {
    val springVersion = springVersion
    val emailNotification = emailNotification
    val productionSourceSets = provider {
        sourceSets.matching { it.extra["purpose"] == "production" }.map { it.name }
    }
    doLast {
        println(springVersion)
        println(emailNotification)
        productionSourceSets.get().forEach { println(it) }
    }
}
build.gradle
plugins {
    id 'java-library'
}

ext {
    springVersion = "3.1.0.RELEASE"
    emailNotification = "build@master.org"
}

sourceSets.all { ext.purpose = null }

sourceSets {
    main {
        purpose = "production"
    }
    test {
        purpose = "test"
    }
    plugin {
        purpose = "production"
    }
}

tasks.register('printProperties') {
    def springVersion = springVersion
    def emailNotification = emailNotification
    def productionSourceSets = provider {
        sourceSets.matching { it.purpose == "production" }.collect { it.name }
    }
    doLast {
        println springVersion
        println emailNotification
        productionSourceSets.get().each { println it }
    }
}
$ gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin

此示例通过 by extraproject 对象添加了两个额外属性。此外,此示例通过将 extra["purpose"] 设置为 null 向每个源集添加了一个名为 purpose 的属性。添加后,您可以通过 extra 读取和设置这些属性。

此示例通过 ext 块向 project 对象添加了两个额外属性。此外,此示例通过将 ext.purpose 设置为 null 向每个源集添加了一个名为 purpose 的属性。添加后,您可以像读取和设置预定义属性一样读取和设置所有这些属性。

Gradle 需要特殊语法来添加属性,以便能够快速失败。例如,这使得 Gradle 能够识别脚本何时尝试设置不存在的属性。您可以在可以访问拥有对象的任何地方访问额外属性。这使得额外属性具有比局部变量更宽的范围。子项目可以访问其父项目上的额外属性。

有关额外属性的更多信息,请参阅 API 文档中的 ExtraPropertiesExtension

配置任意对象

示例中的 greet() 任务展示了任意对象配置的示例:

build.gradle.kts
class UserInfo(
    var name: String? = null,
    var email: String? = null
)

tasks.register("greet") {
    val user = UserInfo().apply {
        name = "Isaac Newton"
        email = "isaac@newton.me"
    }
    doLast {
        println(user.name)
        println(user.email)
    }
}
build.gradle
class UserInfo {
    String name
    String email
}

tasks.register('greet') {
    def user = configure(new UserInfo()) {
        name = "Isaac Newton"
        email = "isaac@newton.me"
    }
    doLast {
        println user.name
        println user.email
    }
}
$ gradle -q greet
Isaac Newton
isaac@newton.me

闭包委托(Closure Delegates)

每个闭包都有一个 delegate 对象。Groovy 使用此委托来查找非局部变量和闭包参数的变量和方法引用。Gradle 将此用于配置闭包,其中 delegate 对象引用被配置的对象。

build.gradle
dependencies {
    assert delegate == project.dependencies
    testImplementation('junit:junit:4.13')
    delegate.testImplementation('junit:junit:4.13')
}

默认导入

为了使构建脚本更简洁,Gradle 会自动向脚本添加一组导入语句。

因此,您可以直接写 throw new StopExecutionException(),而无需写 throw new org.gradle.api.tasks.StopExecutionException()

Gradle 会隐式地向每个脚本添加以下导入:

import org.gradle.*
import org.gradle.api.*
import org.gradle.api.artifacts.*
import org.gradle.api.artifacts.capability.*
import org.gradle.api.artifacts.component.*
import org.gradle.api.artifacts.dsl.*
import org.gradle.api.artifacts.ivy.*
import org.gradle.api.artifacts.maven.*
import org.gradle.api.artifacts.query.*
import org.gradle.api.artifacts.repositories.*
import org.gradle.api.artifacts.result.*
import org.gradle.api.artifacts.transform.*
import org.gradle.api.artifacts.type.*
import org.gradle.api.artifacts.verification.*
import org.gradle.api.attributes.*
import org.gradle.api.attributes.java.*
import org.gradle.api.attributes.plugin.*
import org.gradle.api.cache.*
import org.gradle.api.capabilities.*
import org.gradle.api.component.*
import org.gradle.api.configuration.*
import org.gradle.api.credentials.*
import org.gradle.api.distribution.*
import org.gradle.api.distribution.plugins.*
import org.gradle.api.execution.*
import org.gradle.api.file.*
import org.gradle.api.flow.*
import org.gradle.api.initialization.*
import org.gradle.api.initialization.definition.*
import org.gradle.api.initialization.dsl.*
import org.gradle.api.initialization.resolve.*
import org.gradle.api.invocation.*
import org.gradle.api.java.archives.*
import org.gradle.api.jvm.*
import org.gradle.api.launcher.cli.*
import org.gradle.api.logging.*
import org.gradle.api.logging.configuration.*
import org.gradle.api.model.*
import org.gradle.api.plugins.*
import org.gradle.api.plugins.antlr.*
import org.gradle.api.plugins.catalog.*
import org.gradle.api.plugins.jvm.*
import org.gradle.api.plugins.quality.*
import org.gradle.api.plugins.scala.*
import org.gradle.api.problems.*
import org.gradle.api.project.*
import org.gradle.api.provider.*
import org.gradle.api.publish.*
import org.gradle.api.publish.ivy.*
import org.gradle.api.publish.ivy.plugins.*
import org.gradle.api.publish.ivy.tasks.*
import org.gradle.api.publish.maven.*
import org.gradle.api.publish.maven.plugins.*
import org.gradle.api.publish.maven.tasks.*
import org.gradle.api.publish.plugins.*
import org.gradle.api.publish.tasks.*
import org.gradle.api.reflect.*
import org.gradle.api.reporting.*
import org.gradle.api.reporting.components.*
import org.gradle.api.reporting.dependencies.*
import org.gradle.api.reporting.dependents.*
import org.gradle.api.reporting.model.*
import org.gradle.api.reporting.plugins.*
import org.gradle.api.resources.*
import org.gradle.api.services.*
import org.gradle.api.specs.*
import org.gradle.api.tasks.*
import org.gradle.api.tasks.ant.*
import org.gradle.api.tasks.application.*
import org.gradle.api.tasks.bundling.*
import org.gradle.api.tasks.compile.*
import org.gradle.api.tasks.diagnostics.*
import org.gradle.api.tasks.diagnostics.artifact.transforms.*
import org.gradle.api.tasks.diagnostics.configurations.*
import org.gradle.api.tasks.incremental.*
import org.gradle.api.tasks.javadoc.*
import org.gradle.api.tasks.options.*
import org.gradle.api.tasks.scala.*
import org.gradle.api.tasks.testing.*
import org.gradle.api.tasks.testing.junit.*
import org.gradle.api.tasks.testing.junitplatform.*
import org.gradle.api.tasks.testing.testng.*
import org.gradle.api.tasks.util.*
import org.gradle.api.tasks.wrapper.*
import org.gradle.api.toolchain.management.*
import org.gradle.authentication.*
import org.gradle.authentication.aws.*
import org.gradle.authentication.http.*
import org.gradle.build.event.*
import org.gradle.buildconfiguration.tasks.*
import org.gradle.buildinit.*
import org.gradle.buildinit.plugins.*
import org.gradle.buildinit.specs.*
import org.gradle.buildinit.tasks.*
import org.gradle.caching.*
import org.gradle.caching.configuration.*
import org.gradle.caching.http.*
import org.gradle.caching.local.*
import org.gradle.concurrent.*
import org.gradle.external.javadoc.*
import org.gradle.ide.visualstudio.*
import org.gradle.ide.visualstudio.plugins.*
import org.gradle.ide.visualstudio.tasks.*
import org.gradle.ide.xcode.*
import org.gradle.ide.xcode.plugins.*
import org.gradle.ide.xcode.tasks.*
import org.gradle.ivy.*
import org.gradle.jvm.*
import org.gradle.jvm.application.scripts.*
import org.gradle.jvm.application.tasks.*
import org.gradle.jvm.tasks.*
import org.gradle.jvm.toolchain.*
import org.gradle.language.*
import org.gradle.language.assembler.*
import org.gradle.language.assembler.plugins.*
import org.gradle.language.assembler.tasks.*
import org.gradle.language.base.*
import org.gradle.language.base.artifact.*
import org.gradle.language.base.compile.*
import org.gradle.language.base.plugins.*
import org.gradle.language.base.sources.*
import org.gradle.language.c.*
import org.gradle.language.c.plugins.*
import org.gradle.language.c.tasks.*
import org.gradle.language.cpp.*
import org.gradle.language.cpp.plugins.*
import org.gradle.language.cpp.tasks.*
import org.gradle.language.java.artifact.*
import org.gradle.language.jvm.tasks.*
import org.gradle.language.nativeplatform.*
import org.gradle.language.nativeplatform.tasks.*
import org.gradle.language.objectivec.*
import org.gradle.language.objectivec.plugins.*
import org.gradle.language.objectivec.tasks.*
import org.gradle.language.objectivecpp.*
import org.gradle.language.objectivecpp.plugins.*
import org.gradle.language.objectivecpp.tasks.*
import org.gradle.language.plugins.*
import org.gradle.language.rc.*
import org.gradle.language.rc.plugins.*
import org.gradle.language.rc.tasks.*
import org.gradle.language.scala.tasks.*
import org.gradle.language.swift.*
import org.gradle.language.swift.plugins.*
import org.gradle.language.swift.tasks.*
import org.gradle.maven.*
import org.gradle.model.*
import org.gradle.nativeplatform.*
import org.gradle.nativeplatform.platform.*
import org.gradle.nativeplatform.plugins.*
import org.gradle.nativeplatform.tasks.*
import org.gradle.nativeplatform.test.*
import org.gradle.nativeplatform.test.cpp.*
import org.gradle.nativeplatform.test.cpp.plugins.*
import org.gradle.nativeplatform.test.cunit.*
import org.gradle.nativeplatform.test.cunit.plugins.*
import org.gradle.nativeplatform.test.cunit.tasks.*
import org.gradle.nativeplatform.test.googletest.*
import org.gradle.nativeplatform.test.googletest.plugins.*
import org.gradle.nativeplatform.test.plugins.*
import org.gradle.nativeplatform.test.tasks.*
import org.gradle.nativeplatform.test.xctest.*
import org.gradle.nativeplatform.test.xctest.plugins.*
import org.gradle.nativeplatform.test.xctest.tasks.*
import org.gradle.nativeplatform.toolchain.*
import org.gradle.nativeplatform.toolchain.plugins.*
import org.gradle.normalization.*
import org.gradle.platform.*
import org.gradle.platform.base.*
import org.gradle.platform.base.binary.*
import org.gradle.platform.base.component.*
import org.gradle.platform.base.plugins.*
import org.gradle.plugin.devel.*
import org.gradle.plugin.devel.plugins.*
import org.gradle.plugin.devel.tasks.*
import org.gradle.plugin.management.*
import org.gradle.plugin.use.*
import org.gradle.plugins.ear.*
import org.gradle.plugins.ear.descriptor.*
import org.gradle.plugins.ide.*
import org.gradle.plugins.ide.api.*
import org.gradle.plugins.ide.eclipse.*
import org.gradle.plugins.ide.idea.*
import org.gradle.plugins.signing.*
import org.gradle.plugins.signing.signatory.*
import org.gradle.plugins.signing.signatory.pgp.*
import org.gradle.plugins.signing.type.*
import org.gradle.plugins.signing.type.pgp.*
import org.gradle.process.*
import org.gradle.swiftpm.*
import org.gradle.swiftpm.plugins.*
import org.gradle.swiftpm.tasks.*
import org.gradle.testing.base.*
import org.gradle.testing.base.plugins.*
import org.gradle.testing.jacoco.plugins.*
import org.gradle.testing.jacoco.tasks.*
import org.gradle.testing.jacoco.tasks.rules.*
import org.gradle.testkit.runner.*
import org.gradle.util.*
import org.gradle.vcs.*
import org.gradle.vcs.git.*
import org.gradle.work.*
import org.gradle.workers.*

下一步: 学习如何使用任务 >>