上一篇文章中,我們提到了Gradle的一些基本概念,如Project、Task以及Action,并且創建了我們的第一個Task。這次我們來看看Gradle中關于Project和Task的更多細節。
1. Project和Task
對于build.gradle配置文件,當運行Gradle <Task> 時,Gradle會為我們創建一個Project的對象,來映射build.gradle中的內容。其中呢,對于不屬于任何Task范疇的代碼,Gradle會創建一個Script類的對象,來執行這些代碼;對于Task的定義,Gradle會創建Task對象,并將它會作為project的屬性存在(實際上是通過getTaskName完成的)。ok,看一個簡單的例子:
新建文件basic/build.gradle,然后加入如下部分代碼:
println "the project name is $name"
task hello << {
println "the current task name is $name"
println "hello world"
}
當運行這個例子時,首先Gradle會創建一個Porject的對象,然后將它和build.gradle的內容映射起來。在這個例子中,project包括兩部分:
1)可執行腳本定義
按照之前提到的,可執行腳本的定義將直接被創建成對應的Script類的對象
在這個例子中,Script對應的部分就是第一行println的部分,然后執行的結果就是打印出 "the project name is basic"。
默認的,Project的名字是當前build.gradle所在目錄的名字,在這個例子中,build.gradle放在basic目錄下,因此,project的name也就是basic.
2)Task定義
在這個例子中,Gradle將創建一個Task的實例,將其和定義的task內容關聯起來。另外,按照之前所說的,當Gradle運行時,我們可以使用訪問project屬性的方式去訪問它。
例如,這個例子中,我們可以使用project.hello來訪問這個task。因為這個task hello已經成為project的一個屬性,那么當我們使用gradle properties(properties是gradle自帶的一個Task,它能列出當前project級別的所有屬性,可以使用gradle tasks查看更多內建的Task)來獲取project級別的屬性列表時,也將會得到'hello'。
另外,有一點要注意的是,在這個例子中,task中使用的$name,并不是Project的name,它是當前Task的name,因為它被使用在Task的scope里。
執行Gradle hello,輸出的結果將是:
current project name is test
the current task name is hello
hello world
2. 定義屬性
在Gradle中,我們可以定義以下三種屬性并使用它們:
1)System Properties
System Properties 實際是指的JVM的system properties。我們知道,在運行java程序時,可以使用-D來設置Java的系統變量,在Gradle中,你也可以做同樣的事情。比如
gradle xxx -DmySystemProp=xxxx
同時,在build.gradle中,應該這樣使用這個變量:
task printSysProps << {
println System.properties['system']
}
2)Project Properties
Project Properties是Gradle專門為Project定義的屬性。它的最大優點在于當運行gradle的時候,我們可以使用-P來設置它的值。比如,
gradle xxx -PmyProjectProp=xxxxx
而在build.gradle中,可以這樣使用這個變量:
task printProps << {
if (project.hasProperty('commandLineProjectProp')) {
println commandLineProjectProp
}
}
同時,當我們執行gradle properties查看屬性列表時,這個變量的名稱以及值會顯示在結果中。 3)Ext(ra) Properties
另外,我們還可以為Project或者Task定義Ext屬性,也稱動態屬性,我們必須使用關鍵字ext(對應ExtraPropertiesExtension的實例)去定義動態屬性。從這點可以看出,Gradle已經為我們設計了很多不同的類,去做不同的事情,我們只需要遵循Convention,使用他們即可。如果忘記寫ext關鍵字,gradle運行時則會提示:
"Dynamic properties are deprecated...."。這是因為以前版本的gradle定義動態屬性時,不需要加ext關鍵字的。
對于Project和Task而言,動態屬性定義的方式完全一樣,只是作用域不一樣。
當定義完成后,我們就可以使用project.prop 或者 task.prop來訪問這些動態屬性了。下面讓我們看一個例子:
ext.projectProperties="ext projectProperties-value"
task printExtProps << {
ext.taskProperties="ext.task.properties-value"
if (project.hasProperty('projectProperties')){
println "ext.projectProperties values is " + projectProperties
}
if (printExtProps.hasProperty('taskProperties')){
println "task has defined ext.taskProperties value is " + taskProperties
}
}
注意:,對于ext定義的動態屬性,并不能通過外部的方式修改它的值,只能在build.gradle中去設置或者修改它的值。
同時,如果是為project定義的ext動態屬性,也會顯示在gradle properties的結果中。
3. Task依賴
當構建一個復雜的項目時,不同task之間存在依賴是必然的。比如說,如果想運行'部署'的task,必然要先運行 編譯、打包、檢測服務器等task,只有當這被些被依賴的task執行完成后,才會部署。對于這種行為之間的依賴,Ant、Maven都提供了聲明式的定義,非常簡單。同樣,使用Gradle定義task之間的依賴也是件很容易的事。
例如,定義如下兩個Task,并且在"intro"里加上"dependendsOn"的關鍵字,如下所示:
task hello << {
println 'Hello world!'
}
task intro(dependsOn: hello) << {
println "I'm Gradle"
}
執行 "gradle intro",結果將是:
Hello World
I'm Gradle
由此可見,當執行gradle intro時,intro依賴的task hello會先被執行。除此之外,dependensOn也支持定義多個task的依賴,使用[]括起來即可。例如
task A(dependensOn:['B','C','D']) <<{ xxx }
除了使用dependensOn跟字符串來定義依賴,我們也可以使用taskX.dependensOn taskY這種形式:
task taskX << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
taskX.dependsOn taskY
或者,也可以使用閉包:
task taskX << {
println 'taskX'
}
taskX.dependsOn {
tasks.findAll { task -> task.name.startsWith('lib') }
}
task lib1 << {
println 'lib1'
}
除了之前講的task的部分,Gradle還為我們提供了很多可用的API,更多的細節大家可以參考下Gradle的文檔。這里我列出一個常用的方法onlyIf。在Gradle里,我們可以使用“OnlyIf()”來決定當前task是否需要被執行,例如:新建build.gradle,加入如下代碼:
task hello << {
println 'hello world'
}
hello.onlyIf { !project.hasProperty('skipHello') }
當我們直接執行"gradle hello"時,沒有任何結果,當我們執行"gradle hello -PskipHello=xxxx"時,會輸出"hello world"。
4. 總結
OK.今天對gradle的總結到此為止。總體而言,用DSL的代碼而不是xml來定義構建的過程,還是很fancy的。