1.Gradle的Project從本質(zhì)上說只是含有多個Task的容器,一個Task與Ant的Target相似,表示一個邏輯上的執(zhí)行單元。我們可以通過很多種方式定義Task,所有的Task都存放在Project的TaskContainer中。
2.Task可以理解為Gradle的執(zhí)行單元,實在是太重要了。根據(jù)前面的分析,Gradle通過一個個task來完成具體的構(gòu)建任務(wù),下面我們來看下Task的定義。
(1)調(diào)用Project的task()方法創(chuàng)建Task
在使用Gradle時,創(chuàng)建Task最常見的方式便是:
task helloWord << {
println 'Hello World! Charles'
}
這里的“<<”表示追加的意思,即向hello中加入執(zhí)行過程。我們還可以使用doLast來達到同樣的效果:
task hello2 {
doLast {
println 'hello2'}
}
另外,如果需要向Task的最前面加入執(zhí)行過程,我們可以使用doFirst:
task hello3 {
doFirst {
println 'hello3'}
}
除此之外,doLast還有一個等價的操作leftShift,leftShift還可以縮寫為<<,因此下這三種實現(xiàn)效果等價
helloWord .leftShift {
println 'Hello World! Charles--left'
}
在上面的例子中,Gradle的DSL向我們展示了一種非常自然的風格來創(chuàng)建Task,而事實上這些都只是一種內(nèi)部DSL,也即必須符合groovy的語法要求。上面的task關(guān)鍵字實際上是一個方法調(diào)用,該方法屬于Project。Project中存在多個重載的task()方法。和Ruby等動態(tài)語言一樣,在調(diào)用groovy方法時,我們不用將參數(shù)放在括號里面。
以上我們自定義的Task都位于TaskContainer中,Project中的tasks屬性即表示該TaskContainer。為此,我們可以新建一個Task來顯示這些信息:
task showTasks {
println tasks.class
println tasks.size()
}
將以上4個Task放在同一個build.gradle中,再執(zhí)行g(shù)radle showTasks,命令行輸出如下:
...
class org.gradle.api.internal.tasks.DefaultTaskContainer_Decorated
4
...
上面的DefaultTaskContainer_Decorated表示tasks類型,而4表示該TaskContainer中包含有4個自定義的Task——包括showTasks本身。
(2)通過TaskContainer的create()方法創(chuàng)建Task而Project又維護了一個TaskContainer類型的屬性tasks,那么我們完全可以直接向TaskContainer里面添加Task。查查TaskContainer的API文檔可以發(fā)現(xiàn),TaskContainer向我們提供了大量重載的create()方法用于添加Task。
tasks.create(name:'hello4') <<{
println 'hello4'
}
(3)聲明Task之間的依賴關(guān)系
Task之間是可以存在依賴關(guān)系,比如TaskA依賴TaskB,那么在執(zhí)行TaskA時,Gradle會先執(zhí)行TaskB,再執(zhí)行TaskA。我們可以在定義一個Task的同時聲明它的依賴關(guān)系:
task hello5(dependsOn:hello4) << {
println 'hello5'
}
當然,我們也可以在定義Task之后再聲明依賴:
task hello6 << {
println 'hello6'
}
hello6.dependsOn hello5
(4)配置Task
一個Task除了執(zhí)行操作之外,還可以包含多個Property,其中有Gradle為每個Task默認定義的Property,比如description,logger等。另外,每一個特定的Task類型還可以含有特定的Property,比如Copy的from和to等。當然,我們還可以動態(tài)地向Task中加入額外的Property。在執(zhí)行一個Task之前,我們通常都需要先設(shè)定Property的值,Gradle提供了多種方法設(shè)置Task的Property值。
首先,我們可以在定義Task的時候?qū)roperty進行配置:
task hello7 << {
description = "this is hello7"
println description
}
我們還可以通過閉包的方式來配置一個已有的Task:
task hello8 << {
println description
}
hello8 {
description = "this is hello8"
}
需要注意的是,對hello8的description設(shè)置發(fā)生在創(chuàng)建該Task之后,在執(zhí)行“gradle hello8”時,命令行依然可以打印出正確的“this is hello8”,這是因為Gradle在執(zhí)行Task時分為兩個階段,首先是配置階段,然后才是實際執(zhí)行階段。所以在執(zhí)行hello8之前,Gradle會掃描整個build.gradle文檔,將hello8的description設(shè)置為“this is hello8”,然后執(zhí)行hello8,此時hello8的description已經(jīng)包含了設(shè)置后的值。
我們還可以通過調(diào)用Task的configure()方法完成Property的設(shè)置:
task hello9 << {
println description
}
hello9.configure {
description = "this is hello9"
}
實際上,通過閉包的方式配置Task在內(nèi)部也是通過調(diào)用Task的configure()方法完成的
(5)group task屬于哪個組下面我來看一個列子
// 定義一個名字為Cls的task,屬于Charles分組,并且依賴myTask1和myTask2兩個task。
project.task('ClsTask', group: "charles", description: "我自己的Task", dependsOn: ["myTask1", "myTask2"] ).doLast {
println "execute ClsTask"
}
嘗試執(zhí)行g(shù)radle ClsTask,結(jié)果如下:
:myTask1
execute myTask1
:myTask2
execute myTask2
:ClsTask
execute ClsTask
BUILD SUCCESSFUL
(6)定義Task的時候是可以指定很多參數(shù)的,如下所示:
參數(shù) 含義 默認值
name task的名字 不能為空,必須指定
type task的“父類” DefaultTask
overwrite 是否替換已經(jīng)存在的task false
dependsOn task依賴的task的集合 []
group task屬于哪個組 null
descriptions task的描述 null
到此 Gradle 定義Task就全部講完。最后,定義task的API很多,我介紹了最常用的部分,剩下的細節(jié)還是需要大家查看Gradle文檔,其實學習Gradle就是一個查文檔的過程。如下幾個文檔,大家讀讀。
Project API