可操作任務描述 Gradle 中的工作。這些任務具有動作。在 Gradle 核心中,compileJava
任務編譯 Java 原始碼。Jar
和 Zip
任務將檔案壓縮到封存檔中。

自訂可操作任務可以透過擴展 DefaultTask
類別並定義輸入、輸出和動作來建立。
任務輸入和輸出
可操作任務具有輸入和輸出。輸入和輸出可以是檔案、目錄或變數。
在可操作任務中
-
輸入包含檔案、資料夾和/或配置資料的集合。
例如,javaCompile
任務接受諸如 Java 原始碼檔案和建置腳本配置(如 Java 版本)之類的輸入。 -
輸出指的是一個或多個檔案或資料夾。
例如,javaCompile
產生類別檔案作為輸出。
然後,jar
任務將這些類別檔案作為輸入,並產生 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
的子類別)。由於我們在此處註冊了一個新任務,因此它未預先配置。我們需要配置輸入和輸出。
定義輸入和輸出是使任務成為可操作任務的原因。
如果輸入是我們直接建立或編輯的檔案,例如執行檔案或 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
註解它,而是使用所有任務都具有的通用輸入屬性。然後,我們在 doLast{}
方法內新增動作程式碼,即 println()
陳述式
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 任務產生的 Artifact 應新增到特定配置。
宣告輸入和輸出
您可以透過兩種主要方式配置任務的輸入和輸出
-
靜態配置:直接在任務類別內定義輸入和輸出。這些輸入和輸出將始終應用於任務,無論何時執行。
-
動態配置:動態將輸入和輸出新增到任務,這表示您可以根據特定條件或需求自訂任務每次執行的輸入和輸出。這種方法可以更靈活地精細控制任務的行為。
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 |
檔案的 Map ( |
檔案的 Map ( |
X |
|
|
|
X |
X |
目錄的可迭代項 ( |
目錄的可迭代項 ( |
X |
|
目錄的 Map ( |
目錄的 Map ( |
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
)之後的任務很有用。