百度百科
Gradle是一個(gè)基于Apache Ant和Apache Maven概念的項(xiàng)目自動(dòng)化構(gòu)建工具到踏。它使用一種基于Groovy的特定領(lǐng)域語言(DSL)來聲明項(xiàng)目設(shè)置,拋棄了基于XML的各種繁瑣配置辐怕。主要用于Java語言。
Groovy對自己的定義就是:Groovy是在 java平臺上的贡茅、 具有像Python秘蛇, Ruby 和 Smalltalk 語言特性的靈活動(dòng)態(tài)語言, Groovy保證了這些特性像 Java語法一樣被 Java開發(fā)者使用顶考。Groovy 是一門JVM 語言,也就是妖泄,Groovy 的代碼最終也會(huì)被編譯成JVM 字節(jié)碼驹沿,交給虛擬機(jī)去執(zhí)行。
Groovy 基本語法
變量
在groovy 中蹈胡,沒有固定的類型渊季,變量可以通過def
關(guān)鍵字引用,比如:
def name = 'Andy'
我們通過單引號引用一串字符串的時(shí)候這個(gè)字符串只是單純的字符串罚渐,但是如果使用雙引號引用却汉,在字符串里面還支持插值操作,
def name = 'Andy'
def greeting = "Hello, $name!"
方法
類似 python 一樣荷并,通過def
關(guān)鍵字定義一個(gè)方法合砂。方法如果不指定返回值,默認(rèn)返回最后一行代碼的值源织。
def square(def num) {
num * num
}
square 4
類
Groovy 也是通過Groovy 定義一個(gè)類:
class MyGroovyClass {
String greeting
String getGreeting() {
return 'Hello!'
}
}
在Groovy 中翩伪,默認(rèn)所有的類和方法都是pulic的,所有類的字段都是private的谈息;
和java一樣缘屹,我們通過new關(guān)鍵字得到類的實(shí)例,使用def接受對象的引用:def instance = new MyGroovyClass()
而且在類中聲明的字段都默認(rèn)會(huì)生成對應(yīng)的setter,getter方法侠仇。所以上面的代碼我們可以直接調(diào)用instance.setGreeting 'Hello, Groovy!'轻姿,注意,groovy 的方法調(diào)用是可以沒有括號的逻炊,而且也不需要分號結(jié)尾互亮。除此之外,我們甚至也可以直接調(diào)用嗅骄;
我們可以直接通過instance.greeting這樣的方式拿到字段值胳挎,但其實(shí)這也會(huì)通過其get方法,而且不是直接拿到這個(gè)值溺森。
閉包
在Groovy 中有一個(gè)閉包的概念慕爬。閉包可以理解為就是 Java 中的匿名內(nèi)部類窑眯。閉包支持類似lamda形式的語法調(diào)用。如下:
def square = { num ->
num * num
}
square 8
如果只有一個(gè)參數(shù)医窿,我們甚至可以省略這個(gè)參數(shù)磅甩,默認(rèn)使用it作為參數(shù),最后代碼是這樣的:
Closure square = {
it * it
}
square 16
安裝
下載官網(wǎng)的壓縮包姥卢,下載地址https://guides.gradle.org
解壓卷要,
配置本地的環(huán)境變量
驗(yàn)證
第一次輸入gradle -v會(huì)在本地用戶文件夾生成.gradle的文件夾,是Gradle的本地倉庫
Eclipse安裝Gradle
現(xiàn)在新版本的Eclipse/oxygen已經(jīng)集成了Geadle
創(chuàng)建一個(gè)新項(xiàng)目独榴,觀察是否有Gradle僧叉,若有就注明,已經(jīng)集成棺榔,不需要下載插件了瓶堕。
若無,需要下載Buildship插件
help---》 Eclipse Markeplace....
安裝完成后重啟Eclipse症歇,觀察是否出現(xiàn)Gradle項(xiàng)目郎笆。
Eclipse創(chuàng)建Gradle項(xiàng)目
Gradle的編譯周期
在解析 Gradle 的編譯過程之前我們需要理解在 Gradle 中非常重要的兩個(gè)對象。Project和Task忘晤。
每個(gè)項(xiàng)目的編譯至少有一個(gè) Project,一個(gè) build.gradle
就代表一個(gè)project
,每個(gè)project里面包含了多個(gè)task,task 里面又包含很多action宛蚓,action是一個(gè)代碼塊,里面包含了需要被執(zhí)行的代碼设塔。
在編譯過程中凄吏, Gradle 會(huì)根據(jù) build 相關(guān)文件,聚合所有的project和task壹置,執(zhí)行task 中的 action竞思。因?yàn)?build.gradle文件中的task非常多,先執(zhí)行哪個(gè)后執(zhí)行那個(gè)需要一種邏輯來保證钞护。這種邏輯就是依賴邏輯盖喷,幾乎所有的Task 都需要依賴其他 task 來執(zhí)行,沒有被依賴的task 會(huì)首先被執(zhí)行难咕。所以到最后所有的 Task 會(huì)構(gòu)成一個(gè) 有向無環(huán)圖(DAG Directed Acyclic Graph)的數(shù)據(jù)結(jié)構(gòu)课梳。
編譯過程分為三個(gè)階段:
初始化階段:創(chuàng)建 Project 對象,如果有多個(gè)build.gradle余佃,也會(huì)創(chuàng)建多個(gè)project.
配置階段:在這個(gè)階段暮刃,會(huì)執(zhí)行所有的編譯腳本,同時(shí)還會(huì)創(chuàng)建project的所有的task爆土,為后一個(gè)階段做準(zhǔn)備椭懊。
執(zhí)行階段:在這個(gè)階段,gradle 會(huì)根據(jù)傳入的參數(shù)決定如何執(zhí)行這些task,真正action的執(zhí)行代碼就在這里.
Gradle的目錄
src文件夾
src/main/java
和src/test/java
是和一般的Java項(xiàng)目一樣步势,存放源碼配置的位置氧猬,方便調(diào)試背犯,和``·src```是一樣的。
gradle文件夾
存放gradle的版本里面有一個(gè) wrapper文件夾
gradlw wrapper 包含一些腳本文件和針對不同系統(tǒng)下面的運(yùn)行文件盅抚。wrapper 有版本區(qū)分漠魏,但是并不需要手動(dòng)去下載,當(dāng)運(yùn)行腳本的時(shí)候妄均,如果本地沒有會(huì)自動(dòng)下載對應(yīng)版本文件柱锹。
build.gradle
配置整個(gè)projeck的項(xiàng)目的構(gòu)建的依賴
apply plugin: 'java-library' 聲明:我們構(gòu)建的是一個(gè)java的library
setting.gradle
這個(gè) setting 文件定義了哪些module 應(yīng)該被加入到編譯過程,對于單個(gè)module 的項(xiàng)目可以不用需要這個(gè)文件丰包,但是對于 multimodule 的項(xiàng)目就需要這個(gè)文件禁熏,否則gradle 不知道要加載哪些項(xiàng)目。這個(gè)文件的代碼在初始化階段就會(huì)被執(zhí)行邑彪。
gradlew和gradlew.bat
gradkew的配置和運(yùn)行文件
Gradle 的 Task
Task的介紹
一個(gè)Task代表一個(gè)構(gòu)建工作的原子操作匹层,例如編譯calsses或者生成javadoc。
Gradle中锌蓄,每一個(gè)待編譯的工程都叫一個(gè)Project。每一個(gè)Project在構(gòu)建的時(shí)候都包含一系列的Task撑柔。比如一個(gè)Android APK的編譯可能包含:Java源碼編譯Task瘸爽、資源編譯Task、JNI編譯Task铅忿、lint檢查Task剪决、打包生成APK的Task、簽名Task等檀训。插件本身就是包含了若干Task的柑潦。
- 一個(gè)Task包含若干Action。所以峻凫,Task有doFirst和doLast兩個(gè)函數(shù)渗鬼,用于添加需要最先執(zhí)行的Action和需要和需要最后執(zhí)行的Action。
Action就是一個(gè)閉包荧琼。閉包譬胎,英文叫Closure,是Groovy中非常重要的一個(gè)數(shù)據(jù)類型或者說一種概念命锄。
- Task創(chuàng)建的時(shí)候可以通過 type: SomeType 指定Type堰乔,Type其實(shí)就是告訴Gradle,這個(gè)新建的Task對象會(huì)從哪個(gè)基類Task派生脐恩。比如镐侯,Gradle本身提供了一些通用的Task,最常見的有Copy 任務(wù)驶冒。Copy是Gradle中的一個(gè)類苟翻。當(dāng)我們:task myTask(type:Copy)的時(shí)候,創(chuàng)建的Task就是一個(gè)Copy Task怜俐。
- 當(dāng)我們使用 taskmyTask{ xxx}的時(shí)候汞扎,花括號就是一個(gè)closure景鼠。
- 當(dāng)我們使用taskmyTask << {xxx}的時(shí)候鲫构,我們創(chuàng)建了一個(gè)Task對象结笨,同時(shí)把closure做為一個(gè)action加到這個(gè)Task的action隊(duì)列中,并且告訴它“最后才執(zhí)行這個(gè)closure”
task myTask
task myTask { configure closure } // closure是一個(gè)閉包
task myType << { task action } // <<符號是doLast的縮寫
task myTask(type: SomeType) // SomeType可以指定任務(wù)類型,Gradle本身提供有Copy、Delete、Sync等
task myTask(type: SomeType) { configure closure }
Task的API文檔:
https://docs.gradle.org/current/dsl/org.gradle.api.Task.html
自定義Task
在Gradle中,我們有3種方法可以自定義Task时迫。
(1)在build.gradle文件中定義
Gradle使用的是Groovy代碼纸肉,所以在build.gradle文件中姐刁,我們便可以定義Task類谬俄。
// 需要繼承自DefaultTask
class HelloWorldTask extends DefaultTask {
// @Optional 表示在配置該Task時(shí)宿礁,message是可選的控汉。
@Optional
String message = 'I am kaku'
// @TaskAction 表示該Task要執(zhí)行的動(dòng)作,即在調(diào)用該Task時(shí),hello()方法將被執(zhí)行
@TaskAction
def hello(){
println "hello world $message"
}
}
// hello使用了默認(rèn)的message值
task hello(type:HelloWorldTask)
// 重新設(shè)置了message的值
task helloOne(type:HelloWorldTask){
message ="I am a android developer"
}
(2)在當(dāng)前工程中定義
當(dāng)項(xiàng)目中自定義Task類型比較多時(shí)沐旨,可以將自定義Task寫在buildSrc項(xiàng)目中。
具體做法為:在項(xiàng)目的根目錄下新建一個(gè)名為buildSrc文件夾,然后依次新建子目錄src/main/groovy,然后可以建自己的包名烟央,這里以demo.gradle.task為例钞艇,依次新建子目錄demo/gradle/task,然后在buildSrc根目錄下新建build.gradle文件,里面寫入:
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
接著在demo.gradle.task包下移怯,創(chuàng)建HelloWorldTask.groovy文件香璃,將(1)中的HelloWorldTask部分代碼粘貼過來
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
class HelloWorldTask extends DefaultTask {
@Optional
String message = 'I am kaku'
@TaskAction
def hello() {
println "hello world $message"
}
}
最終目錄結(jié)構(gòu)如下:
(3)在單獨(dú)的項(xiàng)目中定義
當(dāng)自定義的Task需要能夠提供給其他項(xiàng)目中使用時(shí),可以通過聲明依賴的方式引入Task舟误。
具體做法為: 創(chuàng)建一個(gè)項(xiàng)目葡秒,將(2)中的buildSrc目錄下的內(nèi)容copy到新建項(xiàng)目中,然后將該項(xiàng)目生成的jar文件上傳到repository中嵌溢。
build.gradle如下:
apply plugin: 'groovy'
apply plugin: 'maven'
version = '1.0'
group = 'skr'
archivesBaseName = 'hellotask'
repositories.mavenCentral()
dependencies {
compile gradleApi()
compile localGroovy()
}
uploadArchives {
repositories.mavenDeployer {
repository(url: 'file:../lib')
}
}
執(zhí)行 gradlew uploadArchives 眯牧,所生成的jar文件將被上傳到上級目錄的lib(../lib)文件夾中
在使用該HelloWorldTask時(shí),客戶端的build.gradle文件需要做以下配置:
buildscript {
repositories {
maven {
url 'file:../lib'
}
}
dependencies {
classpath group: 'skr', name: 'hellotask', version: '1.0'
}
}
task hello(type: HelloWorldTask)
自定義Plugin
與自定義Task相似赖草,也是3種定義方式学少,只是代碼不一樣:
apply plugin: DateAndTimePlugin
dateAndTime {
timeFormat = 'HH:mm:ss.SSS'
dateFormat = 'MM/dd/yyyy'
}
// 每一個(gè)自定義的Plugin都需要實(shí)現(xiàn)Plugin<T>接口
class DateAndTimePlugin implements Plugin<Project> {
//該接口定義了一個(gè)apply()方法,在該方法中秧骑,我們可以操作Project版确,
//比如向其中加入Task,定義額外的Property等乎折。
void apply(Project project) {
project.extensions.create("dateAndTime", DateAndTimePluginExtension)
//每個(gè)Gradle的Project都維護(hù)了一個(gè)ExtenionContainer绒疗,
//我們可以通過project.extentions進(jìn)行訪問
//比如讀取額外的Property和定義額外的Property等。
project.task('showTime') << {
println "Current time is " + new Date().format(project.dateAndTime.timeFormat)
}
project.tasks.create('showDate') << {
println "Current date is " + new Date().format(project.dateAndTime.dateFormat)
}
}
}
//向Project中定義了一個(gè)名為dateAndTime的extension
//并向其中加入了2個(gè)Property骂澄,分別為timeFormat和dateFormat
class DateAndTimePluginExtension {
String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"
String dateFormat = "yyyy-MM-dd"
}