什么是Gradle
Gradle 是新一代的自動(dòng)化構(gòu)建工具命迈,它是一個(gè)獨(dú)立的項(xiàng)目,跟 AS、Android 無(wú)關(guān),類似 Ant嘉栓、Maven這類構(gòu)建工具都是基于XML來(lái)進(jìn)行描述的,很臃腫科贬,而 Gradle 采用的是一種叫做 Groovy 的語(yǔ)言衷敌,語(yǔ)法跟 Java 語(yǔ)法很像,但是是一種動(dòng)態(tài)語(yǔ)言蛉腌,而且在 Java 基礎(chǔ)上做了不少改進(jìn)官份,用起來(lái)更加簡(jiǎn)潔只厘、靈活,而且 Gradle 完全兼容 Maven舅巷、Ivy羔味,這點(diǎn)基本上宣布了 Maven、Ivy 可以被拋棄了钠右,Gradle 的推出主要以 Java 應(yīng)用為主赋元,當(dāng)然目前還支持 Android、C飒房、C++搁凸。
Gradle是一種構(gòu)建工具,它通過(guò)編寫(xiě)一個(gè)名為build.gradle的腳本文件對(duì)項(xiàng)目進(jìn)行設(shè)置狠毯,再根據(jù)這個(gè)腳本對(duì)項(xiàng)目進(jìn)行構(gòu)建(復(fù)雜的項(xiàng)目也有其他文件)护糖,幫你管理項(xiàng)目中的差異、依賴嚼松、編譯嫡良、打包、部署......你可以定義滿足自己需要的構(gòu)建邏輯献酗,寫(xiě)入到build.gradle中供日后復(fù)用寝受。
Gradle 腳本本質(zhì)上就是Groovy腳本,只不過(guò)高度利用了Groovy的語(yǔ)法糖罕偎,例如省略方法參數(shù)括號(hào)和省略句尾分號(hào)等很澄,讓代碼看起來(lái)像DSL(特定領(lǐng)域語(yǔ)言)。Groovy語(yǔ)法跟 Java 語(yǔ)法很像锨亏,但是是一種動(dòng)態(tài)語(yǔ)言痴怨,而且在 Java 基礎(chǔ)上做了不少改進(jìn),用起來(lái)更加簡(jiǎn)潔器予、靈活浪藻,所以幾乎所有Java和Groovy支持的語(yǔ)法,它的腳本都支持乾翔,而且 Gradle 完全兼容 Maven爱葵、Ivy。
構(gòu)建工具
我們以前開(kāi)發(fā)都是用 Eclipse 反浓,而Eclipse 大家都知道是一種 IDE(集成開(kāi)發(fā)環(huán)境)萌丈,最初是用來(lái)做 Java 開(kāi)發(fā)的,而 Android 是基于 Java 語(yǔ)言的雷则,所以最初 Google 還是希望 Android 能在 Eclipse 上進(jìn)行開(kāi)發(fā)辆雾,為了滿足這個(gè)需求,Google 開(kāi)發(fā)了一個(gè)叫 ADT (Android Developer Tools)的東西月劈,相信以前從 Eclipse 時(shí)代過(guò)來(lái)的對(duì) ADT 應(yīng)該都不陌生度迂,正是因?yàn)橛辛?ADT 藤乙,從此我們只需要碼好代碼,然后直接在Eclipse 上進(jìn)行編譯惭墓、運(yùn)行坛梁、簽名、打包等一系列流程腊凶,而這背后的工作都是 ADT 的功勞划咐。某種意義上 ADT 就是我們的構(gòu)建工具。
而自 Google 推出 Android Studio 以來(lái)钧萍,就宣布默認(rèn)使用 Gradle 來(lái)作為構(gòu)建工具褐缠,并且之后放棄更新 ADT ,從此 Gradle 走入 Android 開(kāi)發(fā)者的視野风瘦,而我也是在 AS 的 Beta 版開(kāi)始接觸并學(xué)習(xí) Gradle送丰。
一般來(lái)說(shuō),構(gòu)建工具除了以上提到的編譯弛秋、運(yùn)行、簽名俐载、打包等蟹略,還具備依賴管理的功能,什么是依賴管理呢遏佣?還是拿 Eclipse 來(lái)說(shuō)挖炬,我們以前在 Eclipse 上開(kāi)發(fā) Android ,如果需要用到第三方庫(kù)的時(shí)候一般都是先下載 jar 文件状婶,然后把 jar 文件添加到 libs 目錄意敛,然后項(xiàng)目中就可以引用了。但是你不覺(jué)得這種管理方式很麻煩么膛虫?假設(shè)第三方庫(kù)有更新草姻,需要下載最新的 Jar 文件,然后替換掉原來(lái)的稍刀,引用的庫(kù)少還好撩独,一旦引用的第三方庫(kù)多,那簡(jiǎn)直麻煩死账月,可以說(shuō)這種方式只有依賴综膀,而沒(méi)有管理。
現(xiàn)在大家不陌生的 Gradle 引用第三方庫(kù)方式是這樣的:compile 'com.android.support:support-v4:24.0.1'
?
類似這樣的依賴方式局齿,是不是很方便剧劝?而且很直觀,直接可以看到源地址抓歼,升級(jí)的話直接改下版本號(hào)就可以了讥此,這就是所謂的依賴管理拢锹。
所以構(gòu)建工具就是對(duì)你的項(xiàng)目進(jìn)行編譯、運(yùn)行暂论、簽名面褐、打包、依賴管理等一系列功能的合集取胎,傳統(tǒng)的構(gòu)建工具有 Make展哭、Ant、Maven闻蛀、Ivy等匪傍,而 Gradle 是新一代的自動(dòng)化構(gòu)建工具。
Ant編寫(xiě)容易觉痛,但功能有限役衡,需要人工操作的過(guò)程也多;Maven依托于龐大的依賴倉(cāng)庫(kù)薪棒,因此有著強(qiáng)大的外部依賴管理手蝎,但添加本地依賴并不方便,且項(xiàng)目不能靈活修改俐芯。而Gradle能很好地結(jié)合Ant與Maven各自的優(yōu)點(diǎn)棵介,可以隨意的編寫(xiě)任務(wù)并組合成項(xiàng)目,直接利用Maven倉(cāng)庫(kù)吧史,并且能很好的支持傳遞依賴和內(nèi)部依賴邮辽。
通俗一點(diǎn)類比成吃飯的話,大致就是:Ant是自己買(mǎi)菜洗菜燒水做飯贸营,Maven是去飯店點(diǎn)餐吨述,Gradle是3D打印食物。
Gradle應(yīng)用場(chǎng)景
差異管理
國(guó)內(nèi)有n個(gè)Android市場(chǎng),n個(gè)手機(jī)品牌,n個(gè)手機(jī)尺寸......,一般公司都會(huì)針對(duì)不同的市場(chǎng)單獨(dú)發(fā)包用來(lái)統(tǒng)計(jì)不同渠道的下載量等情況,可能需要針對(duì)不同(品牌,尺寸等各種硬件信息)的手機(jī)做一些特殊的處理,這個(gè)時(shí)候你可以針對(duì)不同的情況單獨(dú)建一個(gè)工程,或者更好一點(diǎn)你可以通過(guò)一些變量來(lái)控制,像這樣:
if(isMoto){
do something
}else if(isHuawei){
do something
}
依賴管理
軟件開(kāi)發(fā)可能需要依賴各種不同的jar钞脂、library揣云,可以通過(guò)將.jar/library工程下載到本地再copy到你的工程中,但不知你是否聽(tīng)說(shuō)過(guò)國(guó)外有個(gè)叫中央倉(cāng)庫(kù)的東西芳肌,在這個(gè)倉(cāng)庫(kù)里你可以找到所有你能想到以及你從來(lái)沒(méi)聽(tīng)說(shuō)過(guò)的jar灵再、aar......這里可以找到所有你需要的依賴,而你需要的只是指定一個(gè)坐標(biāo)
compile 'com.android.support:support-v4:24.0.1'
剩下的依賴的尋找亿笤、下載翎迁、添加到classpath等你都不需要去關(guān)心
什么是Gradle插件?
在使用Android Studio進(jìn)行開(kāi)發(fā)的時(shí)候净薛,我們創(chuàng)建一個(gè)Android工程汪榔,會(huì)默認(rèn)生成一個(gè)build.gradle腳本,打開(kāi)腳本你會(huì)看到以下代碼:
apply plugin: 'com.android.application'
如果我們創(chuàng)建一個(gè)Library的話,就會(huì)變成:
apply plugin: 'com.android.library'
其實(shí)這就是在Gradle腳本引用Android為我們提供的插件痴腌,plugin表示插件雌团,’com.android.application’表示我們引用的插件名,通常是以包名來(lái)命名士聪。
這個(gè)插件是怎么被引用進(jìn)來(lái)的锦援?我們可以在根目錄找到另外一個(gè)build.gradle文件,打開(kāi)可以看到以下代碼:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
- buildscript方法是定義了全局的相關(guān)屬性
- repositories定義了jcenter作為倉(cāng)庫(kù)剥悟。一個(gè)倉(cāng)庫(kù)代表著你的依賴包的來(lái)源灵寺,例如maven倉(cāng)庫(kù)
- dependencies用來(lái)定義構(gòu)建過(guò)程
- classpath ‘com.android.tools.build:gradle:2.0.0’,就是將遠(yuǎn)程的插件下載到本地并將其構(gòu)建到我們工程當(dāng)中
Androd應(yīng)用插件其實(shí)就是Gradle插件区岗,用于提供Gradle構(gòu)建環(huán)境略板,支持其在AndroidStudio中使用,通過(guò)classpath 'com.android.tools.build:gradle:1.2.3'
獲取插件慈缔,apply plugin: 'java
應(yīng)用插件叮称。
理解Gradle腳本
當(dāng)然我們現(xiàn)在討論的所有內(nèi)容都是基于Android Studio的,所以請(qǐng)先行下載相關(guān)工具藐鹤。當(dāng)我們創(chuàng)建一個(gè)新的工程瓤檐,Android Studio會(huì)默認(rèn)為我們創(chuàng)建三個(gè)gradle文件,兩個(gè)build.gradle娱节,一個(gè)settings.gradle距帅,build.gradle分別放在了根目錄和moudle目錄下,下面是gradle文件的構(gòu)成圖:
MyApp
├── build.gradle
├── settings.gradle
└── app
└── build.gradle
setting.gradle解析
當(dāng)你的app只有一個(gè)模塊的時(shí)候括堤,你的setting.gradle將會(huì)是這樣子的:
include ':app'
setting.gradle文件將會(huì)在初始化時(shí)期執(zhí)行,關(guān)于初始化時(shí)期绍移,并且定義了哪一個(gè)模塊將會(huì)被構(gòu)建悄窃。舉個(gè)例子,上述setting.gradle包含了app模塊蹂窖,setting.gradle是針對(duì)多模塊操作的轧抗,所以單獨(dú)的模塊工程完全可以刪除掉該文件。在這之后瞬测,Gradle會(huì)為我們創(chuàng)建一個(gè)Setting對(duì)象横媚,并為其包含必要的方法,你不必知道Settings類的詳細(xì)細(xì)節(jié)月趟,但是你最好能夠知道這個(gè)概念灯蝴。
build.gradle的配置文件
基于grade構(gòu)建的項(xiàng)目通常至少有一個(gè)build.gradle,那么我們來(lái)看看Android的build.gradle:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
}
這個(gè)就是實(shí)際構(gòu)建開(kāi)始的地方孝宗,在倉(cāng)庫(kù)地址中穷躁,我們使用了JCenter,JCenter類似maven庫(kù)因妇,不需要任何額外的配置问潭,grade還支持其他幾個(gè)倉(cāng)庫(kù)猿诸,不論是遠(yuǎn)程還是本地倉(cāng)庫(kù)。
構(gòu)建腳本也定義了一個(gè)Android構(gòu)建工具狡忙,這個(gè)就是Android plugin(Android應(yīng)用插件)的來(lái)源之處梳虽。Android plugin提供了所有需要去構(gòu)建和測(cè)試的應(yīng)用。每個(gè)Android應(yīng)用都需要這么一個(gè)插件:
apply plugin: 'com.android.application'
Android應(yīng)用插件用于擴(kuò)展Gradle腳本的能力灾茁,在一個(gè)項(xiàng)目中使用插件窜觉,這樣該項(xiàng)目的構(gòu)建腳本就可以定義該插件定義好的屬性和使用它的tasks。
這里的Androd應(yīng)用插件其實(shí)就是Gradle插件删顶,用于提供Gradle構(gòu)建環(huán)境竖螃,支持其在AndroidStudio中使用,通過(guò)classpath 'com.android.tools.build:gradle:1.2.3'
獲取插件逗余,apply plugin: 'java
應(yīng)用插件
注意:當(dāng)你在開(kāi)發(fā)一個(gè)依賴庫(kù)特咆,那么你應(yīng)該使用'com.android.library',并且你不能同時(shí)使用他們2個(gè)录粱,這將導(dǎo)致構(gòu)建失敗腻格,一個(gè)模塊要么使用Android application或者Android library插件,而不是二者啥繁。
當(dāng)使用Android 插件的時(shí)候菜职,Android標(biāo)簽將可以被使用,如下所示:
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
}
根目錄的build.gradle
該gradle文件是定義在這個(gè)工程下的所有模塊的公共屬性旗闽,它默認(rèn)包含二個(gè)方法:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
}
allprojects {
repositories {
jcenter()
}
}
repositories {
mavenCentral()
}
buildscript方法是定義了全局的相關(guān)屬性酬核,repositories定義了jcenter作為倉(cāng)庫(kù)。一個(gè)倉(cāng)庫(kù)代表著你的依賴包的來(lái)源适室,例如maven倉(cāng)庫(kù)嫡意。dependencies用來(lái)定義構(gòu)建過(guò)程。這意味著你不應(yīng)該在該方法體內(nèi)定義子模塊的依賴包捣辆,你僅僅需要定義默認(rèn)的Android插件就可以了蔬螟,因?yàn)樵摬寮梢宰屇銏?zhí)行相關(guān)Android的tasks。
allprojects方法可以用來(lái)定義各個(gè)模塊的默認(rèn)屬性汽畴,你可以不僅僅局限于默認(rèn)的配置旧巾,未來(lái)你可以自己創(chuàng)造tasks在allprojects方法體內(nèi),這些tasks將會(huì)在所有模塊中可見(jiàn)忍些。
為什么repositories要聲明兩次哪鲁猩?buildscript代碼塊中的聲明與下半部分聲明有什么不同?buildscript中的聲明是gradle腳本自身需要使用的資源罢坝∩龋可以聲明的資源包括依賴項(xiàng)、第三方插件、maven倉(cāng)庫(kù)地址等疾棵。而在build.gradle文件中直接聲明的依賴項(xiàng)戈钢、倉(cāng)庫(kù)地址等信息是項(xiàng)目自身需要的資源。
模塊內(nèi)的build.gradle
模塊內(nèi)的gradle文件只對(duì)該模塊起作用是尔,而且其可以重寫(xiě)任何的參數(shù)來(lái)自于根目錄下的gradle文件殉了。模塊內(nèi)的build.gradle主要分三個(gè)模塊:apply plugin , android, dependencies。
該模塊文件應(yīng)該是這樣:
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.gradleforandroid.gettingstarted"
minSdkVersion 14
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
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:22.2.0'
}
apply plugin
apply plugin 聲明了接下來(lái)要用到哪些插件的內(nèi)容拟枚,上圖表明使用了 Androd 插件薪铜,這里之所以能用 Android 插件,是因?yàn)橹髂夸浿新暶髁?Gradle for Android 的依賴恩溅,這里才能使用隔箍。Android應(yīng)用插件,該插件其是Google的Android開(kāi)發(fā)團(tuán)隊(duì)編寫(xiě)的插件脚乡,能夠提供所有關(guān)于Android應(yīng)用和依賴庫(kù)的構(gòu)建蜒滩,打包和測(cè)試。
因此當(dāng)我們需要使用其他插件奶稠,比如 retrolambda 時(shí)俯艰,首先需要在主目錄 build.gradle 文件中添加依賴,然后在模塊 build.gradle 中聲明使用 retrolambda 插件锌订。
備注:默認(rèn)的 Android 插件是由 Google 官方維護(hù)的竹握,為我們提供了構(gòu)建、測(cè)試辆飘、打包 Android 應(yīng)用的能力啦辐。除此之外我們還可以自定義插件。在逐漸加深對(duì) Gradle 的了解后蜈项,我們將嘗試自己寫(xiě)個(gè) Gradle 插件昧甘。
android
在聲明了 Android 插件后,我們就可以使用 Android 插件提供的內(nèi)容進(jìn)行構(gòu)建配置战得。
android 構(gòu)建配置中必須要有的是兩個(gè)版本:
- compileSdkVersion : 編譯應(yīng)用的 Android API 版本
- buildToolsVersion : 構(gòu)建工具版本
- 構(gòu)建工具包括 aapt, zipalign, renderscript 等
- 用于在打包時(shí)生成各種中間產(chǎn)物,可以從 SDK Manager 中下載構(gòu)建工具
defaultConfig 代碼塊用于配置應(yīng)用的默認(rèn)屬性庸推,可以覆蓋 AndroidManifest.xml 中的屬性常侦,比如:
- applicationId : 覆蓋了 AndroidManifest 中的 package name
- minSdkVersion : 覆蓋了 AndroidManifest 中的屬性,配置運(yùn)行應(yīng)用的最小 API
- targetSdkVersion : 一樣贬媒,用于通知系統(tǒng)當(dāng)前應(yīng)用已經(jīng)被這個(gè)版本測(cè)試過(guò)聋亡,和之前的 compileSdkVersion 沒(méi)有關(guān)系
- versionCode : 一樣,應(yīng)用的版本號(hào)
- versionName : 版本名稱
defaultConfig 還可以添加簽名际乘,占位符等等坡倔,這里只列這些。
buildTypes 用來(lái)定義如何構(gòu)建和打包不同類型的應(yīng)用,常見(jiàn)的就是測(cè)試和生產(chǎn)罪塔。
android 中還可以配置其他信息投蝉,比如 簽名、渠道等征堪,你可以在 Project Structure 面板中直觀的查看瘩缆,添加,也可以使用代碼添加佃蚜。
dependencies
上圖中可以看到 依賴配置 在 android 代碼塊的外邊庸娱,事實(shí)上依賴配置是 Gradle 配置的基礎(chǔ)功能,也就是說(shuō)除了 Android谐算,其他類型的項(xiàng)目(比如 JavaEE )也可以這么用熟尉。
依賴模塊作為Gradle默認(rèn)的屬性之一,為你的App定義了所有的依賴包洲脂。
在配置完項(xiàng)目倉(cāng)庫(kù)后斤儿,我們可以聲明其中的依賴,如果我們想要聲明一個(gè)新的依賴腮考,可以采用如下步驟:
- 指定依賴的配置雇毫。
- 聲明所需的依賴。
有些時(shí)候踩蔚,你可能需要和SDK協(xié)調(diào)工作棚放。為了能順利編譯你的代碼,你需要添加SDK到你的編譯環(huán)境馅闽。你不需要將SDK包含在你的APK中飘蚯,因?yàn)樗缫呀?jīng)存在于設(shè)備中,所以配置來(lái)啦福也,我們會(huì)有5個(gè)不同的配置:
- compile
- apk
- provided
- testCompile
- androidTestCompile
compile是默認(rèn)的那個(gè)局骤,其含義是包含所有的依賴包,即在APK里暴凑,compile的依賴會(huì)存在峦甩。
apk的意思是apk中存在,但是不會(huì)加入編譯中现喳,這個(gè)貌似用的比較少凯傲。
provided的意思是提供編譯支持,但是不會(huì)寫(xiě)入apk嗦篱。
testCompile和androidTestCompile會(huì)添加額外的library支持針對(duì)測(cè)試冰单。
這些配置將會(huì)被用在測(cè)試相關(guān)的tasks中,這會(huì)對(duì)添加測(cè)試框架例如JUnit或者Espresso非常有用灸促,因?yàn)槟阒皇窍胱屵@些框架們能夠出現(xiàn)在測(cè)試apk中诫欠,而不是生產(chǎn)apk中涵卵。
除了這些特定的配置外,Android插件還為每個(gè)構(gòu)建變體提供了配置荒叼,這讓debugCompile或者releaseProvided等配置成為可能轿偎。如果你想針對(duì)你的debug版本添加一個(gè)logging框架,這將很有用甩挫。
一個(gè)依賴需要定義三個(gè)元素:group贴硫,name和version。group意味著創(chuàng)建該library的組織名伊者,通常這會(huì)是包名英遭,name是該library的唯一標(biāo)示。version是該library的版本號(hào)亦渗,我們來(lái)看看如何申明依賴:
dependencies {
compile 'com.google.code.gson:gson:2.3'
compile 'com.squareup.retrofit:retrofit:1.9.0'
}
上述的代碼是基于Groovy語(yǔ)法的挖诸,所以其完整的表述應(yīng)該是這樣的:
dependencies {
compile group: 'com.google.code.gson', name: 'gson', version:'2.3'
compile group: 'com.squareup.retrofit', name: 'retrofit', version: '1.9.0'
}
Gradle腳本的執(zhí)行時(shí)序
Gradle腳本的執(zhí)行分為三個(gè)過(guò)程:
-
初始化
分析有哪些Module將要被構(gòu)建,為每個(gè)Module創(chuàng)建對(duì)應(yīng)的 Project實(shí)例法精。這個(gè)時(shí)候settings.gradle
文件會(huì)被解析多律,setting.gradle是針對(duì)多模塊操作的,定義了哪一個(gè)模塊將會(huì)別構(gòu)建搂蜓。 - 配置:處理所有的模塊的 build.gradle 腳本狼荞,處理依賴、屬性等帮碰。這個(gè)時(shí)候每個(gè)模塊的build.gradle文件會(huì)被解析并配置相味,這個(gè)時(shí)候會(huì)構(gòu)建整個(gè)Task的鏈表(這里的鏈表僅僅指存在依賴關(guān)系的Task的集合,不是數(shù)據(jù)結(jié)構(gòu)的鏈表)殉挽。
- 執(zhí)行:根據(jù)Task鏈表來(lái)執(zhí)行某一個(gè)特定的Task丰涉,這個(gè)Task所依賴的其他Task都將會(huì)被提前執(zhí)行。
Project和tasks
在Grade中的兩大重要的概念斯碌,分別是Project和Tasks一死。每一次構(gòu)建都是有至少一個(gè)Project來(lái)完成,所以Android Studio中的Project和Gradle中的Project不是一個(gè)概念傻唾。每個(gè)Project有至少一個(gè)Tasks投慈。每一個(gè)build.grade文件代表著一個(gè)Project。Tasks在build.gradle中定義冠骄。當(dāng)初始化構(gòu)建進(jìn)程伪煤,Gradle會(huì)基于build文件,集合所有的Project和Tasks猴抹,一個(gè)Tasks包含了一系列動(dòng)作,然后它們將會(huì)按照順序執(zhí)行锁荔,一個(gè)動(dòng)作就是一段被執(zhí)行的代碼蟀给,很像Java中的方法蝙砌。