Gradle是基與Groovy的腳本配置的構筑工具,用與構筑Java及Android應用.
Gradle
Gradle是個構筑工具,本身是一個框架,提供了一系列的API,使用中則是執行.Gradle腳本文件,借助與其中的配置來進行構筑.
簡單的來說,.Gradle文件就是使用Groovy語言配置及調用Gradle的API的腳本
對與Gradle而言,一個Project是一個執行單元,一個Project對應了一個build.gradle腳本.一個App或一個Library都算是一個Project.
GradleWrapper
一個使用Gradle的項目,如果在沒有安裝Gradle或對應的版本不對的環境時,需要手動去配置環境.為了避免這個情況,在項目中自帶了Gradle的運行環境配置.
就是gradle\wrapper
目錄.其配置文件為gradle-wrapper.properties
.
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
項目中gradlew
或gradlew.bat
就是不同平臺下的gradle命令行.他使用的是指定的gradle環境.
1 首先會在指定的路徑下wrapper/dists下查找是否有對應版本的環境
2 如果沒有則會根據gradle-wrapper.properties
中的distributionUrl
下載對應的版本.
路徑優先級如下
- GRADLE_USER_HOME
- GRADLE_HOME
- 如果使用AndroidStudio會在OffLine Work指定的目錄
- User/.gradle
如上面的distributionUrl
,實際上就是下載gradle-3.3-all.zip
到指定路徑的wrapper/dists/gradle-3.3-all/亂碼/目錄下.如C:\Users\花京院\.gradle\wrapper\dists\gradle-3.3-all\55gk2rcmfc6p2dg9u9ohc3hw9
這個亂碼目錄自動生成的.下載時會生成.lck文件.下載完成時會生成.ok文件.
所以,如果不能翻墻或下載很慢時,可以停止下載,從下載速度好的鏡象網址中下載對應的版本放在該目錄下,并新建一個空txt文件,改名成.ok文件.如gradle-3.3-all.zip.ok
為了更好的使用Gradle,可以注意兩點
- 配置GRADLE_USER_HOME路徑
- 把
gradle-wrapper.properties
中的distributionUrl
地址改成鏡象的地址.
如https\://services.gradle.org/distributions/gradle-3.3-all.zip
改為http\://mirrors.flysnow.org/gradle/gradle-3.3-all.zip
一個不錯的鏡象網址
Project
Project
是一個接口,是Gradle的核心.通過Project
來訪問所有的Gradle的功能.Project
和build.gradle
是一一對應的關系.
一個項目必須有一個builde.gradle
.它對應的Project
叫做rootProjcet
.這個Project
對其它Project
提供基礎性及公共性的配置.它會創建一個Settings
的實例并根據setting.gradle
來配置這個實例.
-
Project
里含有一個容器TaskContainer
接口.用與創建,存取及管理所有的Task
. -
Project
里含有一個容器ConfigurationContainer
接口,來管理對應的項目配置 -
Project
里含有一個DependencyHandler
接口用與管理項目的依賴 -
Project
里含有一個RepositoryHandler
接口用來注冊和管理依賴所需的Repository
.
屬性property
Project
可以聲明很多屬性,沒有類型限制.有多種來源
-
Project
自身帶的屬性 - 額外屬性(
extra properties
),每個Project
都持有一個Map用來存放額外屬性.這個Map的聲明為ext.所以可用ext.屬性名
來訪問或用ext.屬性名=xxx
來賦值 - 通過插件添加到
extensions
的extension
,可以做為同名的只讀屬性 - 通過插件添加
convention
屬性,插件可以通過Project
的convention
對象添加屬性和方法 - 父
Project
的屬性
Project的動態方法
Project
中的方法有多個來源.
-
Project
自身的方法 -
builde.gradle
中聲明的方法 - 通過插件提供的額外方法
- 把Task當成方法,通過把Task名當成方法名來調用Task中的Action或閉包.
- 父
Project
的方法,頂層直到rootProject
- 閉包形式的屬性(
property
).可以把屬性當成方法調用.
TASK
task
在gradle里可以看成是一個執行任務.除了自定義的task,其它的task都是通過pluging
引入的.像編譯,打包,安裝這些都是定義好的task.
windows調用task的方法是gradle或gradlew task名 ,在linux或mac下是./gradle或gradlew task名
task
在Gradle中是個接口,其默認實現類為DefaultTask
.其它的實現類都是繼承與此.
創建Task
可以通過TaskContainer
對象的create方法來創建Task.但通常是使用task關鍵字來創建Task
使用task
關鍵字創建task實際上是使用了Project
對象的task
方法來創建的.共有四個重載方法.調用此方法會創建task
并保存在其中的TaskContainer
里.方法如下
Task task(String name)
Task task(String name, Closure configureClosure) //Cloure就是閉包
Task task(Map<String,?> args,String name)
Task task(Map<String,?> args,String name,Closure configureClosure)
//例子
task hello
task hello {xxx} //groovy語法
task hello(type:jar)
task hello(type:jar) {xxx} //gradle的DSL
doFirst和doLast
task
執行任務是基與Action
接口的.基內部維護了一個List
,通過List<Action<? super Task>> getActions()
方法可獲取這個容器.在執行Task
時就是遍歷這個容器,調用每個Action
為Task
添加Action
的方法就是doFirst
和doLast
.添加至List
的頭和尾.這說明該List是LinkedList
參數有兩種,一種為Action<? extend Task>
,另一種為閉包.通常使用閉包這種簡便的方式
在gradle提供的DSL中對doLast提供了一個簡化寫法
task hello <<{
xxx
}
//等同與
task hello {
doLast {
xxx
}
}
讀懂Gradle腳本
如上說的,Gradle腳本是基與Gradle的API.所以腳本中基本上都是在調用Gradle的API.
因為腳本使用的是Groovy語言,那么明白Groovy對了解腳本有很大的幫助.這里只說幾個要點
- Groovy是基與Java的.可以看成是Java言的簡寫形式.也就是說可以把Groovy完全替換成Java代碼.
- 在Groovy中所有的都是對象,基本數據類型對應的是其對象類,容器使用的是
List
和Map
,容器的聲明是[]
,每個元素以,
分隔. - 在groovy中
Map
的定義是[key:value],key必須是字符串,如果不用''
或""
包含則會自動轉成對應的字符串,如果key想使用變量引用,則需要加上()
,當方法參數時如果只有一個鍵值對時可以省略[ ]
def map=[k:`v`]
//這里key是"k",value是"v"
def key="k"
def map=[key:'value']
//這里key是"key"而不是k
def map=[(key):"value"]
//這里的key是'k'
- Groovy中不需要聲明類型,但是所有的參數都是有類型的.其頂層是Object.聲明一個變量或方法都用def關鍵字
- Groovy中有閉包,閉包是被{}包裹的可執行代碼.可以看成是一個
Runable
,不過可以傳遞參數,如果不設置參數,則有一個默認的參數,在閉包中用it
表示.類型會自動推導 - Groovy里方法調用是可以鏈式調用的.方法名+空格+參數表示一個方法調用.省略了括號,在鏈式調用中方法名+()表示調用空參的方法.如果鏈式調用為奇數,最后一個參數視為成員變量,如
from a into b from(a).into(b); from a,b init() name from(a,b).init().name; from {} into {} name from({}).into({}).getName();
- Groovy里頂層方法調用可以省略括號,參數間以
,
分隔.但參數是方法調用的話是不能省略括號的.from(a)//可以寫成from a from(a,get(b)) //不能寫成 from a,get b,必須寫成from a,get(b)
- 方法參數中含有閉包的可以把閉包放到括號外,并省略括號及
,
from(a,{}) from a {}
閉包
閉包是一個被{}包含的可執行代碼.在Java中是沒有閉包存在的,因為Groovy最終會轉化為Java代碼.實際上閉包會被轉化成對應的對象.原理類似與Java8的Lamda.
比如說在對容器進行遍歷時調用foreach
方法.就可以傳入一個閉包對容器的元素進行操作.這個閉包是沒有傳遞參數的.在閉包中這個元素可以用it來調用.可以理解為創建了一個Runable,含有一個成員變量it.這個變量就是遍歷時對應的元素
調用Gradle的方法,傳入一個閉包.可以簡單的理解為需要傳入一個指定的繼承Runable的對象或者說是匿名內部類,它的run()方法由自己來實現.這在Gradle里叫委托.
在Gradle里需要傳入閉包的方法都是委托指定的對象.所以在閉包中可以直接調用該對象的方法.具體的閉包對應的對象及其可調用的方法就需要查看Gradle的API文檔.
解析幾個常見的腳本
apply plugin: 'com.android.library'
apply from: 'config.gradle'
實際上都是在調用Gradle的API,apply(Map map)
方法,在方法調用時可以通過空格來省略方法的括號.實際可以寫成
apply([plugin:'com.android.library'])
上面的代碼也可以合起來寫
apply [plugin: 'com.android.library',from:'config.gradle']
android {
compileSdkVersion 24
buildToolsVersion '24.0.1'
defaultConfig {
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName '1.0'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
- 這里首先調用了
android
方法,參數是個閉包A.這里是創建了一個Android
對象.閉包內的內容為對其的配置 - A中調用
compileSdkVersion
,buildToolsVersion
,defaultConfig
及buildTypes
方法.前兩個方法為Android
對象的方法,后兩個方法的參數為閉包B和C - B中調用了四個方法,C中調用了閉包D,在D中調用了
release
方法,參數為閉包E - E中調用了
minifyEnabled
及proguardFiles
方法 -
proguardFiles
方法的參數為proguard-rules.pro
字符串及方法getDefaultProguardFile('progurad-android.txt')
方法的返回值
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:support-v4:19.1.0'
}
- 這里調用了
dependencies
方法,閉包中為其配置 -
compile
為添加依賴的方法. -
fileTree(include: ['*.jar'], dir: 'libs')
做為compile
方法的參數.fileTree
是個方法,參數為一個List
用來表示添加的類型和一個Map
用來表示文件路徑, -
'com.android.support:support-v4:19.1.0'
為依賴的名稱.構建時會通過RepositoryHandler
在注冊的Repository
里查找.
task clean(type: Delete) {
delete rootProject.buildDir
}
- 聲明了一個
clean
的task
. -
task
的類型為Delete
,所以在閉包中可以使用對應的方法delete
- 刪除的路徑為
rootProject.buildDir
變量保存的路徑