
一、前言

????從明面上看,Gradle 是一款強(qiáng)大的構(gòu)建工具,但 Gradle 不僅僅是一款強(qiáng)大的構(gòu)建工具,它更像是一個(gè)編程框架。Gradle 的組成可以細(xì)分為如下三個(gè)方面:
????groovy 核心語(yǔ)法:包括 groovy 基本語(yǔ)法、閉包、數(shù)據(jù)結(jié)構(gòu)、面向?qū)ο蟮鹊取?br>
Android DSL(build scrpit block):Android 插件在 Gradle 所特有的東西,我們可以在不同的 build scrpit block 中去做不同的事情。
Gradle API:包含 Project、Task、Setting 等等。
可以看到,Gradle 的語(yǔ)法是以 groovy 為基礎(chǔ)的,而且它還有自己獨(dú)有的 API,所以我們可以把 Gradle 認(rèn)作是一款編程框架,利用 Gradle 我們可以在編程中去實(shí)現(xiàn)項(xiàng)目構(gòu)建過(guò)程中的所有需求。想要隨心所欲地使用 Gradle,我們必須提前掌握好 groovy。需要注意的是,Groovy 是一門(mén)語(yǔ)言,而 DSL 一種特定領(lǐng)域的配置文件,Gradle 是基于 Groovy 的一種框架工具,而 gradlew 則是 gradle 的一個(gè)兼容包裝工具。
Gradle 有以下優(yōu)勢(shì):
- 靈活性:相對(duì)于 Maven、Ant 等構(gòu)建工具,Gradle 提供了一系列的 API 讓我們有能力去修改或定制項(xiàng)目的構(gòu)建過(guò)程。例如我們可以利用 Gradle 去動(dòng)態(tài)修改生成的 APK 包名。
- 粒度性:使用 Maven、Ant 等構(gòu)建工具時(shí),我們的源代碼和構(gòu)建腳本是獨(dú)立的,而且我們也不知道其內(nèi)部的處理是怎樣的。但是 Gradle 則不同,它從源代碼的編譯、資源的編譯、到生成 APK 的過(guò)程中都是一個(gè)接一個(gè)來(lái)執(zhí)行的。此外,Gradle 構(gòu)建的粒度細(xì)化到了每一個(gè) task 之中。并且它所有的 Task 源碼都是開(kāi)源的,在我們掌握了這一整套打包流程后,我們就可以通過(guò)修改它的 Task 去動(dòng)態(tài)改變其執(zhí)行流程。例如 Tinker 框架的實(shí)現(xiàn)過(guò)程中,它通過(guò)動(dòng)態(tài)地修改 Gradle 的打包過(guò)程生成 APK 的同時(shí),也生成了各種補(bǔ)丁文件。
- 擴(kuò)展性:Gradle 支持插件機(jī)制,所以我們可以復(fù)用這些插件,就如同復(fù)用庫(kù)一樣簡(jiǎn)單方便。
兼容性:Gradle 不僅自身功能強(qiáng)大,而且它還能兼容所有的 Maven、Ant 功能,也就是說(shuō),Gradle 吸取了所有構(gòu)建工具的長(zhǎng)處。
可以看到,Gradle 相比于其它構(gòu)建工具,其好處不言而喻,而其最核心的原因就是因?yàn)?Gradle 是一套編程框架。
二、Gradle 的生命周期
????所謂 Gradle 的生命周期,即 gradle 的執(zhí)行流程,也就是 Gradle 先執(zhí)行什么后執(zhí)行什么。我們看下它的流程圖:
可以看到,gradle 的執(zhí)行流程分了 初始化、配置、執(zhí)行 三個(gè)階段,上圖中的 project、task 我們接下來(lái)幾篇會(huì)詳細(xì)介紹。下面我們看看這幾個(gè)階段。

2.1 初始化階段
????初始化階段會(huì)讀取根工程中的 setting.gradle 中的 include 信息,確定有多少工程加入構(gòu)建,然后會(huì)為每一個(gè)項(xiàng)目(build.gradle 腳本文件)創(chuàng)建一個(gè)個(gè)與之對(duì)應(yīng)的 Project 實(shí)例,最終形成一個(gè)項(xiàng)目的層次結(jié)構(gòu)。
????與初始化階段相關(guān)的腳本文件是 settings.gradle,而一個(gè) settings.gradle 腳本對(duì)應(yīng)一個(gè) Settings 對(duì)象,我們最常用來(lái)聲明項(xiàng)目的層次結(jié)構(gòu)的 include 就是 Settings 對(duì)象下的一個(gè)方法,在 Gradle 初始化的時(shí)候會(huì)構(gòu)造一個(gè) Settings 實(shí)例對(duì)象,以執(zhí)行各個(gè) Project 的初始化配置。

