Gradle 自動化構(gòu)建項目(一)Gradle 核心之生命周期

一经窖、前言
image.png

????從明面上看画侣,Gradle 是一款強大的構(gòu)建工具,但 Gradle 不僅僅是一款強大的構(gòu)建工具配乱,它更像是一個編程框架搬泥。Gradle 的組成可以細(xì)分為如下三個方面:

????groovy 核心語法:包括 groovy 基本語法、閉包忿檩、數(shù)據(jù)結(jié)構(gòu)燥透、面向?qū)ο蟮鹊取?br> Android DSL(build scrpit block):Android 插件在 Gradle 所特有的東西,我們可以在不同的 build scrpit block 中去做不同的事情兽掰。
Gradle API:包含 Project孽尽、Task、Setting 等等。
可以看到鸳吸,Gradle 的語法是以 groovy 為基礎(chǔ)的速勇,而且它還有自己獨有的 API,所以我們可以把 Gradle 認(rèn)作是一款編程框架养匈,利用 Gradle 我們可以在編程中去實現(xiàn)項目構(gòu)建過程中的所有需求都伪。想要隨心所欲地使用 Gradle,我們必須提前掌握好 groovy猬仁。需要注意的是先誉,Groovy 是一門語言,而 DSL 一種特定領(lǐng)域的配置文件诈闺,Gradle 是基于 Groovy 的一種框架工具漱病,而 gradlew 則是 gradle 的一個兼容包裝工具杨帽。

Gradle 有以下優(yōu)勢:

  • 靈活性:相對于 Maven嗤军、Ant 等構(gòu)建工具,Gradle 提供了一系列的 API 讓我們有能力去修改或定制項目的構(gòu)建過程老客。例如我們可以利用 Gradle 去動態(tài)修改生成的 APK 包名震叮。
  • 粒度性:使用 Maven、Ant 等構(gòu)建工具時尉间,我們的源代碼和構(gòu)建腳本是獨立的,而且我們也不知道其內(nèi)部的處理是怎樣的贪薪。但是 Gradle 則不同眠副,它從源代碼的編譯、資源的編譯霍弹、到生成 APK 的過程中都是一個接一個來執(zhí)行的娃弓。此外,Gradle 構(gòu)建的粒度細(xì)化到了每一個 task 之中钝计。并且它所有的 Task 源碼都是開源的齐佳,在我們掌握了這一整套打包流程后,我們就可以通過修改它的 Task 去動態(tài)改變其執(zhí)行流程本鸣。例如 Tinker 框架的實現(xiàn)過程中硅蹦,它通過動態(tài)地修改 Gradle 的打包過程生成 APK 的同時,也生成了各種補丁文件涮瞻。
  • 擴展性:Gradle 支持插件機制假褪,所以我們可以復(fù)用這些插件,就如同復(fù)用庫一樣簡單方便宁否。
    兼容性:Gradle 不僅自身功能強大缀遍,而且它還能兼容所有的 Maven域醇、Ant 功能冤寿,也就是說青伤,Gradle 吸取了所有構(gòu)建工具的長處。
    可以看到号杠,Gradle 相比于其它構(gòu)建工具丰歌,其好處不言而喻,而其最核心的原因就是因為 Gradle 是一套編程框架眼溶。
二晓勇、Gradle 的生命周期

????所謂 Gradle 的生命周期绑咱,即 gradle 的執(zhí)行流程,也就是 Gradle 先執(zhí)行什么后執(zhí)行什么铝噩。我們看下它的流程圖:
Gradle 的生命周期

可以看到窿克,gradle 的執(zhí)行流程分了 初始化、配置具被、執(zhí)行 三個階段谋右,上圖中的 project改执、task 我們接下來幾篇會詳細(xì)介紹坑雅。下面我們看看這幾個階段。


gradle 生命周期分解
2.1 初始化階段

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


setting對象

????此外将塑,在 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í)行各項目下的 build.gradle 腳本戚长,完成 Project 的配置怠苔,與此同時柑司,會構(gòu)造 Task 任務(wù)依賴關(guān)系圖以便在執(zhí)行階段按照依賴關(guān)系執(zhí)行 Task而在配置階段執(zhí)行的代碼通常來說都會包括以下三個部分的內(nèi)容,如下所示:

  • 1)攒驰、build.gralde 中的各種語句玻粪。
  • 2)诬垂、閉包伦仍。
  • 1)充蓝、Task 中的配置段語句
    需要注意的是,執(zhí)行任何 Gradle 命令悠垛,在初始化階段和配置階段的代碼都會被執(zhí)行娜谊。
2.3 執(zhí)行階段

