【Android開發(fā)高級(jí)系列】Gradle專題

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 參考鏈接

GoodGradle學(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í)系列之七——管理

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 StudioGradle使用

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

GoodAndroid 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 中的自定配置信息

http://blog.csdn.net/winnershili/article/details/78532833

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容