????此外,在 settings.gradle 文件中,我們可以指定其它 project 的位置,這樣就可以將其它外部工程中的 moudle 導(dǎo)入到當(dāng)前的工程之中了。示例代碼如下所示:
if (useStepMoudle) {
// 導(dǎo)入其它 App 的 step 步數(shù)模塊
include "step"
project(":step").projectDir = new File("../OtherApp/step")
}
2.2 配置階段
????配置階段的任務(wù)是執(zhí)行各項(xiàng)目下的 build.gradle 腳本,完成 Project 的配置,與此同時(shí),會(huì)構(gòu)造 Task 任務(wù)依賴關(guān)系圖以便在執(zhí)行階段按照依賴關(guān)系執(zhí)行 Task而在配置階段執(zhí)行的代碼通常來(lái)說(shuō)都會(huì)包括以下三個(gè)部分的內(nèi)容,如下所示:
- 1)、build.gralde 中的各種語(yǔ)句。
- 2)、閉包。
-
1)、Task 中的配置段語(yǔ)句
需要注意的是,執(zhí)行任何 Gradle 命令,在初始化階段和配置階段的代碼都會(huì)被執(zhí)行。
2.3 執(zhí)行階段
????在配置階段結(jié)束后,Gradle 會(huì)根據(jù)各個(gè)任務(wù) Task 的依賴關(guān)系來(lái)創(chuàng)建一個(gè)有向無(wú)環(huán)圖,我們可以通過(guò) Gradle 對(duì)象的 getTaskGraph 方法來(lái)得到該有向無(wú)環(huán)圖。并且當(dāng)有向無(wú)環(huán)圖構(gòu)建完成之后,所有 Task 執(zhí)行之前,我們可以通過(guò) whenReady(groovy.lang.Closure) 或者 addTaskExecutionGraphListener(TaskExecutionGraphListener) 來(lái)接收相應(yīng)的通知,其代碼如下所示:
gradle.getTaskGraph().addTaskExecutionGraphListener(new TaskExecutionGraphListener() {
@Override
void graphPopulated(TaskExecutionGraph taskExecutionGraph) {
}
})
然后,Gradle 構(gòu)建系統(tǒng)會(huì)通過(guò)調(diào)用 gradle <任務(wù)名> 來(lái)執(zhí)行相應(yīng)的各個(gè)任務(wù)。
可以看到,整個(gè) Gradle 生命周期的流程包含如下 四個(gè)部分:
- 首先,解析 settings.gradle 來(lái)獲取模塊信息,這是初始化階段。
- 然后,配置每個(gè)模塊,配置的時(shí)候并不會(huì)執(zhí)行 task。
- 接著,配置完了以后,有一個(gè)重要的回調(diào) project.afterEvaluate,它表示所有的模塊都已經(jīng)配置完了,可以準(zhǔn)備執(zhí)行 task 了。
- 最后,執(zhí)行指定的 task 及其依賴的 task。

2.4 生命周期監(jiān)聽(tīng)
????上面我們學(xué)習(xí)了 Gradle 的執(zhí)行生命流程,下面我們?cè)谒谋O(jiān)聽(tīng)回調(diào)中做一些輸出。首先在項(xiàng)目根目錄的 build.gradle 中添加如下監(jiān)聽(tīng)代碼:
//配置階段開(kāi)始前的監(jiān)聽(tīng)回調(diào),也就是初始化階段和配置階段之間
beforeEvaluate {
println "準(zhǔn)備執(zhí)行配置階段..."
}
//配置階段完成后的監(jiān)聽(tīng)回調(diào),執(zhí)行階段之前的監(jiān)聽(tīng)
afterEvaluate {
println "配置階段執(zhí)行完畢..."
}
//gradle生命周期執(zhí)行完畢后的回調(diào)監(jiān)聽(tīng)
this.gradle.buildFinished {
println "執(zhí)行階段執(zhí)行完畢..."
}
this.gradle.beforeProject{
}
this.gradle.afterProject{
}
在根目錄的 setting.gradle 中添加如下代碼:
include ':app'
println "初始化階段開(kāi)始"
接下來(lái)我們執(zhí)行一個(gè)簡(jiǎn)單的 gradle 命令:gradle clean
