可操作任务描述 Gradle 中的工作。这些任务具有操作。在 Gradle 核心中,compileJava
任务编译 Java 源代码。Jar
和 Zip
任务将文件压缩到归档文件中。

可以通过扩展 DefaultTask
类并定义输入、输出和操作来创建自定义可操作任务。
任务输入和输出
可操作任务具有输入和输出。输入和输出可以是文件、目录或变量。
在可操作任务中
-
输入 由文件、文件夹和/或配置数据的集合组成。
例如,javaCompile
任务接受输入,例如 Java 源代码文件和构建脚本配置(如 Java 版本)。 -
输出 指一个或多个文件或文件夹。
例如,javaCompile
生成 class 文件作为输出。
然后,jar
任务将这些 class 文件作为输入,并生成 JAR 归档文件。
明确定义的任务输入和输出有两个目的
-
它们告知 Gradle 关于任务依赖关系。
例如,如果 Gradle 理解compileJava
任务的输出用作jar
任务的输入,它将优先运行compileJava
。 -
它们促进增量构建。
例如,假设 Gradle 识别到任务的输入和输出保持不变。在这种情况下,它可以利用之前构建运行或构建缓存的结果,避免完全重新运行任务操作。
当您应用插件(如 java-library
插件)时,Gradle 将自动注册一些任务并使用默认值配置它们。
让我们定义一个任务,该任务将 JAR 和启动脚本打包到假想示例项目中的归档文件中
gradle-project
├── app
│ ├── build.gradle.kts // app build logic
│ ├── run.sh // script file
│ └── ... // some java code
├── settings.gradle.kts // includes app subproject
├── gradle
├── gradlew
└── gradlew.bat
gradle-project
├── app
│ ├── build.gradle // app build logic
│ ├── run.sh // script file
│ └── ... // some java code
├── settings.gradle // includes app subproject
├── gradle
├── gradlew
└── gradlew.bat
run.sh
脚本可以从构建中执行 Java 应用程序(一旦打包为 JAR)
java -cp 'libs/*' gradle.project.app.App
让我们使用 task.register()
注册一个名为 packageApp
的新任务
tasks.register<Zip>("packageApp") {
}
tasks.register(Zip, "packageApp") {
}
我们使用了 Gradle 核心中现有的实现,即 Zip
任务实现(即 DefaultTask
的子类)。因为我们在此处注册了一个新任务,所以它没有预先配置。我们需要配置输入和输出。
定义输入和输出是使任务成为可操作任务的原因。
如果输入是我们直接创建或编辑的文件,例如 run 文件或 Java 源代码,它通常位于我们项目目录中的某个位置。为了确保我们使用正确的位置,我们使用 layout.projectDirectory
并定义到项目目录根目录的相对路径。
我们提供 jar
任务的输出以及所有依赖项的 JAR(使用 configurations
.runtimeClasspath
)作为额外的输入。
对于输出,我们需要定义两个属性。
首先,目标目录,它应该是构建文件夹内的目录。我们可以通过 layout
访问它。
其次,我们需要为 zip 文件指定一个名称,我们将其命名为 myApplication.zip
以下是完整任务的样子
val packageApp = tasks.register<Zip>("packageApp") {
from(layout.projectDirectory.file("run.sh")) // input - run.sh file
from(tasks.jar) { // input - jar task output
into("libs")
}
from(configurations.runtimeClasspath) { // input - jar of dependencies
into("libs")
}
destinationDirectory.set(layout.buildDirectory.dir("dist")) // output - location of the zip file
archiveFileName.set("myApplication.zip") // output - name of the zip file
}
def packageApp = tasks.register(Zip, 'packageApp') {
from layout.projectDirectory.file('run.sh') // input - run.sh file
from tasks.jar { // input - jar task output
into 'libs'
}
from configurations.runtimeClasspath { // input - jar of dependencies
into 'libs'
}
destinationDirectory.set(layout.buildDirectory.dir('dist')) // output - location of the zip file
archiveFileName.set('myApplication.zip') // output - name of the zip file
}
如果我们运行 packageApp
任务,则会生成 myApplication.zip
$./gradlew :app:packageApp
> Task :app:compileJava
> Task :app:processResources NO-SOURCE
> Task :app:classes
> Task :app:jar
> Task :app:packageApp
BUILD SUCCESSFUL in 1s
3 actionable tasks: 3 executed
Gradle 执行了构建 JAR 文件所需的许多任务,其中包括 app
项目的代码编译和代码依赖项的编译。
查看新创建的 ZIP 文件,我们可以看到它包含运行 Java 应用程序所需的一切
> unzip -l ./app/build/dist/myApplication.zip
Archive: ./app/build/dist/myApplication.zip
Length Date Time Name
--------- ---------- ----- ----
42 01-31-2024 14:16 run.sh
0 01-31-2024 14:22 libs/
847 01-31-2024 14:22 libs/app.jar
3041591 01-29-2024 14:20 libs/guava-32.1.2-jre.jar
4617 01-29-2024 14:15 libs/failureaccess-1.0.1.jar
2199 01-29-2024 14:15 libs/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar
19936 01-29-2024 14:15 libs/jsr305-3.0.2.jar
223979 01-31-2024 14:16 libs/checker-qual-3.33.0.jar
16017 01-31-2024 14:16 libs/error_prone_annotations-2.18.0.jar
--------- -------
3309228 9 files
可操作任务应连接到生命周期任务,以便开发人员只需运行生命周期任务。
到目前为止,我们直接调用了新任务。 让我们将其连接到生命周期任务。
以下内容被添加到构建脚本中,以便使用 dependsOn()
将 packageApp
可操作任务连接到 build
生命周期任务
tasks.build {
dependsOn(packageApp)
}
tasks.build {
dependsOn(packageApp)
}
我们看到运行 :build
也会运行 :packageApp
$ ./gradlew :app:build
> Task :app:compileJava UP-TO-DATE
> Task :app:processResources NO-SOURCE
> Task :app:classes UP-TO-DATE
> Task :app:jar UP-TO-DATE
> Task :app:startScripts
> Task :app:distTar
> Task :app:distZip
> Task :app:assemble
> Task :app:compileTestJava
> Task :app:processTestResources NO-SOURCE
> Task :app:testClasses
> Task :app:test
> Task :app:check
> Task :app:packageApp
> Task :app:build
BUILD SUCCESSFUL in 1s
8 actionable tasks: 6 executed, 2 up-to-date
如果需要,您可以定义自己的生命周期任务。
通过扩展 DefaultTask
实现任务
为了满足更个性化的需求,并且如果没有现有插件提供您需要的构建功能,您可以创建自己的任务实现。
实现类意味着创建自定义类(即类型),这通过子类化 DefaultTask
完成
让我们从 Gradle init
为一个简单的 Java 应用程序构建的示例开始,该应用程序的源代码位于 app
子项目中,公共构建逻辑位于 buildSrc
中
gradle-project
├── app
│ ├── build.gradle.kts
│ └── src // some java code
│ └── ...
├── buildSrc
│ ├── build.gradle.kts
│ ├── settings.gradle.kts
│ └── src // common build logic
│ └── ...
├── settings.gradle.kts
├── gradle
├── gradlew
└── gradlew.bat
gradle-project
├── app
│ ├── build.gradle
│ └── src // some java code
│ └── ...
├── buildSrc
│ ├── build.gradle
│ ├── settings.gradle
│ └── src // common build logic
│ └── ...
├── settings.gradle
├── gradle
├── gradlew
└── gradlew.bat
我们在 ./buildSrc/src/main/kotlin/GenerateReportTask.kt
或 ./buildSrc/src/main/groovy/GenerateReportTask.groovy
中创建一个名为 GenerateReportTask
的类。
为了让 Gradle 知道我们正在实现一个任务,我们扩展了 Gradle 自带的 DefaultTask
类。将我们的任务类设为 abstract
也是有益的,因为 Gradle 将自动处理许多事情
import org.gradle.api.DefaultTask
public abstract class GenerateReportTask : DefaultTask() {
}
import org.gradle.api.DefaultTask
public abstract class GenerateReportTask extends DefaultTask {
}
接下来,我们使用属性和注解定义输入和输出。在此上下文中,Gradle 中的属性充当对它们背后实际值的引用,允许 Gradle 跟踪任务之间的输入和输出。
对于我们任务的输入,我们使用 Gradle 中的 DirectoryProperty
。我们使用 @InputDirectory
对其进行注解,以指示它是任务的输入
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputDirectory
public abstract class GenerateReportTask : DefaultTask() {
@get:InputDirectory
abstract var sourceDirectory: DirectoryProperty
}
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputDirectory
public abstract class GenerateReportTask extends DefaultTask {
@InputDirectory
DirectoryProperty sourceDirectory
}
类似地,对于输出,我们使用 RegularFileProperty
并使用 @OutputFile
对其进行注解。
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputFile
public abstract class GenerateReportTask : DefaultTask() {
@get:InputDirectory
abstract var sourceDirectory: DirectoryProperty
@get:OutputFile
abstract var reportFile: File
}
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputFile
public abstract class GenerateReportTask extends DefaultTask {
@InputDirectory
DirectoryProperty sourceDirectory
@OutputFile
File reportFile
}
定义了输入和输出后,剩下的唯一事情是实际的任务操作,它在用 @TaskAction
注解的方法中实现。在此方法内部,我们编写代码,使用 Gradle 特定的 API 访问输入和输出
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
public abstract class GenerateReportTask : DefaultTask() {
@get:InputDirectory
abstract var sourceDirectory: DirectoryProperty
@get:OutputFile
abstract var reportFile: File
@TaskAction
fun generateReport() {
val fileCount = sourceDirectory.listFiles().count { it.isFile }
val directoryCount = sourceDirectory.listFiles().count { it.isDirectory }
val reportContent = """
|Report for directory: ${sourceDirectory.absolutePath}
|------------------------------
|Number of files: $fileCount
|Number of subdirectories: $directoryCount
""".trimMargin()
reportFile.writeText(reportContent)
println("Report generated at: ${reportFile.absolutePath}")
}
}
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
public abstract class GenerateReportTask extends DefaultTask {
@InputDirectory
DirectoryProperty sourceDirectory
@OutputFile
File reportFile
@TaskAction
void generateReport() {
def fileCount = sourceDirectory.listFiles().count { it.isFile() }
def directoryCount = sourceDirectory.listFiles().count { it.isDirectory() }
def reportContent = """
Report for directory: ${sourceDirectory.absolutePath}
------------------------------
Number of files: $fileCount
Number of subdirectories: $directoryCount
""".trim()
reportFile.text = reportContent
println("Report generated at: ${reportFile.absolutePath}")
}
}
任务操作生成 sourceDirectory
中文件的报告。
在应用程序构建文件中,我们使用 task.register()
注册 GenerateReportTask
类型的任务,并将其命名为 generateReport
。同时,我们配置任务的输入和输出
tasks.register<GenerateReportTask>("generateReport") {
sourceDirectory.set(layout.projectDirectory.dir("src/main"))
reportFile.set(layout.buildDirectory.file("reports/directoryReport.txt"))
}
tasks.build {
dependsOn("generateReport")
}
tasks.register(GenerateReportTask, "generateReport") {
sourceDirectory = layout.projectDirectory.dir("src/main").asFile
reportFile = layout.buildDirectory.file("reports/directoryReport.txt").asFile
}
tasks.build.dependsOn("generateReport")
generateReport
任务连接到 build
任务。
通过运行构建,我们观察到我们的启动脚本生成任务已执行,并且在后续构建中是 UP-TO-DATE
。Gradle 的增量构建和缓存机制与自定义任务无缝协作
./gradlew :app:build
> Task :buildSrc:checkKotlinGradlePluginConfigurationErrors
> Task :buildSrc:compileKotlin UP-TO-DATE
> Task :buildSrc:compileJava NO-SOURCE
> Task :buildSrc:compileGroovy NO-SOURCE
> Task :buildSrc:pluginDescriptors UP-TO-DATE
> Task :buildSrc:processResources NO-SOURCE
> Task :buildSrc:classes UP-TO-DATE
> Task :buildSrc:jar UP-TO-DATE
> Task :app:compileJava UP-TO-DATE
> Task :app:processResources NO-SOURCE
> Task :app:classes UP-TO-DATE
> Task :app:jar UP-TO-DATE
> Task :app:startScripts UP-TO-DATE
> Task :app:distTar UP-TO-DATE
> Task :app:distZip UP-TO-DATE
> Task :app:assemble UP-TO-DATE
> Task :app:compileTestJava UP-TO-DATE
> Task :app:processTestResources NO-SOURCE
> Task :app:testClasses UP-TO-DATE
> Task :app:test UP-TO-DATE
> Task :app:check UP-TO-DATE
> Task :app:generateReport
Report generated at: ./app/build/reports/directoryReport.txt
> Task :app:packageApp
> Task :app:build
BUILD SUCCESSFUL in 1s
13 actionable tasks: 10 executed, 3 up-to-date
任务操作
任务操作是实现任务正在执行的操作的代码,如上一节所示。例如,javaCompile
任务操作调用 Java 编译器将源代码转换为字节码。
可以动态修改已注册任务的任务操作。这对于测试、修补或修改核心构建逻辑很有帮助。
让我们看一个简单的 Gradle 构建示例,其中一个 app
子项目构成一个 Java 应用程序——包含一个 Java 类并使用 Gradle 的 application
插件。该项目在 buildSrc
文件夹中具有公共构建逻辑,其中驻留着 my-convention-plugin
plugins {
id("my-convention-plugin")
}
version = "1.0"
application {
mainClass = "org.example.app.App"
}
plugins {
id 'my-convention-plugin'
}
version = '1.0'
application {
mainClass = 'org.example.app.App'
}
我们在 app
的构建文件中定义一个名为 printVersion
的任务
import org.gradle.api.DefaultTask
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
abstract class PrintVersion : DefaultTask() {
// Configuration code
@get:Input
abstract val version: Property<String>
// Execution code
@TaskAction
fun print() {
println("Version: ${version.get()}")
}
}
import org.gradle.api.DefaultTask
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
abstract class PrintVersion extends DefaultTask {
// Configuration code
@Input
abstract Property<String> getVersion()
// Execution code
@TaskAction
void printVersion() {
println("Version: ${getVersion().get()}")
}
}
此任务做一件简单的事情:它将项目的版本打印到命令行。
该类扩展了 DefaultTask
,并且它有一个 @Input
,类型为 Property<String>
。它有一个用 @TaskAction
注解的方法,该方法打印出版本。
请注意,任务实现清楚地区分了“配置代码”和“执行代码”。
配置代码在 Gradle 的配置阶段执行。它在内存中构建项目的模型,以便 Gradle 知道对于特定的构建调用需要做什么。任务操作周围的所有内容,例如输入或输出属性,都是此配置代码的一部分。
任务操作方法内部的代码是执行代码,它执行实际工作。如果任务是任务图的一部分,并且如果它不能被跳过,因为它处于 UP-TO-DATE 状态或从缓存中获取,它会访问输入和输出以执行某些工作。
一旦任务实现完成,就可以在构建设置中使用它。在我们的约定插件 my-convention-plugin
中,我们可以注册一个新任务,该任务使用新的任务实现
tasks.register<PrintVersion>("printVersion") {
// Configuration code
version = project.version as String
}
tasks.register(PrintVersion, "printVersion") {
// Configuration code
version = project.version.toString()
}
在任务的配置块内,我们可以编写配置阶段代码,该代码修改任务的输入和输出属性的值。这里没有以任何方式引用任务操作。
可以以更紧凑的方式直接在构建脚本中编写像这样的简单任务,而无需为任务创建单独的类。
让我们注册另一个任务并将其称为 printVersionDynamic
。
这次,我们没有为任务定义类型,这意味着任务将属于通用类型 DefaultTask
。此通用类型未定义任何任务操作,这意味着它没有用 @TaskAction
注解的方法。此类型对于定义“生命周期任务”很有用
tasks.register("printVersionDynamic") {
}
tasks.register("printVersionDynamic") {
}
但是,默认任务类型也可以用于动态定义具有自定义操作的任务,而无需额外的类。这通过使用 doFirst{}
或 doLast{}
构造来完成。类似于定义一个方法并注解 @TaskAction
,这会向任务添加一个操作。
这些方法被称为 doFirst{}
和 doLast{}
,因为任务可以有多个操作。如果任务已经定义了操作,您可以使用此区分来决定您的附加操作应在现有操作之前还是之后运行
tasks.register("printVersionDynamic") {
doFirst {
// Task action = Execution code
// Run before exiting actions
}
doLast {
// Task action = Execution code
// Run after existing actions
}
}
tasks.register("printVersionDynamic") {
doFirst {
// Task action = Execution code
// Run before exiting actions
}
doLast {
// Task action = Execution code
// Run after existing actions
}
}
如果您只有一个操作,这里就是这种情况,因为我们从一个空任务开始,我们通常使用 doLast{}
方法。
在任务中,我们首先动态声明我们要打印的版本作为输入。我们没有声明属性并用 @Input
注解它,而是使用了所有任务都具有的通用输入属性。然后,我们将操作代码(一个 println()
语句)添加到 doLast{}
方法内部
tasks.register("printVersionDynamic") {
inputs.property("version", project.version.toString())
doLast {
println("Version: ${inputs.properties["version"]}")
}
}
tasks.register("printVersionDynamic") {
inputs.property("version", project.version)
doLast {
println("Version: ${inputs.properties["version"]}")
}
}
我们看到了在 Gradle 中实现自定义任务的两种替代方法。
动态设置使其更紧凑。但是,在编写动态任务时,很容易混淆配置和执行时状态。您还可以看到“输入”在动态任务中是无类型的,这可能会导致问题。当您将自定义任务实现为类时,您可以清楚地将输入定义为具有专用类型的属性。
动态修改任务操作可以为已注册的任务提供价值,但您出于某种原因需要修改这些任务。
让我们以 compileJava
任务为例。
一旦注册了任务,您就无法删除它。相反,您可以清除其操作
tasks.compileJava {
// Clear existing actions
actions.clear()
// Add a new action
doLast {
println("Custom action: Compiling Java classes...")
}
}
tasks.compileJava {
// Clear existing actions
actions.clear()
// Add a new action
doLast {
println("Custom action: Compiling Java classes...")
}
}
同样很难,在某些情况下甚至不可能,删除您正在使用的插件已设置的某些任务依赖项。相反,您可以修改其行为
tasks.compileJava {
// Modify the task behavior
doLast {
val outputDir = File("$buildDir/compiledClasses")
outputDir.mkdirs()
val compiledFiles = sourceSets["main"].output.files
compiledFiles.forEach { compiledFile ->
val destinationFile = File(outputDir, compiledFile.name)
compiledFile.copyTo(destinationFile, true)
}
println("Java compilation completed. Compiled classes copied to: ${outputDir.absolutePath}")
}
}
tasks.compileJava {
// Modify the task behavior
doLast {
def outputDir = file("$buildDir/compiledClasses")
outputDir.mkdirs()
def compiledFiles = sourceSets["main"].output.files
compiledFiles.each { compiledFile ->
def destinationFile = new File(outputDir, compiledFile.name)
compiledFile.copyTo(destinationFile)
}
println("Java compilation completed. Compiled classes copied to: ${outputDir.absolutePath}")
}
}
理解输入和输出
任务输入和输出对于以下方面很重要
-
最新检查 - Gradle 的增量构建功能通过查看任务输入和输出的更改,帮助您的构建避免多次执行相同的工作。
-
链接任务输入和输出 - 当一个任务的输出链接到另一个任务的输入时,Gradle 可以自动创建任务依赖关系。
-
使用依赖配置 - 任务输出可用于告知 Gradle 应将任务生成的工件添加到特定配置。
声明输入和输出
您可以通过两种主要方式配置任务的输入和输出
-
静态配置: 直接在任务类内部定义输入和输出。这些输入和输出将始终应用于任务,无论何时执行。
-
动态配置: 动态地向任务添加输入和输出,这意味着您可以根据特定条件或要求自定义任务每次执行的输入和输出。这种方法允许对任务的行为进行更大的灵活性和细粒度控制。
abstract class ConfigurableTask : DefaultTask() {
@Input
val inputProperty = project.objects.property(String::class.java)
@OutputFile
val outputFile = project.objects.fileProperty()
// Static Configuration: Inputs and Outputs defined in the task class
init {
group = "custom"
description = "A configurable task example"
}
@TaskAction
fun executeTask() {
println("Executing task with input: ${inputProperty.get()} and output: ${outputFile.get()}")
}
}
// Dynamic Configuration: Adding inputs and outputs to a task instance
tasks.register("dynamicTask", ConfigurableTask::class) {
// Set the input property dynamically
inputProperty.set("dynamic input value")
// Set the output file dynamically
outputFile.set(layout.buildDirectory.file("dynamicOutput.txt"))
}
abstract class ConfigurableTask extends DefaultTask {
@Input
def inputProperty = project.objects.property(String)
@OutputFile
def outputFile = project.objects.fileProperty()
// Static Configuration: Inputs and Outputs defined in the task class
{
group = 'custom'
description = 'A configurable task example'
}
@TaskAction
void executeTask() {
println "Executing task with input: ${inputProperty.get()} and output: ${outputFile.get()}"
}
}
// Dynamic Configuration: Adding inputs and outputs to a task instance
tasks.register('dynamicTask', ConfigurableTask) {
// Set the input property dynamically
inputProperty.set('dynamic input value')
// Set the output file dynamically
outputFile.set(layout.buildDirectory.file('dynamicOutput.txt'))
}
创建延迟输入和输出
Gradle 具有延迟配置的概念,它允许在实际设置任务输入和输出之前引用它们。这通过 Property
类类型完成。
abstract class MyTask : DefaultTask() {
// Avoid Java Bean properties
@Input
var myEagerProperty: String = "default value"
// Use Gradle managed properties instead
@Input
val myLazyProperty: Property<String> = project.objects.property(String::class.java)
@TaskAction
fun myAction() {
println("Use ${myLazyProperty.get()} and do NOT use $myEagerProperty")
}
}
abstract class MyTask extends DefaultTask {
// Avoid Java Bean properties
@Input
String myEagerProperty = "default value"
// Use Gradle managed properties instead
@Input
Property<String> myLazyProperty = project.objects.property(String)
@TaskAction
void myAction() {
println("Use ${myLazyProperty.get()} and do NOT use $myEagerProperty")
}
}
此机制的一个优点是,您可以将一个任务的输出文件链接到另一个任务的输入文件,所有这些都在文件名甚至被确定之前。Property
类也知道它链接到哪个任务,因此以这种方式使用输入和输出使 Gradle 能够自动添加所需的任务依赖关系。

