1 關(guān)于Groovy
????????Gradle是一種聲明式的構(gòu)建工具。在執(zhí)行時(shí),Gradle并不會(huì)一開始便順序執(zhí)行build.gradle文件中的內(nèi)容,而是分為兩個(gè)階段,第一個(gè)階段是配置階段,然后才是實(shí)際的執(zhí)行階段。
????????配置階段,Gradle將讀取所有build.gradle文件的所有內(nèi)容來(lái)配置Project和Task等,比如設(shè)置Project和Task的Property,處理Task之間的依賴關(guān)系等。
????????Gradle的DSL只是Groovy語(yǔ)言的內(nèi)部DSL,也必須遵循Groovy的語(yǔ)法規(guī)則。Groovy語(yǔ)言中的兩個(gè)概念,一個(gè)是Groovy中的Bean概念,一個(gè)是Groovy閉包的delegate機(jī)制。
1.1 bean
??????? Groovy中的Bean和Java中的Bean有一個(gè)很大的不同,即Groovy動(dòng)態(tài)的為每一個(gè)字段都會(huì)自動(dòng)生成getter和setter,并且我們可以通過(guò)像訪問(wèn)字段本身一樣調(diào)用getter和setter
class GroovyBeanExample {
????private String name
}
def bean = new GroovyBeanExample()
bean.name = 'this is name' //實(shí)際調(diào)用的是"bean.setName('this isname')"
println bean.name //實(shí)際調(diào)用的是"println bean.getName()"
??????? 采用像直接訪問(wèn)的方式的目的是為了增加代碼的可讀性,使它更加自然,而在內(nèi)部,Groovy依然是在調(diào)用setter和getter方法。
2 閉包的delegate機(jī)制
????????簡(jiǎn)單來(lái)說(shuō),delegate機(jī)制可以使我們將一個(gè)閉包中的執(zhí)行代碼的作用對(duì)象設(shè)置成任意其他對(duì)象。
class Child {
????private String name
}
class Parent {
????Child child = new Child();
????void configChild(Closure c) {
???????c.delegate = child
???????c.setResolveStrategy
???????Closure.DELEGATE_FIRST c()
????}
}
def parent = new Parent()
parent.configChild{
????name = "child name"
}
println parent.child.name
??????? 在上面的例子中,當(dāng)調(diào)用configChild()方法時(shí),并沒(méi)有指出name屬性是屬于Child的,但是它的確是在設(shè)置Child的name屬性。事實(shí)上光從該方法的調(diào)用中,我們根本不知道name是屬于哪個(gè)對(duì)象的,你可能會(huì)認(rèn)為它是屬于Parent的。
??????? 真實(shí)情況是,在默認(rèn)情況下,name的確被認(rèn)為是屬于Parent的,但是我們?cè)赾onfigChild()方法的定義中做了手腳,使其不再訪問(wèn)Parent中的name(Parent也沒(méi)有name屬性),而是Child的name。
??????? 在configChild()方法中,我們將該方法接受的閉包的delegate設(shè)置成了child,然后將該閉包的ResolveStrategy設(shè)置成了DELEGATE_FIRST。這樣,在調(diào)用configChild()時(shí),所跟閉包中代碼被代理到了child上,即這些代碼實(shí)際上是在child上執(zhí)行的。
??????? 此外,閉包的ResolveStrategy在默認(rèn)情況下是OWNER_FIRST,即它會(huì)先查找閉包的owner(這里即parent),如果owner存在,則在owner上執(zhí)行閉包中的代碼。這里我們將其設(shè)置成了DELEGATE_FIRST,即該閉包會(huì)首先查找delegate(本例中即child),如果找到,該閉包便會(huì)在delegate上執(zhí)行。
2.1 聯(lián)想gradle中聲明的方法
??????? 在使用Gradle時(shí),我們并沒(méi)有像上面的parent.configChild()一樣指明方法調(diào)用的對(duì)象,而是在build.gradle文件中直接調(diào)用task(),apply()和configuration()等方法。這是因?yàn)樵跊](méi)有說(shuō)明調(diào)用對(duì)象的情況下,Gradle會(huì)自動(dòng)將調(diào)用對(duì)象設(shè)置成當(dāng)前Project。比如調(diào)用apply()方法和調(diào)用project.apply()方法的效果是一樣的。查查Gradle的Project文檔,你會(huì)發(fā)現(xiàn)這些方法都是Project類的方法。
??????? 對(duì)于configurations()方法,該方法實(shí)際上會(huì)將所跟閉包的delegate設(shè)置成ConfigurationContainer,然后在該ConfigurationContainer上執(zhí)行閉包中的代碼。再比如,dependencies()方法,該方法會(huì)將所跟閉包的delegate設(shè)置成DependencyHandler。
3 Gradle語(yǔ)法
3.1 Gradle簡(jiǎn)介
??????? Gradle本身的領(lǐng)域?qū)ο笾饕蠵roject和Task。
??????? Project為Task提供了執(zhí)行上下文,所有的Plugin要么向Project中添加用于配置的Property,要么向Project中添加不同的Task。
??????? 一個(gè)Task表示一個(gè)邏輯上較為獨(dú)立的執(zhí)行過(guò)程,比如編譯Java源代碼,拷貝文件,打包Jar文件,甚至可以是執(zhí)行一個(gè)系統(tǒng)命令或者調(diào)用Ant。另外,一個(gè)Task可以讀取和設(shè)置Project的Property以完成特定的操作。是不是很屌的樣子。
??????? task關(guān)鍵字其實(shí)是一個(gè)groovy中方法的調(diào)用,該方法屬于Project,而大括號(hào)之間的內(nèi)容則表示傳遞給task()方法的一個(gè)閉包。
3.2 task間的依賴
??????? task之間是可以存在依賴關(guān)系,比如TaskA依賴TaskB,那么在執(zhí)行TaskA時(shí),Gradle會(huì)先執(zhí)行TaskB,再執(zhí)行TaskA。我們可以在定義一個(gè)Task的同時(shí)聲明它的依賴關(guān)系:
task helloWorldFour(dependsOn:helloWorldThree) << {
??????? println 'hellohelloWorldFour'
}
或者
task helloWorldFour << {
??????? println 'hellohelloWorldFour'
}
helloWorldFour.dependsOnhelloWorldThree
3.3 可配置的task
??????? 一個(gè)Task除了執(zhí)行操作之外,還可以包含多個(gè)Property,其中有Gradle為每個(gè)Task默認(rèn)定義了一些Property,比如description,logger等。另外,每一個(gè)特定的Task類型還可以含有特定的Property,比如Copy的from和to等。當(dāng)然,我們還可以動(dòng)態(tài)地向Task中加入額外的Property。在執(zhí)行一個(gè)Task之前,我們通常都需要先設(shè)定Property的值。
task helloWorld << {
??????? description = "this ishelloWorld"
??????? println description
}
??????? 或者通過(guò)調(diào)用Task的configure()方法完成Property的設(shè)置:
task helloWorld << {
??????? println description
}
helloWorld.configure{
??????? description = "this ishelloWorld"
}
3.4 花式task
task showDescription1 << {
??????? description = 'this is taskshowDescription'
??????? println description
}
task showDescription2 << {
??????? println description
}
showDescription2.description = 'this is task showDescription'
task showDescription3 << {
??????? println description
}
showDescription3{
??????? description = 'this is taskshowDescription'
}
??????? 對(duì)于每一個(gè)Task,Gradle都會(huì)在Project中創(chuàng)建一個(gè)同名的Property,所以我們可以將該Task當(dāng)作Property來(lái)訪問(wèn),showDescription2便是這種情況。另外,Gradle還會(huì)創(chuàng)建一個(gè)同名的方法,該方法接受一個(gè)閉包,我們可以使用該方法來(lái)配置Task,showDescription3便是這種情況。
3.5 自定義Property
??????? Gradle還為我們提供了多種方法來(lái)自定義Project的Property。
3.5.1 在build.gradle文件中定義Property
??????? 添加一個(gè)名為property1的Property:
ext.property1 = "this is property1"
??????? 或者采用閉包的形式
ext{
??????? property2 = "this isproperty2"
}
??????? 定義了Property后,使用這些Property時(shí)我們則不需要ext,而是可以直接訪問(wèn):
task showProperties << {
??????? println property1
??????? println property2
}
??????? 還可以在執(zhí)行命令行的時(shí)候加屬性
task showCommandLieProperties << {
??????? println property3
}
?//以下是cmd中執(zhí)行命令
gradle-Property3 = "this is property3" showCommandLieProperties
//通過(guò)JVM系統(tǒng)參數(shù)定義Property,與java類似,但是前面要約定以“org.gradle.project”為前綴
gradle-D org.gradle.project.property3 = "this is another property3" showCommandLieProperties
??????? 此外還可以通過(guò)環(huán)境變量來(lái)為Gradle設(shè)置Property,但是每一個(gè)Property都需要以 “ORG_GRADLE_PROJECT_”為前綴:
ORG_GRADLE_PROJECT_property3 = "thisis yet another property3"
3.6 Gradle的Plugin
??????? Gradle最常用的Plugin便是java Plugin了。和其他Plugin一樣,java Plugin并沒(méi)有什么特別的地方,只是向Project中引入了多個(gè)Task和Property。當(dāng)然,java Plugin也有比較與眾不同的地方,其中之一便是它在項(xiàng)目中引入了構(gòu)建生命周期的概念,就像Maven一樣。但是,和Maven不同的是,Gradle的項(xiàng)目構(gòu)建生命周期并不是Gradle的內(nèi)建機(jī)制,而是由Plugin自己引入的。
3.7 依賴管理
??????? 一個(gè)項(xiàng)目總會(huì)依賴于第三方,要么是一個(gè)第三方類庫(kù),要么是自己開發(fā)的另一個(gè)module
配置Gradle的Repository,就是告訴Gradle在什么地方去獲取這些依賴
repositories{
??????? mavenCentral()
??????? jCentral()
}
??????? jCentral()是大于mavenCentral()的一個(gè)倉(cāng)庫(kù),現(xiàn)在是studio默認(rèn)的倉(cāng)庫(kù)
??????? Gradle對(duì)依賴進(jìn)行分組,允許編譯時(shí)使用一組依賴,運(yùn)行時(shí)使用另一組依賴。每一組依賴稱為一個(gè)Configuration,在聲明依賴時(shí),我們實(shí)際上是在設(shè)置不同的Configuration。
??????? 要定義一個(gè)Configuration,我們可以通過(guò)以下方式完成:studio一般不需要設(shè)置,應(yīng)該是有默認(rèn)的,即為classpath。
configurations{
??????? myDependency
}
??????? 通過(guò)dependencies()方法向myDependency中加入實(shí)際的依賴項(xiàng):
dependencies{
??????? //下面的myDependency是關(guān)鍵
??????? myDependency 'org.apache.commons:commons-lang3:3.0'
}
//類似studio中的classpath
dependencies{
??????? classpath 'com.android.tools.build:gradle:1.3.0'
}
//還有 這里的compile,testCompile
dependencies{
??????? compile project(':library')
??????? compile 'com.android.support:recyclerview-v7:22.2.1'
??????? compile 'com.android.support:design:22.2.1'
??????? compile 'com.evernote:android-intent:1.0.1'
??????? testCompile 'junit:junit:4.8.2'
}
??????? myDependency,classpath,compile,testCompile都是Configuration(一組依賴)。除了myDependency都不是我們定義的, android Plugin會(huì)自動(dòng)定義compile和testCompile分別用于編譯Java源文件和編譯Java測(cè)試源文件。classpath應(yīng)該是用于所有,我類推的。
??????? Gradle還允許我們聲明對(duì)其他Project或者文件系統(tǒng)的依賴。
dependencies{
??????? //library是另一個(gè)module的名字
??????? compile project(':library')
}
??????? 對(duì)于本地文件系統(tǒng)中的Jar文件,我們可以通過(guò)以下方式聲明對(duì)其的依賴:
dependencies{
??????? //java compile files('spring-core.jar', 'spring-aap.jar')
??????? compile fileTree(dir: 'deps', include:'*.jar')
??????? //studio中一般這么寫
??????? compile fileTree(dir: 'libs', include:['*.jar'])
}
3.8 構(gòu)建多module的project
??????? Gradle為每個(gè)build.gradle都會(huì)創(chuàng)建一個(gè)相應(yīng)的module領(lǐng)域?qū)ο?,在編寫Gradle腳本時(shí),我們實(shí)際上是在操作諸如module這樣的Gradle領(lǐng)域?qū)ο?。在多module的項(xiàng)目中,我們會(huì)操作多個(gè)module領(lǐng)域?qū)ο?。Gradle提供了強(qiáng)大的多module構(gòu)建支持。
??????? 要?jiǎng)?chuàng)建多module的Gradle項(xiàng)目,我們首先需要在根(Root)Project中加入名為settings.gradle的配置文件,該文件應(yīng)該包含各個(gè)子module(其實(shí)就是一個(gè)子project)的名稱。如setting.gradle中:
include'library', 'demo'
??????? 類似module(子project)的build.gradle,(Root)Project也有自己的build.gradle,在里面通常設(shè)置:
allprojects{
??????? repositories {
? ? ? ? ? ? jcenter()
??????? }
??????? //通常studio項(xiàng)目沒(méi)有,咱自己加的
??????? apply plugin: 'idea'
??????? task allTask << {
????????????println project.name
??????? }
}
??????? allprojects()方法將repositories配置一次性地應(yīng)用于所有的module(子Project)和root-project本身,當(dāng)然也包括定義的Task,這個(gè)task配置到所有module里面了和root-project。
????????subprojects()方法用于配置所有的子Project(不包含根Project)。
4 參考鏈接
(Good)Gradle學(xué)習(xí)總結(jié)——根本上看透Android Studio構(gòu)建
http://www.itdecent.cn/p/60e556a968de
深入理解Android之Gradle
http://blog.csdn.net/innost/article/details/48228651
Gradle學(xué)習(xí)系列之一——Gradle快速入門
http://www.cnblogs.com/davenkin/p/gradle-learning-1.html
Gradle學(xué)習(xí)系列之二——創(chuàng)建Task的多種方法
http://www.cnblogs.com/davenkin/p/gradle-learning-2.html
Gradle學(xué)習(xí)系列之三——讀懂Gradle語(yǔ)法
http://www.cnblogs.com/davenkin/p/gradle-learning-3.html
Gradle學(xué)習(xí)系列之四——增量式構(gòu)建
https://www.cnblogs.com/CloudTeng/p/3418260.html
Gradle學(xué)習(xí)系列之五——自定義Property
http://www.cnblogs.com/davenkin/p/gradle-learning-5.html
Gradle學(xué)習(xí)系列之六——使用Java Plugin
Gradle學(xué)習(xí)系列之八——構(gòu)建多個(gè)Project
Gradle學(xué)習(xí)系列之九——自定義Task類型
Gradle學(xué)習(xí)系列之十——自定義Plugin(本系列完)
理解與配置Android studio中的gradle
http://blog.csdn.net/u011913612/article/details/51732632
Android Studio中Gradle使用詳解
http://www.itdecent.cn/p/02cb9a0eb2a0
Android Studio Gradle命令和配置
https://www.2cto.com/kf/201704/626582.html
gradle深入理解以及在android studio中的使用
http://www.itdecent.cn/p/1680700a974f
Android Gradle 語(yǔ)法簡(jiǎn)介
http://blog.csdn.net/wangbaochu/article/details/51177672
(Good)Android Gradle 完整指南
https://www.cnblogs.com/laughingQing/p/5855774.html
Cannot get property 'compileSdkVersion' on
extra properties extension as it does not exist問(wèn)題解決
http://blog.csdn.net/u013768203/article/details/53140449
使用 代碼 讀取build.gradle 中的自定義配置信息