前言
在學(xué)習(xí)Gradle時(shí),首先要對(duì)Groovy這個(gè)腳本語(yǔ)言的常用的東西有個(gè)概念,以后也好閱讀別人的腳本或者自己寫(xiě)插件。
Groovy中的基本數(shù)據(jù)類(lèi)型
數(shù)據(jù)類(lèi)型可以在Groovy Api 在線文檔的lang包下看到,大致有以下三類(lèi):
1. java中的基本類(lèi)型
2. 容器類(lèi)型(List ,Map,Range)
3. 閉包
- List
類(lèi)似ArrayList , def alist = ['a',1,true]; alist[1] == 1; alist.size == 3 - Map
類(lèi)似LinkedHashMap,def amap = ['key1':value1,'key2':value2]; - Range
對(duì)List的擴(kuò)展
IntRange :Represents a list of Integer objects from a specified int up (or down) to and including a given to
ObjectRange:Represents an inclusive list of objects from a value to a value using comparators.
def arange = 1..5 //表示1,2,3,4,5
def arange = 1..<5//表示1,2,3,4 -
Closure
閉包的定義:
def a = 1
def c = { a }
assert c() == 1
//或者
def a = 1
def c = {a}
assert c.call() == 1
在閉包的學(xué)習(xí)中,有以下需要注意的地方:
- it
如果閉包沒(méi)定義參數(shù)的話,則隱含有一個(gè)參數(shù),這個(gè)參數(shù)名字叫 it ,和 this 的作用類(lèi)似。it 代表閉包的參數(shù)。 - 省略圓括號(hào)
閉包在 Groovy 中大量使用,比如很多類(lèi)都定義了一些函數(shù),這些函數(shù)最后一個(gè)參數(shù)都
是一個(gè)閉包。比如:
public static <T> List<T> each(List<T> self, Closure closure)
上面這個(gè)函數(shù)表示針對(duì)List的每一個(gè)元素都會(huì)調(diào)用closure做一些處理。這里的closure,
就有點(diǎn)回調(diào)函數(shù)的感覺(jué)。但是,在使用這個(gè) each 函數(shù)的時(shí)候,我們傳遞一個(gè)怎樣的 Closure
進(jìn)去呢?比如:
def iamList = [1,2,3,4,5] //定義一個(gè) List
iamList.each{ //調(diào)用它的 each,這段代碼的格式看不懂了吧?each 是個(gè)函數(shù),圓括號(hào)去哪了?
println it
}
上面代碼有兩個(gè)知識(shí)點(diǎn):
each 函數(shù)調(diào)用的圓括號(hào)不見(jiàn)了!原來(lái),Groovy 中,當(dāng)函數(shù)的最后一個(gè)參數(shù)是閉包的話,可以省略圓括號(hào)。比如
def testClosure(int a1,String b1, Closure closure){
//do something
closure() //調(diào)用閉包
}
那么調(diào)用的時(shí)候,就可以免括號(hào)!
testClosure 4, "test", {
println "i am in closure"
}
省略圓括號(hào)雖然使得代碼簡(jiǎn)潔,看起來(lái)更像腳本語(yǔ)言,但是它這經(jīng)常會(huì)讓我 confuse(不知道其他人是否有同感),以 doLast 為例,完整的代碼應(yīng)該按下面這種寫(xiě)法:
doLast({
println 'Hello world!'
})
有了圓括號(hào),你會(huì)知道 doLast 只是把一個(gè) Closure 對(duì)象傳了進(jìn)去。很明顯,它不代表這段腳本解析到 doLast 的時(shí)候就會(huì)調(diào)用 println 'Hello world!' 。但是把圓括號(hào)去掉后,就感覺(jué)好像 println 'Hello world!'立即就會(huì)被調(diào)用一樣!
- 如何確定 Closure 的參數(shù)
另外一個(gè)比較讓人頭疼的地方是,Closure 的參數(shù)該怎么搞?還是剛才的 each 函數(shù):
public static <T> List<T> each(List<T> self, Closure closure)
each 函數(shù)說(shuō)明中,將給指定的 closure 傳遞 Set 中的每一個(gè) item。所以,closure的參數(shù)只有一個(gè)。
findAll 中呢,就不知道該怎么辦了。一個(gè)是沒(méi)說(shuō)明往 Closure 里傳什么。另外沒(méi)說(shuō)明 Closure的返回值是什么.....。
Closure 雖然很方便,但是它一定會(huì)和使用它的上下文有極強(qiáng)的關(guān)聯(lián)。要不,作為類(lèi)似回調(diào)這樣的東西,我如何知道調(diào)用者傳遞什么參數(shù)給 Closure 呢?此問(wèn)題如何破解?只能通過(guò)查詢(xún) API 文檔才能了解上下文語(yǔ)義。所以最初階段,SDK 查詢(xún)是必不可少的。
文件IO和XML操作
文件讀寫(xiě):File
def targetFile = new File(文件名) <==File 對(duì)象還是要?jiǎng)?chuàng)建的。
看看 Groovy 定義的 API:
1 讀該文件中的每一行:eachLine 的唯一參數(shù)是一個(gè) Closure。Closure 的參數(shù)是文件每一行的內(nèi)容
其內(nèi)部實(shí)現(xiàn)肯定是 Groovy 打開(kāi)這個(gè)文件,然后讀取文件的一行,然后調(diào)用 Closure...
targetFile.eachLine{
String oneLine ->
println oneLine
} <==是不是令人發(fā)指??!
2 直接得到文件內(nèi)容
targetFile.getBytes() <==文件內(nèi)容一次性讀出,返回類(lèi)型為 byte[]
//注意前面提到的 getter 和 setter 函數(shù),這里可以直接使用 targetFile.bytes....
3 使用 InputStream.InputStream 的 SDK 在http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/InputStream.html
def ism = targetFile.newInputStream()
//操作 ism,最后記得關(guān)掉
ism.close
4 使用閉包操作 inputStream,以后在 Gradle 里會(huì)??吹竭@種搞法
targetFile.withInputStream{ ism ->
操作 ism. 不用 close。Groovy 會(huì)自動(dòng)替你 close
}
5 寫(xiě)文件
def srcFile = new File(源文件名)
def targetFile = new File(目標(biāo)文件名)
targetFile.withOutputStream{ os->
srcFile.withInputStream{ ins->
os << ins //利用 OutputStream 的<<操作符重載,完成從 inputstream 到 OutputStream的輸出
}
}
Xml解析: GPathResult,XmlSlurper
def androidManifest = new XmlSlurper().parse("AndroidManifest.xml")
println androidManifest['@android:versionName']
或者
println androidManifest.@'android:versionName'
Gradle模型常用數(shù)據(jù)類(lèi)型
-
Project
映射到build.gradle文件,從Project你可以獲取Gradle的所有features,其中主要的Method如下:




