Android Studio作為Android應(yīng)用開發(fā)的官方IDE,默認使用Gradle作為構(gòu)建工具筹燕,所以對于Android應(yīng)用開發(fā)來說,Gradle是必須要掌握的工具。然而現(xiàn)實是舞丛,很多Android應(yīng)用開發(fā)人員都不太了解Gradle,并且網(wǎng)上大部分關(guān)于Android Gradle的資料都是幫助解決某個具體的配置問題果漾,缺乏系統(tǒng)深入的講解球切。本文就來系統(tǒng)且深入的學(xué)習Gradle。
Java構(gòu)建工具的發(fā)展
Java構(gòu)建工具最早出現(xiàn)的是Ant绒障。Ant里的每一個任務(wù)(target)都可以互相依賴吨凑。Ant的最大缺點就是依賴的外部庫也要添加到版本控制系統(tǒng)中,因為Ant沒有一個機制來把這些外部庫文件放在一個中央庫里面户辱,結(jié)果就是不斷的拷貝和粘貼代碼鸵钝。
隨后Maven在2004年出現(xiàn)了,Maven引入了標準的項目和路徑結(jié)構(gòu)焕妙,還有依賴管理蒋伦,不幸的是自定義的邏輯很難實現(xiàn),唯一的方法就是引入插件焚鹊。
隨后Ant通過Apache Ivy引入依賴管理來跟上Maven的腳步痕届,Ant和Ivy集成實現(xiàn)了聲明式的依賴,比如項目的編譯和打包過程末患。
Gradle的出現(xiàn)滿足了很多現(xiàn)在構(gòu)建工具的需求研叫,Gradle提供了一個DSL(領(lǐng)域特定語言),一個約定優(yōu)于配置的方法璧针,還有更強大的依賴管理嚷炉,Gradle使得我們可以拋棄XML的繁瑣配置,引入動態(tài)語言Groovy來定義你的構(gòu)建邏輯探橱。
Why Gradle
Android Studio Project Site上對Android Studio為何選用Gradle作為構(gòu)建工具描述如下:
Gradle is an advanced build system as well as an advanced build toolkit allowing to create custom build logic through plugins. Here are some of its features that made us choose Gradle:
- Domain Specific Language (DSL) based on Groovy, used to describe and manipulate the build logic
- Build files are Groovy based and allow mixing of declarative elements through the DSL and using code to manipulate the DSL elements to provide custom logic.
- Built-in dependency management through Maven and/or Ivy.
- Very flexible. Allows using best practices but doesn’t force its own way of doing things.
- Plugins can expose their own DSL and their own API for build files to use.
- Good Tooling API allowing IDE integration.
DSL申屹,領(lǐng)域特定語言绘证,指不像通用目的語言那樣目標范圍涵蓋一切軟件問題,而是專門針對某一特定問題的計算機語言哗讥,如init.rc嚷那,renderscript等。
理解Groovy
由于Gradle是基于Groovy開發(fā)的杆煞,要深入理解Gradle魏宽,必須先了解Groovy。Groovy概括的說就是把寫Java程序變得像寫腳本一樣簡單决乎,寫完就可以執(zhí)行队询,Groovy內(nèi)部會將其編譯成Java字節(jié)碼,然后啟動虛擬機來執(zhí)行构诚。Groovy是用于Java虛擬機蚌斩,具有像Python,Ruby和Smalltalk語言特性的敏捷的動態(tài)語言唤反,使用該種語言不必編寫過多的代碼凳寺,同時又具有閉包和動態(tài)語言中的其他特性。Groovy使用方式基本與Java代碼的使用方式相同彤侍,其設(shè)計時充分考慮了Java集成肠缨,這使Groovy與Java代碼的互操作很容易。
Groovy安裝
Mac上可以直接通過Homebrew安裝Groovy盏阶,具體命令如下:
$ brew install groovy
安裝完成后可通過如下命令查看:
$ groovy -v
Groovy Version: 2.4.8 JVM: 1.8.0_45 Vendor: Oracle Corporation OS: Mac OS X
Groovy基礎(chǔ)語法
- 可以不同分號結(jié)尾晒奕。
- 支持動態(tài)類型,即定義變量時可以不指定其類型名斟。
- 可以使用關(guān)鍵字def定義變量和函數(shù)(Groovy推薦)(其實def會改變變量的作用域)脑慧。
- Groovy中的所有事物都是對象。
def var = "Hello Groovy"
println var
println var.class
var = 5
println var
println var.class
輸出結(jié)果如下:
Hello Groovy
class java.lang.String
5
class java.lang.Integer
- 單引號中的內(nèi)容嚴格對應(yīng)Java的String砰盐,不對$進行轉(zhuǎn)義闷袒。
- 雙引號的內(nèi)容如果有$則會對$表達式先求值(GString)。
- 三引號可以指示一個多行的字符串岩梳,并可以在其中自由的使用單引號和雙引號囊骤。
def name = 'Jerry'
println 'His name is $name'
println "His name is $name"
def members = """
'Terry'
"Larry" """
println "Team member is: " + members
輸出結(jié)果如下:
His name is $name
His name is Jerry
Team member is:
'Terry'
"Larry"
- 函數(shù)定義時返回值和函數(shù)參數(shù)也可以不指定類型。
- 未指定返回類型的函數(shù)定義必須使用def冀值。
- 可以不使用return xxx來設(shè)置函數(shù)返回值也物,函數(shù)最后一行代碼的執(zhí)行結(jié)果被設(shè)置成返回值,如果定義時指明了類型則必須返回正確的數(shù)據(jù)類型列疗。
- 函數(shù)調(diào)用可以不加括號她渴,構(gòu)造函數(shù)和無參函數(shù)除外应民。
def getValue(name) {// def is must
name + "'s value is 10"
}
value = getValue "Terry"
println value
結(jié)果如下:
Terry's value is 10
- Java原始數(shù)據(jù)類型在Groovy中為其對應(yīng)的包裝類型臂聋。
- 類不支持default作用域,且默認作用域為public坤次,如果需要public修飾符,則不用寫它创葡。
- 自動提供足夠使用的構(gòu)造函數(shù)(一個無參和帶一個Map參數(shù)的構(gòu)造函數(shù)浙踢,足夠)。
- Groovy動態(tài)的為每一個字段都會自動生成getter和setter灿渴,并且我們可以通過像訪問字段本身一樣調(diào)用getter和setter。
- Groovy所有的對象都有一個元類
metaClass
胰舆,我們可以通過metaClass屬性訪問該元類骚露。通過元類,可以為這個對象增加屬性和方法(在java中不可想象)缚窿! - 常用的集合類有
List
棘幸,Map
,Range
倦零。
class Person {
int id
String name
void setId(id) {
println "setId($id)"
this.id = id
}
String toString() {
"id=$id, name=$name"
}
}
merry = new Person()
merry.id = 1 // call merry.setId(1)
merry.setName "Merry"
println merry
println merry.getId().class
jerry = new Person(id: 2, name: "Jerry")
println jerry
運行結(jié)果如下:
setId(1)
id=1, name=Merry
class java.lang.Integer
setId(2)
id=2, name=Jerry
下面的例子展示通過metaClass向String對象中動態(tài)添加屬性和方法:
def msg = "Hello Groovy"
msg.metaClass.upper = { delegate.toUpperCase() }
msg.metaClass.lower = msg.toLowerCase()
println msg.upper()
println msg.lower
運行結(jié)果如下:
HELLO GROOVY
hello groovy
Groovy動態(tài)性
Groovy動態(tài)性示例如下:
class Dog {
def bark() {
println 'woof!'
}
def sit() {
println 'sitting!'
}
def jump() {
println 'boing!'
}
}
def dog = new Dog()
def acts = ['sit','jump','bark']
acts.each {
dog."${it}"()
}
運行結(jié)果如下:
sitting!
boing!
woof!
另一個動態(tài)性的例子:
class LightOn
{
def doing()
{
println 'Ligth turning on...'
}
}
class LightOff
{
def doing()
{
println 'Ligth turning off...'
}
}
class Switch
{
def control(action)
{
action."doing"()
}
}
def sh = new Switch()
sh.control(new LightOn())
運行結(jié)果如下:
Ligth turning on...
Groovy List
- List變量由
[]
定義误续,其元素可以是任意對象,底層對應(yīng)Java的List接口扫茅。 - 直接通過索引存取蹋嵌,而且不用擔心索引越界,當索引超過當前列表長度葫隙,List自動往該索引添加元素栽烂。
tmp = ["Jerry", 19 , true]
println "tmp[1] = " + tmp[1]
println tmp[5] == null
tmp[10] = 3.14
println "The size is " + tmp.size
println tmp
運行結(jié)果如下:
tmp[1] = 19
true
The size is 11
[Jerry, 19, true, null, null, null, null, null, null, null, 3.14]
Groovy Map
- Map變量由
[:]
定義,冒號左邊是key恋脚,右邊是value腺办,key必須是字符串,value可以是任何對象糟描。另外key可以用引號包起來怀喉,也可以不用。 - Map中元素的存取支持多種方法船响。
def score = "mark"
// id and name are treated as String
// "$score" is also correct
tmp = [id: 1, name: "Jerry", (score): 92]
println tmp
println "id: " + tmp.id
println "name: " + tmp["name"]
tmp.height = 183
println "height: " + tmp.height
運行結(jié)果如下:
[id:1, name:Jerry, mark:92]
id: 1
name: Jerry
height: 183
Groovy Range
- Range是Groovy對
List
的擴展躬拢,由begin值 + .. + end值定義。 - 不包含end值時使用<灿意。
tmp = 1..5
println tmp
println tmp.from
println tmp.to
tmpWithoutEnd = 1..<5
println tmpWithoutEnd.step(2)
println ""
println ""
println tmpWithoutEnd
tmp = 1.0f..5.0f
println tmp
運行結(jié)果如下:
[1, 2, 3, 4, 5]
1
5
[1, 3]
[1, 2, 3, 4]
[1.0, 2.0, 3.0, 4.0, 5.0]
Groovy文檔
- Groovy的API文檔位于http://www.groovy-lang.org/api.html估灿。
- 以Range為例,從getter方法我們知道Range有
from
和to
屬性缤剧,盡管文檔中并沒有說明馅袁。
T getFrom()
The lower value in the range.
T getTo()
The upper value in the range.
Groovy閉包
- 英文叫Closure,是Groovy中非常重要的一個數(shù)據(jù)類型或者說一種概念了荒辕。
- 閉包汗销,是一種數(shù)據(jù)類型犹褒,它代表了一段可執(zhí)行代碼或方法指針。定義格式為:
def 閉包對象 = { parameters -> code }
-
def 閉包對象 = { code }
// 參數(shù)個數(shù)少于2個時可以省略->符號 - `def 閉包對象 = reference.&methodName
- 閉包的調(diào)用方式:
閉包對象.call(參數(shù))
閉包對象(參數(shù))
- 閉包只有一個參數(shù)時弛针,可省略書寫參數(shù)叠骑,在閉包內(nèi)使用it變量引用參數(shù)。
- 閉包可以作為函數(shù)返回值削茁,函數(shù)參數(shù)宙枷,可以引用閉包外部定義的變量,可以實現(xiàn)接口方法茧跋。
def person = { id, name ->
println "id=$id, name=$name"
}
person(1, "Jerry")
person.call(2, "Larry")
person 3, "Merry"
Closure resume = { "resume" }
println resume()
def hello = "Hello"
def length = hello.&length
println "The length is " + length()
def greeting = { "$hello, $it" }
// equals: greeting = { it -> "Hello, $it" }
println greeting('Groovy')
def exit = { -> "exit" }
// exit(1) <= wrong!!
def members = ["Jerry", "Larry", "Merry"]
members.each {
println "Hello $it"
}
def welcome(name) {
return {
println "Welcome $name"
}
}
println welcome("Terry")
運行結(jié)果如下:
id=1, name=Jerry
id=2, name=Larry
id=3, name=Merry
resume
The length is 5
Hello, Groovy
Hello Jerry
Hello Larry
Hello Merry
closure$_welcome_closure6@73a1e9a9
如何確定閉包的參數(shù)慰丛?查看API文檔。
Groovy DSL
-
Command Chain
: 鏈式調(diào)用既可以省略圓括號瘾杭,又可以省略”.”號诅病。 - 閉包作為函數(shù)調(diào)用的最后一個參數(shù)時,可以拿到圓括號外面粥烁。
// equivalent to: turn(left).then(right)
turn left then right
// equivalent to: take(2.pills).of(chloroquinine).after(6.hours)
take 2.pills of chloroquinine after 6.hours
// equivalent to: paint(wall).with(red, green).and(yellow)
paint wall with red, green and yellow
// with named parameters too
// equivalent to: check(that: margarita).tastes(good)
check that: margarita tastes good
// with closures as parameters
// equivalent to: given({}).when({}).then({})
given { } when { } then { }
一個例子:
def name(name) {
println "name: $name"
return this
}
def age(age) {
println "age: $age"
return this
}
def action(String tips, Closure c) {
println "begin to $tips"
c()
println "end"
return this
}
name "Jerry" age 18
// name("Jerry").age(18)
name "Herry"
age 22
action("eat") {
println "eating..."
}
運行結(jié)果如下:
name: Jerry
age: 18
name: Herry
age: 22
begin to eat
eating...
end
Groovy腳本
Groovy腳本是什么贤笆?我們通過一個例子來看一下。
// variables.groovy
def x = 1 // or int x = 1
def printx() {
println x
}
printx() // failed
運行結(jié)果如下:
Caught: groovy.lang.MissingPropertyException: No such property: x for class: variables
groovy.lang.MissingPropertyException: No such property: x for class: variables
at variables.printx(variables.groovy:5)
at variables.run(variables.groovy:8)
為何會出現(xiàn)找不到屬性x
讨阻?我們來看看反編譯groovy運行時生成的.class
文件芥永。使用如下命令在-d
指定的目錄生成.class
文件,然后使用JD-GUI查看:
groovyc –d classes variables.groovy
可以看到:
- XXX.groovy被轉(zhuǎn)換成XXX類变勇,它從
Script
類派生恤左。 - 每一個腳本都會生成一個
static main
函數(shù)。這樣搀绣,當我們groovy XXX.groovy的時候飞袋,其實就是用調(diào)用虛擬機去執(zhí)行這個main
函數(shù)。 - 如果腳本定義了函數(shù)链患,則函數(shù)會被定義在XXX類中巧鸭。
- 腳本中的其他代碼都會放到
run
函數(shù)中。
所以變量x
是在是在run
函數(shù)中定義的局部變量麻捻,當然無法在printx()
函數(shù)的訪問纲仍。那要如何才能實現(xiàn)printx()
函數(shù)訪問變量x
呢?有兩種方式可以實現(xiàn)贸毕。
第一種方式:
x = 1 // replace def x = 1 or int x = 1
def printx() {
println x
}
printx()
對應(yīng)的.class
文件反編譯代碼:
另一種方式:
import groovy.transform.Field;
@Field x = 1 // <= def x = 1 or int x = 1
def printx() {
println x
}
printx()
對應(yīng)的.class
文件反編譯代碼:
Gradle介紹
Gradle被認為是Java世界構(gòu)建工具的一次飛躍郑叠,它提供:
- 一個非常靈活通用的構(gòu)建工具。
- 對多項目構(gòu)建提供強大支持明棍。
- 強大的依賴管理機制乡革。
- 完美支持已有的Maven和Ivy倉庫。
- 支持依賴傳遞管理。
- 腳本編寫基于Groovy沸版。
- 豐富的描述構(gòu)建的領(lǐng)域模型嘁傀。
更多Gradle特性概述,可以訪問Gradle概述视粮。
Why Groovy
Gradle官方網(wǎng)站上對為何選用Groovy來開發(fā)的原因描述如下:
We think the advantages of an internal DSL (based on a dynamic language) over XML are tremendous when used in build scripts. There are a couple of dynamic languages out there. Why Groovy? The answer lies in the context Gradle is operating in. Although Gradle is a general purpose build tool at its core, its main focus are Java projects. In such projects the team members will be very familiar with Java. We think a build should be as transparent as possible to all team members.
In that case, you might argue why we don't just use Java as the language for build scripts. We think this is a valid question. It would have the highest transparency for your team and the lowest learning curve, but because of the limitations of Java, such a build language would not be as nice, expressive and powerful as it could be. [1] Languages like Python, Groovy or Ruby do a much better job here. We have chosen Groovy as it offers by far the greatest transparency for Java people. Its base syntax is the same as Java's as well as its type system, its package structure and other things. Groovy provides much more on top of that, but with the common foundation of Java.
For Java developers with Python or Ruby knowledge or the desire to learn them, the above arguments don't apply. The Gradle design is well-suited for creating another build script engine in JRuby or Jython. It just doesn't have the highest priority for us at the moment. We happily support any community effort to create additional build script engines.
Gradle基本概念
Gradle腳本是配置腳本细办,腳本執(zhí)行時會配置特定的對象,這些對象被稱為腳本的delegate
對象蕾殴。腳本中可以使用delegate
對象的屬性和方法笑撞。所有的Gradle腳本實現(xiàn)了org.gradle.api.Script接口,所以腳本中可以直接使用Script接口定義的屬性和方法区宇,Script接口中找不到的屬性或方法將被轉(zhuǎn)交給delegate
對象娃殖。同時,Gradle腳本也是Groovy腳本议谷,同樣可以包含Groovy腳本允許的元素,方法堕虹、類定義等卧晓。
Gradle生命周期
Gradle執(zhí)行構(gòu)建時有它自己的生命周期,概括來說可以分為3個階段:
第一是初始化階段赴捞。初始化階段Gradle會創(chuàng)建一個Gradle對象逼裆、Settings對象和Root Project對象,然后在項目根目錄尋找并執(zhí)行settings.gradle
文件來配置Settings對象赦政,并生成項目的Project樹胜宇。
第二是配置階段。配置階段Gradle會執(zhí)行特定的構(gòu)建腳本恢着,默認是各Project目錄下名為build.gradle
的文件桐愉,以配置對應(yīng)的Project。配置階段結(jié)束時掰派,Gradle內(nèi)部會生成整個項目的有向無循環(huán)Task圖从诲。
第三是執(zhí)行階段。執(zhí)行階段Gradle依據(jù)命令行傳入的task
名字在Task圖中找出此task
的所有依賴鏈靡羡,并從各依賴鏈起點開始系洛,沿著依賴鏈依次執(zhí)行Task,最終得到編譯產(chǎn)物略步。
Gradle用戶手冊中關(guān)于Gradle生命周期的描述如下:
Gradle生命周期的例子如下:
// settings.gradle
println 'This is executed during the initialization phase.'
// build.gradle in root directory
println 'This is executed during the configuration phase.'
task configured {
println 'This is also executed during the configuration phase.'
}
task test {
doLast {
println 'This is executed during the execution phase.'
}
}
task testBoth {
doFirst {
println 'This is executed first during the execution phase.'
}
doLast {
println 'This is executed last during the execution phase.'
}
println 'This is executed during the configuration phase as well.'
}
執(zhí)行結(jié)果如下:
This is executed during the initialization phase.
This is executed during the configuration phase.
This is also executed during the configuration phase.
This is executed during the configuration phase as well.
Gradle生命周期Hook
Gradle提供了豐富的Hook機制以獲知Gradle生命周期各個階段各類事件的發(fā)生描扯。常用的Hook可以通過Settings對象,Project或Task對象來設(shè)置趟薄,設(shè)置方式包括配置閉包方式和設(shè)置監(jiān)聽器方式绽诚。
以項目評估結(jié)束事件為例說明:
// build.gradle in root directory
afterEvaluate {
println "Project $name has been evaluated."
}
gradle.afterProject {
println "Project $it.name is evaluated."
}
gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {
void afterEvaluate(Project project, ProjectState state) {
println "Project $project.name was evaluated."
}
void beforeEvaluate(Project project) {
}
})
執(zhí)行結(jié)果如下:
Project tutorial was evaluated.
Project tutorial is evaluated.
Project tutorial has been evaluated.
Gradle核心組件
Gradle的核心組件包括Gradle,Settings,Project憔购,Task宫峦,Dependency,Plugin等玫鸟,每個核心組件都對應(yīng)很多有用的屬性导绷、方法和腳本塊。
Gradle組件
Gradle組件代表了一次Gradle構(gòu)建屎飘,通過Gradle組件能夠獲韧浊(或設(shè)置)本次構(gòu)建的一些全局信息,包括gradleVersion钦购,taskGraph檐盟,所有用到的plugins及添加各種Hook等。
Settings組件
Settings實例與settings.gradle
文件存在一一對應(yīng)關(guān)系押桃,Gradle執(zhí)行時會使用settings.gradle
來配置對應(yīng)的Settings實例葵萎。通常,在settings.gradle
腳本中會通過include(String[])方法來添加對多項目的支持唱凯。Root Project
會在Settings對象被創(chuàng)建時自動添加羡忘。另外,Settings組件還支持動態(tài)屬性磕昼,除了對象接口本身的屬性卷雕,還包含如下可用的屬性:
- 與
setting.gradle
同級的gradle.properites
文件定義的屬性。 - 用戶Gradle目錄里
gradle.properties
定義的屬性票从。 - 通過命令行-P參數(shù)定義的屬性漫雕。
示例如下:
// gradle.properties in project root directory
componentized=true
// settings.gradle
if (componentized) {
include ':components'
}
執(zhí)行結(jié)果如下:
Project tutorial was evaluated.
Project tutorial is evaluated.
Project tutorial has been evaluated.
Project components was evaluated.
Project components is evaluated.
Project組件
Project組件是編譯腳本與Gradle交互的主API接口,通過Project接口能訪問Gradle所有功能峰鄙。Gradle運行時使用build.gradle
配置對應(yīng)的project對象浸间。一個Project本質(zhì)上一些列Task的集合,每一個Task執(zhí)行一定的任務(wù)(類編譯先馆,生成javadoc等)发框。Project配置通常包括倉庫,依賴煤墙,產(chǎn)物梅惯,分組配置,插件的管理仿野。所有Project將都將被加入到Project層次樹中铣减,Project全路徑是其在層次樹中的唯一標識。Project配置還可以引入插件脚作,插件可以使得Project配置更加模塊化葫哗,并可重用缔刹。Project組件還支持5大范圍的動態(tài)屬性和5大范圍的動態(tài)方法。
5大范圍動態(tài)屬性
5大范圍動態(tài)方法
Ext屬性示例:
// build.gradle in root directory
ext {
gradleVersion = "3.4"
isSnapshot = true
}
ext.javaVersion = "1.7"
task addProperty(dependsOn: clean) {
project.ext.prop3 = true
}
if (isSnapshot) {
println "GradleVersion: $gradleVersion"
println "JavaVersion: $javaVersion"
println "Prop3: ${prop3}"
}
// build.gradle in components directory
println "GradleVersion in components: $gradleVersion"
println "JavaVersion in components: ${rootProject.ext.javaVersion}"
執(zhí)行結(jié)果如下:
GradleVersion: 3.4
JavaVersion: 1.7
Prop3: true
GradleVersion in components: 3.4
JavaVersion in components: 1.7
依賴管理
Gradle的依賴管理主要包括2大塊:
- 解決依賴劣针。依賴指使得項目能夠正常編譯或運行的輸入組件校镐。
- 依賴配置:包括項目內(nèi)依賴和外部依賴,并以配置分組捺典。
- 倉庫配置:Gradle會在配置的倉庫地址查找外部依賴鸟廓。
- 發(fā)布產(chǎn)物。產(chǎn)物指項目編譯生成的或需要上傳到中心的倉庫的輸出產(chǎn)物襟己。
- 配置發(fā)布倉庫引谜。通常插件會定義好項目的產(chǎn)物,我們不必關(guān)心擎浴,但必須告訴Gradle將產(chǎn)物發(fā)布到何處员咽,MavenCentral,Ivy倉庫贮预,JCenter等贝室。
Gradle有6大類型依賴,如下圖仿吞,其中比較常用的包括External module dependency档玻,Project dependency,File dependency茫藏。
依賴管理示例:
// In this section you declare where to find the dependencies of your project
repositories {
jcenter()
jcenter {
url "http://jcenter.bintray.com/"
}
mavenCentral()
maven {
url "http://repo.company.com/maven2"
}
ivy {
url "../local-repo"
}
}
dependencies {
compile 'com.google.guava:guava:20.0'
compile project(':components')
compile fileTree(dir: 'libs', include: '*.jar')
testCompile group: 'junit', name: 'junit', version: '4.+'
}
Task組件
Gradle task represents some atomic piece of work which a build performs。Task可以使用task
關(guān)鍵字定義霹琼,也可以使用TaskContainer.create()來定義务傲。一個Task可以依賴于另一個Task,Gradle支持使用must run after
和should run after
直接控制2個Task的執(zhí)行順序枣申。預(yù)定義的Task可以被替換售葡。
另外Task還支持4大范圍動態(tài)屬性和通過Convention對象支持動態(tài)方法。
4大范圍動態(tài)屬性
Task使用示例:
// build.gradle in root project
task hello1 {
doLast {
println "Hello1 Task"
}
}
task hello2 << {
ext.prop2 = "prop2"
println "Hello2 Task"
}
hello2.dependsOn hello1
task(hello3, dependsOn: hello2) {
doFirst {
println "Prop2: ${hello2.ext.prop2}"
println "Hello3 Task"
}
}
tasks.create('hello4').dependsOn('hello3')
hello4.doLast {
println "Hello4 Task"
}
運行結(jié)果如下:
:hello1
Hello1 Task
:hello2
Hello2 Task
:hello3
Prop2: prop2
Hello3 Task
:hello4
Hello4 Task
Plugin組件
Gradle插件就是將很多可在多個不同項目或構(gòu)建中重用的編譯邏輯(屬性忠藤、方法和Task等)打包起來挟伙。可以使用不同的語言來實現(xiàn)插件模孩,如Groovy尖阔,Java,Scala榨咐,插件最終被編譯成字節(jié)碼介却。插件源碼可位于3類地方:
- Build script:插件自動被編譯并被include到
classpath
中,build script外不可用块茁。 - buildSrc project:
buildSrc
子項目自動被編譯并被include到classpath
中齿坷,整個項目可用桂肌,其他項目不可用。 - Standalone project:可以發(fā)布jar或發(fā)布到公共倉庫永淌,其他項目可用崎场。
Gradle Wrapper目錄結(jié)構(gòu)
Gradle Wrapper可以使得每個項目擁有各自的Gradle版本而不互相影響。當前項目中Gradle相關(guān)文件說明如下:
用戶主目錄下Gradle相關(guān)文件說明如下:
Android Plugin for Gradle
Android Plugin for Gradle就是通過Gradle插件機制方式實現(xiàn)Gradle在Android平臺的擴展遂蛀,詳細信息請參考Gradle Plugin User Guide和Android Gradle DSL Reference谭跨。
參考
- http://groovy-lang.org/
- https://docs.gradle.org/3.4.1/userguide/userguide.html
- https://docs.gradle.org/3.4.1/dsl/
- http://tools.android.com/
- https://github.com/google/android-gradle-dsl
- http://blog.csdn.net/suncaishen/article/details/6194706
- http://blog.csdn.net/kmyhy/article/details/4200563
- http://jijiaxin89.com/2015/08/29/gradle-use-note/
- https://developer.android.com/studio/build/gradle-tips.html
- http://www.infoq.com/cn/articles/android-in-depth-gradle