前言:
大家回想一下自己第一次接觸Gradle
是什么時(shí)候?
相信大家也都是和我一樣,在我們打開第一個(gè)AS項(xiàng)目的時(shí)候,
發(fā)現(xiàn)有很多帶gradle字樣的文件:setting.gradle, build.gradle,gradle.warpper
,以及在gradle
文件中各種配置,
這些都是啥wy啊。。
特別對(duì)于一些小公司開發(fā)人員,因?yàn)榻佑|架構(gòu)層面的機(jī)會(huì)很少,可能在使用AS幾年后都不一定對(duì)Gradle
有太多深入了解,這是實(shí)話,因?yàn)楣P者就是這么過來的。。
而Gradle
又是進(jìn)階高級(jí)
開發(fā)的必經(jīng)之路。
好了,接下來進(jìn)入正題,此系列筆者會(huì)由淺入深的方式,帶領(lǐng)大家來了解下,Gradle
背后究竟有哪些奧秘。
1.Gradle
定義:
很多開發(fā)喜歡把Gradle
簡(jiǎn)單定義為一種構(gòu)建工具,和ant,maven
等作用類似,
誠然Gradle確實(shí)是用來做構(gòu)建,但是如果簡(jiǎn)單得把Gradle拿來做構(gòu)建,就太小看Gradle了.
筆者更愿意將Gradle看做一種編程框架
。在這個(gè)框架中,你可以做很多ant,maven等常用構(gòu)建工具做不了的事情,
如將自己的任務(wù)task集成到構(gòu)建生命周期中,完成文件拷貝,腳本編寫等操作。
2.Gradle
優(yōu)缺點(diǎn):
相較早期的構(gòu)建工具:ant,maven等。
優(yōu)點(diǎn)如下:
-
1.使用DSL Grovvy語言來編寫: :了解ant的同學(xué)應(yīng)該都知道:ant使用的是xml配置的模式,而Gradle使用的是
表達(dá)性的Groovy
來編寫,Groovy同時(shí)
支持面向?qū)ο蠛兔嫦蜻^程
進(jìn)行開發(fā),這個(gè)特性讓Groovy
可以寫出一些腳本的任務(wù),這在傳統(tǒng)ant,maven上是不可能實(shí)現(xiàn)的 -
2.基于java虛擬機(jī): :
Groovy
是基于jvm
的語言,groovy
文件編譯后其實(shí)就是class文件,和我們的java
一樣。
所以在gradle構(gòu)建過程中,我們完全可以使用java/kotlin去編寫我們的構(gòu)建任務(wù)以及腳本,極大的降低我們學(xué)習(xí)的成本。
- 3.Gradle自定義task :可以構(gòu)建自己的任務(wù),然后掛接到gradle構(gòu)建
生命周期
中去,這在ant,maven上也是不可能實(shí)現(xiàn)的, - 4.擴(kuò)展性好 :gradle將關(guān)鍵配置扔給我們開發(fā)者,開發(fā)者配置好任務(wù)后,無需關(guān)心gradle是如何構(gòu)建的。
- 5.支持增量更新 :增量更新可以大大加快我們的編譯速度
關(guān)于Groovy的語法篇:可以參考這篇文章:
Gradle筑基篇(二)-groovy語法詳解
缺點(diǎn):
用過gradle都知道,低版本gradle的項(xiàng)目在高版本的gradle中經(jīng)常出現(xiàn)很多莫名其妙的錯(cuò)誤,向后兼容性較差。
3.Gradle
工程結(jié)構(gòu):
gradle標(biāo)準(zhǔn)工程代碼如下
├── moduleA
│ └── build.gradle
├── moduleB
│ └── build.gradle
├── build.gradle
├── settings.gradle
├── gradle.properties
├── local.properties
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
- 1.
build.gradle
:可以理解為一個(gè)Project腳本,Project腳本中有自己的任務(wù),最外層的Project為rootProject - 2.
settings.gradle
:主要用來配置我們項(xiàng)目中需要用到的模塊。用include關(guān)鍵字給包裹進(jìn) - 3.
gradle.properties
:這個(gè)文件主要是設(shè)置一些全局變量,包括jvm運(yùn)行以及自定義的一些全局參數(shù) - 4.
local.properties
:這個(gè)文件主要配置一些本地的sdk和ndk版本信息以及路徑 - 5.
gradle-wrapper.jar
:負(fù)責(zé)自動(dòng)下載Gradle腳本運(yùn)行環(huán)境 - 6.
gradle-wrapper.properties
:用來配置當(dāng)前使用的Gradle的版本以及存儲(chǔ)的路徑
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-bin.zip
distributionBase + distributionPath:指定Gradle安裝路徑;
zipStoreBase + zipStorePath:指定Gradle安裝包的存儲(chǔ)路徑;
distributionUrl:Gradle版本的下載地址。
注意這里如果將bin改為all,則可以查看當(dāng)前Gradle的源碼信息。
- 7.
gradlew和gradlew.bat
:用來執(zhí)行構(gòu)建任務(wù)的腳本,可以在命令行使用gradlew xxxTask
4.Gradle生命周期
Gradle作為新興的構(gòu)建工具,其內(nèi)部也有自己的生命周期階段,每個(gè)階段做的事情都層次分明,
了解Gradle生命周期,才能很好的使用我們的Gradle工具。
1.初始化階段
做了哪些事情?:
- 1.初始化
Setting.gradle
文件,獲取setting
實(shí)例, - 2.執(zhí)行
setting
中的腳本,根據(jù)include
字段,創(chuàng)建對(duì)應(yīng)的project
實(shí)例 - 3.設(shè)置構(gòu)建需要的環(huán)境
注意:初始化階段執(zhí)行任何任務(wù)都會(huì)執(zhí)行一次。
Project實(shí)例關(guān)系如下:
gradleproject樹.png
2.配置階段
- 1.下載所有插件和構(gòu)建腳本依賴項(xiàng)
- 2.執(zhí)行
build.gradle
文件中的腳本信息 - 3.實(shí)現(xiàn)task任務(wù)的拓?fù)鋱D,這個(gè)圖是一個(gè)
有向無環(huán)圖
,防止任務(wù)執(zhí)行進(jìn)入死循環(huán)。
注意:配置階段執(zhí)行任何任務(wù)都會(huì)執(zhí)行一次。
3.執(zhí)行階段
執(zhí)行階段就是根據(jù)當(dāng)前task拓?fù)鋱D進(jìn)行執(zhí)行task任務(wù)。
需要注意以下幾點(diǎn):
-
1.在項(xiàng)目中配置的
doLast,doFirst
操作,都會(huì)在任務(wù)執(zhí)行階段執(zhí)行,而不會(huì)在配置階段執(zhí)行,而如果任務(wù)需要執(zhí)行,需要掛接到
gradle執(zhí)行生命周期
中,筆者開始接觸gradle時(shí)就踩過這個(gè)坑。。這塊后面講解task
的時(shí)候在來具體講解 -
2.前面也說了初始化階段和配置階段在每個(gè)任務(wù)執(zhí)行前都會(huì)執(zhí)行,所以 不要在前兩個(gè)階段進(jìn)行一些耗時(shí)的操作 ,這樣可能每次編譯執(zhí)行你都會(huì)崩潰的
5.Gradle生命周期監(jiān)聽:
要查找Gradle是如何監(jiān)聽生命周期,可以到Gradle
源碼中看看:
-
1.監(jiān)聽初始化階段
初始化階段主要用來初始化
Setting.gradle
文件,獲取setting
實(shí)例,創(chuàng)建Project
實(shí)例等,所以其可用下面代碼監(jiān)聽:
//開始初始化Setting.gradle前
this.gradle.beforeSettings {
println "beforeSettings"
}
//Setting.gradle配置完畢后,創(chuàng)建了setting實(shí)例
this.gradle.settingsEvaluated {
println "settingsEvaluated"
}
//執(zhí)行解析Setting.gradle文件后,創(chuàng)建了project實(shí)例列表
this.gradle.projectsLoaded {
println "projectsLoaded"
}
- 2.監(jiān)聽配置階段
2.1:監(jiān)聽當(dāng)前project的配置階段前后:
在Project源碼
中可以看到:
/**
* Adds an action to execute immediately before this project is evaluated.
*
* @param action the action to execute.
*/
void beforeEvaluate(Action? action);
/**
* Adds an action to execute immediately after this project is evaluated.
*
* @param action the action to execute.
*/
void afterEvaluate(Action? action);
/**
* Adds a closure to be called immediately before this project is evaluated. The project is passed to the closure
* as a parameter.
*
* @param closure The closure to call.
*/
void beforeEvaluate(Closure closure);
/**
* Adds a closure to be called immediately after this project has been evaluated. The project is passed to the
* closure as a parameter. Such a listener gets notified when the build file belonging to this project has been
* executed. A parent project may for example add such a listener to its child project. Such a listener can further
* configure those child projects based on the state of the child projects after their build files have been
* run.
*
* @param closure The closure to call.
*/
void afterEvaluate(Closure closure);
看這兩個(gè)方法的說明就是用來監(jiān)聽配置階段,傳入的是一個(gè)Action或者傳入一個(gè)閉包,閉包的代理為當(dāng)前Project
使用方式如下 :
//監(jiān)聽project被配置前
this.beforeEvaluate {Project project ->
println "${project.name} :beforeEvaluate"
}
//監(jiān)聽project被配置后
this.afterEvaluate {Project project ->
println "${project.name}:afterEvaluate"
}
注意:這個(gè)監(jiān)聽只是針對(duì)當(dāng)前Project的配置階段而不是所有Project的配置
你也可以使用:
this.project.beforeEvaluate
this.project.afterEvaluate
那么有沒有可以監(jiān)聽所有Project的配置階段的api呢?安排
2.2:監(jiān)聽每個(gè)Project的配置前后:
使用this.gradle的內(nèi)部方法,因?yàn)?strong>gradle是相對(duì)于整個(gè)工程作為作用域
//監(jiān)聽所有的Project的被配置前
this.gradle.beforeProject {Project project ->
println "${project.name}:beforeProject"
}
//監(jiān)聽所有的Project的被配置后
this.gradle.afterProject {Project project ->
println "${project.name}:afterProject"
}
編譯下看看:
> Configure project :
gradle_source_plugin:afterProject
> Configure project :app
app:beforeProject
do app evaluating
app:afterProject
> Configure project :application
application:beforeProject
do application evaluating
application:afterProject
看到當(dāng)前工程所有的project都調(diào)用了一次beforeProject和afterProject
那有同學(xué)又要問了,有沒有監(jiān)聽整個(gè)project配置階段的:當(dāng)然有
2.3:監(jiān)聽全部project配置階段的前后
this.gradle.projectsEvaluated {
println "all projectsEvaluated"
}
這個(gè)閉包可以監(jiān)聽整個(gè)項(xiàng)目的配置完畢后的事件
配置階段還有一些監(jiān)聽如下:
2.4:監(jiān)聽任務(wù)的添加操作
this.project.tasks.whenTaskAdded {Task task->
println "${task.name}:whenTaskAdded"
}
2.5:監(jiān)聽任務(wù)拓?fù)鋱D的執(zhí)行
//task拓?fù)鋱D構(gòu)造完畢
this.gradle.taskGraph.whenReady {TaskExecutionGraph graph->
println "taskGraph:->"+graph
}
監(jiān)聽拓?fù)鋱D完畢后其實(shí)才是真正的配置階段完畢 ,瞧瞧源碼:
在BasePlugin中:
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,
project.getPath(),
null,
this::configureProject);
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,
project.getPath(),
null,
this::configureExtension);
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,
project.getPath(),
null,
this::createTasks);
看到配置階段最后一步才是創(chuàng)建Task,所以可以使用this.gradle.taskGraph.whenReady監(jiān)聽整個(gè)配置階段的結(jié)束
- 3.監(jiān)聽執(zhí)行階段
3.1:監(jiān)聽任務(wù)執(zhí)行:
gradle.taskGraph.beforeTask { Task task ->
println "${task.name}:beforeTask"
}
gradle.taskGraph.afterTask {Task task ->
println "${task.name}:afterTask"
}
執(zhí)行下面任務(wù):
task clean(type: Delete) {
doFirst {
println 'clean:doFirst'
}
doLast {
println 'clean:doLast'
}
delete rootProject.buildDir
}
結(jié)果:
> Task :clean
clean:beforeTask
clean:doFirst
clean:doLast
clean:afterTask
可以看到在task執(zhí)行前后調(diào)用了監(jiān)聽中的方法
3.2:監(jiān)聽執(zhí)行任務(wù)階段開始
其實(shí)可以使用配置階段的this.gradle.taskGraph.whenReady,這個(gè)就是所有project配置完畢,且生成了task拓?fù)鋱D
下一步就是開始執(zhí)行任務(wù)了
3.3:監(jiān)聽執(zhí)行任務(wù)階段結(jié)束
this.gradle.buildFinished {}
這個(gè)可以監(jiān)聽所有任務(wù)執(zhí)行完畢后事件回調(diào):
-
DSL
+關(guān)注
關(guān)注
2文章
58瀏覽量
38260 -
AS
+關(guān)注
關(guān)注
0文章
27瀏覽量
26056 -
gradle
+關(guān)注
關(guān)注
0文章
26瀏覽量
694
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論