[TOC]
是什么舌菜?
在語法上是基于Groovy語言的(Groovy 是一種基于JVM的敏捷開發(fā)語言源梭,可以簡(jiǎn)單的理解為強(qiáng)類型語言java的弱類型版本)摔桦,在項(xiàng)目管理上是基于Ant和Maven概念的項(xiàng)目自動(dòng)化建構(gòu)工具调缨。
搭建Gradle運(yùn)行環(huán)境
- Gradle 運(yùn)行依賴JVM丧肴,也就是java運(yùn)行的環(huán)境。所以要安裝jdk和jre月弛,好像目前的Gradle的運(yùn)行環(huán)境要求jdk的版本在1.6以上肴盏,應(yīng)該的,現(xiàn)在jdk都到1.8了帽衙。
- 然后到Gradle官網(wǎng)現(xiàn)在Gradle的壓縮包菜皂。地址,這個(gè)頁面里面又兩種方式厉萝,一種手動(dòng)安裝恍飘,一種通過腳本安裝。我一般喜歡自己動(dòng)手谴垫,這樣將來清理起來比較方便常侣。
- 下載壓縮包后,解壓弹渔,然后配置環(huán)境變量,手動(dòng)安裝過jdk的人應(yīng)該都配置環(huán)境變量很熟了吧溯祸。每個(gè)平臺(tái)下配置環(huán)境變量的方式不一樣
MacOS 下配置肢专。在~/.bash_profile中添加如下代碼
#gradle 注意gradle-2.14.1是自己解壓的路徑
export GRADLE_HOME=${HOME}/gradle-2.14.1
PATH=${PATH}:${GRADLE_HOME}/bin
export PATH
保存后在終端輸入source ~/.bash_profile回車執(zhí)行讓剛剛的配置生效。然后命令行輸入gradle -v查看是否安裝成功焦辅。
$ gradle -v
------------------------------------------------------------
Gradle 2.14.1
------------------------------------------------------------
Build time: 2016-07-18 06:38:37 UTC
Revision: d9e2113d9fb05a5caabba61798bdb8dfdca83719
Groovy: 2.4.4
Ant: Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM: 1.8.0_111 (Oracle Corporation 25.111-b14)
OS: Mac OS X 10.12.2 x86_64
弄一個(gè)HelloWorld看看
創(chuàng)建一個(gè)test_gralde文件夾博杖。然后在文件夾里面創(chuàng)建一個(gè)build.gradle文件。注意文件名不要亂起筷登。在build.gradle中添加如下代碼:
task helloworld{
doLast{
println'Hello World!'
}
}
然后來運(yùn)行一下:
gradle helloworld
> Task :helloworld
Hello World!
BUILD SUCCESSFUL in 809ms
1 actionable task: 1 executed
我們分析一下執(zhí)行步驟剃根。build.gradle是Gradle默認(rèn)的構(gòu)建腳本文件,執(zhí)行Gradle命令的時(shí)候前方,會(huì)默認(rèn)加載當(dāng)前目錄下的build.gradle腳本文件狈醉,當(dāng)然你也可以通過 -b 參數(shù)指定想要加載執(zhí)行的文件。這只是個(gè)最簡(jiǎn)單的task例子惠险,后面詳細(xì)介紹task的常見定義苗傅。
這個(gè)構(gòu)建腳本定義一個(gè)任務(wù)(Task),任務(wù)名字叫helloworld班巩,并且給任務(wù)helloworld添加了一個(gè)動(dòng)作渣慕,官方名字是Action,閱讀Gradle源代碼你會(huì)到處見到它,其實(shí)他就是一段Groovy語言實(shí)現(xiàn)的閉包逊桦,doLast就意味著在Task執(zhí)行完畢之后要回調(diào)doLast的這部分閉包的代碼實(shí)現(xiàn)
執(zhí)行流程和基本術(shù)語
和Maven一樣眨猎,Gradle只是提供了構(gòu)建項(xiàng)目的一個(gè)框架,真正起作用的是Plugin强经。Gradle在默認(rèn)情況下為我們提供了許多常用的Plugin睡陪,其中包括有構(gòu)建Java項(xiàng)目的Plugin,還有Android等夕凝。與Maven不同的是宝穗,Gradle不提供內(nèi)建的項(xiàng)目生命周期管理,只是java Plugin向Project中添加了許多Task码秉,這些Task依次執(zhí)行逮矛,為我們營造了一種如同Maven般項(xiàng)目構(gòu)建周期。
Gradle是一種聲明式的構(gòu)建工具转砖。在執(zhí)行時(shí)须鼎,Gradle并不會(huì)一開始便順序執(zhí)行build.gradle文件中的內(nèi)容,而是分為兩個(gè)階段府蔗,第一個(gè)階段是配置階段晋控,然后才是實(shí)際的執(zhí)行階段。
配置階段姓赤,Gradle將讀取所有build.gradle文件的所有內(nèi)容來配置Project和Task等赡译,比如設(shè)置Project和Task的Property,處理Task之間的依賴關(guān)系等不铆。
看一個(gè)基本結(jié)構(gòu)的Android多Moudule(也就是gradle中的多Project Multi-Projects Build)的基本項(xiàng)目結(jié)構(gòu)蝌焚。
├── app #Android App目錄
│ ├── app.iml
│ ├── build #構(gòu)建輸出目錄
│ ├── build.gradle #構(gòu)建腳本
│ ├── libs #so相關(guān)庫
│ ├── proguard-rules.pro #proguard混淆配置
│ └── src #源代碼,資源等
├── module #Android 另外一個(gè)module目錄
│ ├── module.iml
│ ├── build #構(gòu)建輸出目錄
│ ├── build.gradle #構(gòu)建腳本
│ ├── libs #so相關(guān)庫
│ ├── proguard-rules.pro #proguard混淆配置
│ └── src #源代碼誓斥,資源等
├── build
│ └── intermediates
├── build.gradle #工程構(gòu)建文件
├── gradle
│ └── wrapper
├── gradle.properties #gradle的配置
├── gradlew #gradle wrapper linux shell腳本
├── gradlew.bat
├── LibSqlite.iml
├── local.properties #配置Androod SDK位置文件
└── settings.gradle #工程配置
上面的是完整的AndroidStudio中的項(xiàng)目結(jié)構(gòu)只洒,我們抽象成Gradle多個(gè)Project的樣子
├── app
│ ├── build.gradle #構(gòu)建腳本
├── module
│ ├── build.gradle #構(gòu)建腳本
├── build.gradle #工程構(gòu)建文件
├── gradle
│ └── wrapper #先不去管它
├── gradle.properties #gradle的配置
├── gradlew #gradle wrapper linux shell腳本
├── gradlew.bat
└── settings.gradle #工程配置
- Gradle為每個(gè)build.gradle都會(huì)創(chuàng)建一個(gè)相應(yīng)的Project領(lǐng)域?qū)ο螅诰帉慓radle腳本時(shí)劳坑,我們實(shí)際上是在操作諸如Project這樣的Gradle領(lǐng)域?qū)ο蠼銎汀T诙郟roject的項(xiàng)目中窍株,我們會(huì)操作多個(gè)Project領(lǐng)域?qū)ο笳獯Аradle提供了強(qiáng)大的多Project構(gòu)建支持穗酥。
- 要?jiǎng)?chuàng)建多Project的Gradle項(xiàng)目,我們首先需要在根(Root)Project中加入名為settings.gradle的配置文件蔑穴,該文件應(yīng)該包含各個(gè)子Project的名稱忠寻。Gradle中的Project可以簡(jiǎn)單的映射為AndroidStudio中的Module。
- 在最外層的build.gradle存和。一般干得活是:配置其他子Project的奕剃。比如為子Project添加一些屬性衷旅。
- 在項(xiàng)目根目錄下有個(gè)一個(gè)名為settings.gradle。這個(gè)文件很重要纵朋,名字必須是settings.gradle柿顶。它里邊用來告訴Gradle,這個(gè)multiprojects包含多少個(gè)子Project(可以理解為AndroidStudio中Module)操软。
讀懂Gradle配置語法
Gradle向我們提供了一整套DSL嘁锯,所以在很多時(shí)候我們寫的代碼似乎已經(jīng)脫離了groovy,但是在底層依然是執(zhí)行的groovy所以很多語法還是Groovy的語法規(guī)則聂薪。
看一個(gè)AndroidStudio中app下的build.gradle的配置
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "me.febsky.demo"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.1.0'
}
分析第一行apply plugin: 'com.android.application'
這句其實(shí)是Groovy語法糖家乘,像Ruby和Js都有這種語法糖,apply實(shí)際上是個(gè)方法藏澳,補(bǔ)上括號(hào)后的腳本:apply (plugin: 'com.android.application'),看起來還是有點(diǎn)別扭是不仁锯?還有個(gè)語法糖,如果方法參數(shù)是個(gè)map類型翔悠,那么方括號(hào)可以省略业崖,進(jìn)一步還原apply([ plugin: 'com.android.application']),不理解的可以去看下Groovy的map的寫法,和js一樣蓄愁。所以這行的意思是:apply其實(shí)是個(gè)方法双炕,接收一個(gè)Map類型的參數(shù)。
總結(jié)兩點(diǎn):1. 方法調(diào)用撮抓,圓括號(hào)可以省略 2. 如果方法參數(shù)是個(gè)Map妇斤,方括號(hào)可以省略。
Groovy語言的閉包語法
看上面的dependencies 這其實(shí)是個(gè)方法調(diào)用丹拯。調(diào)用了Project的dependencies方法趟济。只不過參數(shù)是個(gè)閉包,我們對(duì)其進(jìn)行還原一下:
#方法調(diào)用省略了()我們加上
dependencies ({
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.1.0'
})
Project,Task 咽笼,Action
Gradle的Project之間的依賴關(guān)系是基于Task的,而不是整個(gè)Project的戚炫。
Project:是Gradle最重要的一個(gè)領(lǐng)域?qū)ο蠼P蹋覀儗懙腷uild.gradle腳本的全部作用,其實(shí)就是配置一個(gè)Project實(shí)例双肤。在build.gradle腳本里施掏,我們可以隱式的操縱Project實(shí)例,比如茅糜,apply插件七芭、聲明依賴、定義Task等蔑赘,如上面build.gradle所示狸驳。apply预明、dependencies、task等實(shí)際上是Project的方法耙箍,參數(shù)是一個(gè)代碼塊撰糠。如果需要,也可以顯示的操縱Project實(shí)例辩昆,比如:project.ext.myProp = 'myValue'
Task:被組織成了一個(gè)有向無環(huán)圖(DAG)阅酪。Gradle中的Task要么是由不同的Plugin引入的,要么是我們自己在build.gradle文件中直接創(chuàng)建的汁针。Gradle保證Task按照依賴順序執(zhí)行术辐,并且每個(gè)Task最多只被執(zhí)行一次。
Gradle在默認(rèn)情況下為我們提供了幾個(gè)常用的Task施无,比如查看Project的Properties辉词、顯示當(dāng)前Project中定義的所有Task等》可以通過一下命令行查看Project中所有的Task:$ gradle tasks (具體log不再貼出來)较屿。可以看到卓练,Gradle默認(rèn)為我們提供了dependencies隘蝎、projects和properties等Task。dependencies用于顯示Project的依賴信息襟企,projects用于顯示所有Project嘱么,包括根Project和子Project,而properties則用于顯示一個(gè)Project所包含的所有Property顽悼。
**Tips: **查看Project中所有的Task: gradle properties
在上面的build.gradle中加入如下代碼:
task myTask {
doFirst {
println 'hello'
}
doLast {
println 'world'
}
}
這段代碼的含義:給Project添加一個(gè)名為“myTask”的任務(wù)
用一個(gè)閉包來配置這個(gè)任務(wù),Task提供了doFirst和doLast方法來給自己添加Action曼振。
其實(shí)build.gradle腳本的真正作用,就是配置一個(gè)Project實(shí)例蔚龙。在執(zhí)行build腳本之前冰评,Gradle會(huì)為我們準(zhǔn)備好一個(gè)Project實(shí)例,執(zhí)行完腳本之后木羹,Gradle會(huì)按照DAG依次執(zhí)行任務(wù)甲雅。
自定義Task的寫法
看下面代碼文件路徑~/Test/build.gradle:
#1
task helloWorld << {
println "Hello World"
}
#2 Test文件夾下建一個(gè)src目錄,建一個(gè)dst目錄坑填,src目錄下建立一個(gè)文件抛人,命名為test.txt
task copyFile(type: Copy){
from "src"
into "dst"
}
第一個(gè)這里的helloWorld是一個(gè)DefaultTask類型的對(duì)象,這也是定義一個(gè)Task時(shí)的默認(rèn)類型脐瑰,當(dāng)然我們也可以顯式地聲明Task的類型妖枚,甚至可以自定義一個(gè)Task類型。
第二個(gè)代碼中(type:Copy)就是“顯式地聲明Task的類型”苍在,執(zhí)行g(shù)radle copyFile test.txt也跑到dst中去了绝页。
如果task聲明在根Project的build.gradle中的allprojects()方法中荠商,那么這個(gè)Task會(huì)應(yīng)用于所有的Project。
task的依賴關(guān)系
Gradle不提供內(nèi)建的項(xiàng)目生命周期管理抒寂,只是java Plugin向Project中添加了許多Task结啼,這些Task依次執(zhí)行,為我們營造了一種如同Maven般項(xiàng)目構(gòu)建周期屈芜。那么這些task是如何依次執(zhí)行的這就用到聲明的依賴關(guān)系taskA.dependsOn taskB看下面代碼:
task taskA << {
println 'this is taskA from project 1'
}
task taskB << {
println 'this is taskB from project 1'
}
taskA.dependsOn taskB
然后我們?cè)诿钚羞\(yùn)行:
$ gradle taskA
運(yùn)行結(jié)果會(huì)先執(zhí)行taskB的打印郊愧,然后執(zhí)行taskA的打印
如果是Muliti-Project的模式,依賴關(guān)系要帶著所屬的Project井佑,如taskA.dependsOn ':other-project:taskC' 其中taskC位于和taskA不同的Project中属铁,相對(duì)于AndroidStudio來說,就是位于不同的Module下的build.gradle中躬翁,而other-project為Module名字焦蘑。
自定義Plugin的寫法
apply plugin: DateAndTimePlugin
dateAndTime {
timeFormat = 'HH:mm:ss.SSS'
dateFormat = 'MM/dd/yyyy'
}
class DateAndTimePlugin implements Plugin<Project> {
//該接口定義了一個(gè)apply()方法,在該方法中盒发,我們可以操作Project例嘱,
//比如向其中加入Task,定義額外的Property等宁舰。
void apply(Project project) {
project.extensions.create("dateAndTime", DateAndTimePluginExtension)
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)
}
}
}
//每個(gè)Gradle的Project都維護(hù)了一個(gè)ExtenionContainer拼卵,
//我們可以通過project.extentions進(jìn)行訪問
//比如讀取額外的Property和定義額外的Property等。
//向Project中定義了一個(gè)名為dateAndTime的extension
//并向其中加入了2個(gè)Property蛮艰,分別為timeFormat和dateFormat
class DateAndTimePluginExtension {
String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"
String dateFormat = "yyyy-MM-dd"
}
Gradle Wrapper
Wrapper腋腮,顧名思義,其實(shí)就是對(duì)Gradle的一層包裝壤蚜,便于在團(tuán)隊(duì)開發(fā)過程中統(tǒng)一Gradle構(gòu)建的版本即寡,然后提交到git上,然后別人可以下載下來袜刷,這樣大家都可以使用統(tǒng)一的Gradle版本進(jìn)行構(gòu)建聪富,避免因?yàn)镚radle版本不統(tǒng)一帶來的不必要的問題。(所以要明白這個(gè)東西可以沒有著蟹,有了只是為了統(tǒng)一管理善涨,更加方便)
生成wrapper
gradle 內(nèi)置了生成wrapper的task,我們可以命令行下執(zhí)行:
$ gradle wrapper
生成后的目錄結(jié)構(gòu)如下(用過AndroidStudio的很熟悉了):
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
- gradlew和gradlew.bat分別是Linux和Window下的可執(zhí)行腳本草则,他們的用法和gradle原生命令是一樣的,gradle怎么用蟹漓,他們也就可以怎么用炕横。在MacOS下運(yùn)行$ ./gradlew myTask
- gradle-wrapper.jar是具體業(yè)務(wù)邏輯實(shí)現(xiàn)的jar包,gradlew最終還是使用java執(zhí)行的這個(gè)jar包來執(zhí)行相關(guān)gradle操作葡粒。
- gradle-wrapper.properties是配置文件份殿,用于配置使用哪個(gè)版本的gradle等
詳細(xì)的看下gradle-wrapper.properties內(nèi)容
#Sat Jan 21 14:02:40 CST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-bin.zip
從上面內(nèi)容和文件的名稱都可以看出膜钓,這就是個(gè)java的配置文件,上面看到的是自動(dòng)生成的,我們也可以手動(dòng)修改卿嘲。然后看下各個(gè)字段的含義:
- distributionBase 下載的gradle壓縮包解壓后存儲(chǔ)的主目錄
- distributionPath 相對(duì)于distributionBase的解壓后的gradle壓縮包的路徑
- zipStoreBase 同distributionBase颂斜,只不過是存放zip壓縮包的
- zipStorePath 同distributionPath,只不過是存放zip壓縮包的
- distributionUrl gradle發(fā)行版壓縮包的下載地址拾枣,也就是你現(xiàn)在這個(gè)項(xiàng)目將要依賴的gradle的版本沃疮。
refer to:
深入理解Android之Gradle