为了确保正确的延迟配置,您应避免使用 Java Bean 类型。让我们探讨 Gradle 延迟类型可以声明为任务输入和输出的常见选项
延迟 Gradle 类型 | Java Bean 类型 | 输入 | 输出 |
---|---|---|---|
|
|
X |
|
|
|
X |
X |
文件迭代 ( |
文件迭代 ( |
X |
X |
文件映射 ( |
文件映射 ( |
X |
|
|
|
X |
X |
目录迭代 ( |
目录迭代 ( |
X |
|
目录映射 ( |
目录映射 ( |
X |
注释
-
字符串仅支持任务输入,不支持输出。这些通常用于配置选项,例如
compileJava
任务类型的sourceCompatibility
。 -
任务输出只能是文件或目录。
-
不要使用
String
、Boolean
、String
和其他标准类型,而应使用Property<T>
。 -
不要使用
List<T>
,而应使用ListProperty<T>
。 -
不要使用
Set<T>
,而应使用SetProperty<T>
。
注解输入和输出
一个好的做法是为您的自定义任务创建一个任务类。该类封装了任务操作逻辑,但也应声明任务期望的任何输入和输出。为此,我们使用注解。
对于任务输入,我们可以使用 @Input
、@InputFile
、@InputDirectory
、@InputFiles
、@Classpath
和 @CompileClasspath
。对于任务输出,我们有 @OutputFile
、@OutputDirectory
、@OutputFiles
、@OutputDirectories
。
以下是所有可用注解的详细信息
注解 | 用法 |
---|---|
|
属性是任务的输入值 |
|
属性是任务的输入文件 |
|
属性是任务的一个或多个输入文件 |
|
属性是任务的输入目录 |
|
属性是一个或多个输入文件或目录,表示 Java 类路径 |
|
属性是一个或多个输入文件或目录,表示 Java 编译类路径 |
|
属性是任务的输出文件[1] |
|
属性是任务的一个或多个输出文件 |
|
属性是任务的输出目录 |
|
属性是任务的一个或多个输出目录 |
|
属性是任务销毁(删除/移除)的一个或多个文件或目录(来自其他任务)[2] |
|
属性是任务的本地状态 |
|
属性是嵌套 bean,应检查其他注解 |
|
属性不是输入或输出,不应在最新检查中考虑 |
|
属性在内部使用,不应在最新检查中考虑 |
|
属性是文件或目录,当属性值为空时,应跳过任务 |
|
属性是文件或目录,可以使用 |
|
属性是任何类型,其值不必指定,并且禁用验证检查 |
|
属性是一个或多个文件,只有文件路径的给定部分是重要的 |
|
与 |
|
与 |
请注意,在 Kotlin 中,注解以 get:
为前缀,因此 @InputFile
变为 @get:InputFile
。
abstract class AllTypes : DefaultTask() {
//inputs
@get:Input
abstract val inputString: Property<String>
@get:InputFile
abstract val inputFile: RegularFileProperty
@get:InputDirectory
abstract val inputDirectory: DirectoryProperty
@get:InputFiles
abstract val inputFileCollection: ListProperty<RegularFile>
@get:Classpath
abstract val inputClasspath: ListProperty<RegularFile>
// outputs
@get:OutputFile
abstract val outputFile: RegularFileProperty
@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty
@get:OutputFiles
abstract val outputFiles: ListProperty<RegularFile>
@get:OutputDirectories
abstract val outputDirectories: ListProperty<Directory>
}
abstract class AllTypes extends DefaultTask {
//inputs
@Input
final abstract Property<String> inputString = ""
@InputFile
final abstract RegularFileProperty inputFile = ""
@InputDirectory
final abstract DirectoryProperty inputDirectory = ""
@InputFiles
final abstract ConfigurableFileCollection inputFileCollection = ""
@Classpath
final abstract ConfigurableFileCollection inputClasspath = ""
// outputs
@OutputFile
final abstract RegularFileProperty outputFile = ""
@OutputDirectory
final abstract DirectoryProperty outputDirectory = ""
@OutputFiles
final abstract ConfigurableFileCollection outputFiles = ""
@OutputDirectories
final abstract ConfigurableFileCollection outputDirectories = ""
}
clean
)后的任务很有用。