-
Task
一個(gè)工程是很多個(gè)Tasks的集合,每個(gè)Task都會(huì)有一個(gè)基本的獨(dú)特的功能,或者單元測(cè)試,或者單純的打一個(gè)jar包。
在script中可以這樣定義Task:
task myTask
task myTask { configure closure }
task myTask(type: SomeType)
task myTask(type: SomeType) { configure closure }
TaskContainer包含了所有的task任務(wù),我們可以通過(guò)在Project中的getTasks().findByPath('packageReleaseJniLibs')來(lái)獲取特定名字的task,然后可以通過(guò)dependsOn,mustRunAfter 等來(lái)插入自己定義的Task。

* [Gradle
](https://docs.gradle.org/current/dsl/org.gradle.api.invocation.Gradle.html)
Gradle對(duì)象實(shí)例,通過(guò)[Project.getGradle()](https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:gradle)可以 獲取。我們需要重點(diǎn)關(guān)注下其中的method方法,對(duì)于我們定制化有很大的意義。


* [Settings
](https://docs.gradle.org/current/dsl/org.gradle.api.initialization.Settings.html)
映射到settings.gradle文檔
* [Script
](https://docs.gradle.org/current/dsl/org.gradle.api.Script.html)
簡(jiǎn)單來(lái)說(shuō),Script 是一個(gè)接口,Gradle中的腳本會(huì)implement這個(gè)接口并實(shí)現(xiàn)自己的功能,并且每個(gè)Script都會(huì)有個(gè)Groovy對(duì)象相應(yīng),例如一個(gè) build script 對(duì)應(yīng)一個(gè)project,一個(gè)init script 對(duì)應(yīng)一個(gè)Gradle 對(duì)象。在此Script對(duì)象上找不到的任何屬性引用或方法調(diào)用都將轉(zhuǎn)發(fā)到委托對(duì)象。
#參考
* [Groovy Api 在線文檔](http://www.groovy-lang.org/api.html)
* [Gradle Api 在線文檔](https://docs.gradle.org/current/javadoc/)