????在配置階段結(jié)束后,Gradle 會根據(jù)各個任務(wù) Task 的依賴關(guān)系來創(chuàng)建一個有向無環(huán)圖湾趾,我們可以通過 Gradle 對象的 getTaskGraph 方法來得到該有向無環(huán)圖派草。并且當(dāng)有向無環(huán)圖構(gòu)建完成之后,所有 Task 執(zhí)行之前艺普,我們可以通過 whenReady(groovy.lang.Closure) 或者 addTaskExecutionGraphListener(TaskExecutionGraphListener) 來接收相應(yīng)的通知鉴竭,其代碼如下所示:

gradle.getTaskGraph().addTaskExecutionGraphListener(new TaskExecutionGraphListener() {
    @Override
    void graphPopulated(TaskExecutionGraph taskExecutionGraph) {

    }
})

然后搏存,Gradle 構(gòu)建系統(tǒng)會通過調(diào)用 gradle <任務(wù)名> 來執(zhí)行相應(yīng)的各個任務(wù)。

可以看到缩焦,整個 Gradle 生命周期的流程包含如下 四個部分:

  • 首先责静,解析 settings.gradle 來獲取模塊信息,這是初始化階段呻拌。
  • 然后睦焕,配置每個模塊垃喊,配置的時候并不會執(zhí)行 task。
  • 接著初家,配置完了以后乌助,有一個重要的回調(diào) project.afterEvaluate,它表示所有的模塊都已經(jīng)配置完了掖肋,可以準(zhǔn)備執(zhí)行 task 了赏参。
  • 最后把篓,執(zhí)行指定的 task 及其依賴的 task。

????在 Gradle 構(gòu)建命令中紊浩,最為復(fù)雜的命令可以說是 gradle build 這個命令了疗锐,因為項目的構(gòu)建過程中需要依賴很多其它的 task。這里呜袁,我們以 Java 項目的構(gòu)建過程看看它所依賴的 tasks 及其組成的有向無環(huán)圖简珠,如下所示:
有向無環(huán)圖
2.4 生命周期監(jiān)聽

????上面我們學(xué)習(xí)了 Gradle 的執(zhí)行生命流程聋庵,下面我們在它的監(jiān)聽回調(diào)中做一些輸出。首先在項目根目錄的 build.gradle 中添加如下監(jiān)聽代碼:

//配置階段開始前的監(jiān)聽回調(diào)氧映,也就是初始化階段和配置階段之間
beforeEvaluate {
    println "準(zhǔn)備執(zhí)行配置階段..."
}

//配置階段完成后的監(jiān)聽回調(diào)脱货,執(zhí)行階段之前的監(jiān)聽
afterEvaluate {
    println "配置階段執(zhí)行完畢..."
}

//gradle生命周期執(zhí)行完畢后的回調(diào)監(jiān)聽
this.gradle.buildFinished {
    println "執(zhí)行階段執(zhí)行完畢..."
}

this.gradle.beforeProject{
}

this.gradle.afterProject{
}

在根目錄的 setting.gradle 中添加如下代碼:

include ':app'

println "初始化階段開始"

接下來我們執(zhí)行一個簡單的 gradle 命令:gradle clean

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末臼疫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子烫堤,更是在濱河造成了極大的恐慌鸽斟,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剩燥,死亡現(xiàn)場離奇詭異格粪,居然都是意外死亡帐萎,警方通過查閱死者的電腦和手機比伏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疆导,“玉大人赁项,你說我怎么就攤上這事〕憾危” “怎么了悠菜?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長败富。 經(jīng)常有香客問我悔醋,道長,這世上最難降的妖魔是什么兽叮? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鹦聪,結(jié)果婚禮上账阻,老公的妹妹穿的比我還像新娘。我一直安慰自己泽本,他們只是感情好淘太,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般蒲牧。 火紅的嫁衣襯著肌膚如雪撇贺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天造成,我揣著相機與錄音显熏,去河邊找鬼雄嚣。 笑死晒屎,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缓升。 我是一名探鬼主播鼓鲁,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼港谊!你這毒婦竟也來了骇吭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤歧寺,失蹤者是張志新(化名)和其女友劉穎燥狰,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斜筐,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡龙致,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了顷链。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片目代。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嗤练,靈堂內(nèi)的尸體忽然破棺而出榛了,到底是詐尸還是另有隱情,我是刑警寧澤煞抬,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布霜大,位于F島的核電站,受9級特大地震影響革答,放射性物質(zhì)發(fā)生泄漏战坤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一蝗碎、第九天 我趴在偏房一處隱蔽的房頂上張望湖笨。 院中可真熱鬧,春花似錦蹦骑、人聲如沸慈省。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽边败。三九已至袱衷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間笑窜,已是汗流浹背致燥。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留排截,地道東北人嫌蚤。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像断傲,于是被迫代替她去往敵國和親脱吱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容