0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Gradle入門知識之Gradle詳解

jf_78858299 ? 來源:小余的自習(xí)室 ? 作者:小余的自習(xí)室 ? 2023-03-30 10:47 ? 次閱讀

前言:

大家回想一下自己第一次接觸Gradle是什么時候?

相信大家也都是和我一樣,在我們打開第一個AS項目的時候,

發(fā)現(xiàn)有很多帶gradle字樣的文件:setting.gradle, build.gradle,gradle.warpper,以及在gradle文件中各種配置,

這些都是啥wy啊。。

特別對于一些小公司開發(fā)人員,因為接觸架構(gòu)層面的機會很少,可能在使用AS幾年后都不一定對Gradle有太多深入了解,這是實話,因為筆者就是這么過來的。。

Gradle又是進(jìn)階高級開發(fā)的必經(jīng)之路。

好了,接下來進(jìn)入正題,此系列筆者會由淺入深的方式,帶領(lǐng)大家來了解下,Gradle背后究竟有哪些奧秘。

1.Gradle定義:

很多開發(fā)喜歡把Gradle簡單定義為一種構(gòu)建工具,和ant,maven等作用類似,

誠然Gradle確實是用來做構(gòu)建,但是如果簡單得把Gradle拿來做構(gòu)建,就太小看Gradle了.

筆者更愿意將Gradle看做一種編程框架。在這個框架中,你可以做很多ant,maven等常用構(gòu)建工具做不了的事情,

如將自己的任務(wù)task集成到構(gòu)建生命周期中,完成文件拷貝,腳本編寫等操作。

2.Gradle優(yōu)缺點:

相較早期的構(gòu)建工具:ant,maven等。

優(yōu)點如下:

  • 1.使用DSL Grovvy語言來編寫: :了解ant的同學(xué)應(yīng)該都知道:ant使用的是xml配置的模式,而Gradle使用的是表達(dá)性的Groovy來編寫,

    Groovy同時支持面向?qū)ο蠛兔嫦蜻^程進(jìn)行開發(fā),這個特性讓Groovy可以寫出一些腳本的任務(wù),這在傳統(tǒng)ant,maven上是不可能實現(xiàn)的

  • 2.基于java虛擬機: :Groovy是基于jvm的語言,groovy文件編譯后其實就是class文件,和我們的java一樣。

所以在gradle構(gòu)建過程中,我們完全可以使用java/kotlin去編寫我們的構(gòu)建任務(wù)以及腳本,極大的降低我們學(xué)習(xí)的成本。

  • 3.Gradle自定義task :可以構(gòu)建自己的任務(wù),然后掛接到gradle構(gòu)建生命周期中去,這在ant,maven上也是不可能實現(xiàn)的,
  • 4.擴展性好 :gradle將關(guān)鍵配置扔給我們開發(fā)者,開發(fā)者配置好任務(wù)后,無需關(guān)心gradle是如何構(gòu)建的。
  • 5.支持增量更新 :增量更新可以大大加快我們的編譯速度

關(guān)于Groovy的語法篇:可以參考這篇文章:

Gradle筑基篇(二)-groovy語法詳解

缺點:

用過gradle都知道,低版本gradle的項目在高版本的gradle中經(jīng)常出現(xiàn)很多莫名其妙的錯誤,向后兼容性較差。

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:可以理解為一個Project腳本,Project腳本中有自己的任務(wù),最外層的Project為rootProject
  • 2.settings.gradle:主要用來配置我們項目中需要用到的模塊。用include關(guān)鍵字給包裹進(jìn)
  • 3.gradle.properties:這個文件主要是設(shè)置一些全局變量,包括jvm運行以及自定義的一些全局參數(shù)
  • 4.local.properties:這個文件主要配置一些本地的sdk和ndk版本信息以及路徑
  • 5.gradle-wrapper.jar:負(fù)責(zé)自動下載Gradle腳本運行環(huán)境
  • 6.gradle-wrapper.properties:用來配置當(dāng)前使用的Gradle的版本以及存儲的路徑
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安裝包的存儲路徑;
distributionUrl:Gradle版本的下載地址。

注意這里如果將bin改為all,則可以查看當(dāng)前Gradle的源碼信息。

  • 7.gradlew和gradlew.bat:用來執(zhí)行構(gòu)建任務(wù)的腳本,可以在命令行使用gradlew xxxTask

4.Gradle生命周期

Gradle作為新興的構(gòu)建工具,其內(nèi)部也有自己的生命周期階段,每個階段做的事情都層次分明,

了解Gradle生命周期,才能很好的使用我們的Gradle工具。

1.初始化階段

做了哪些事情?:

  • 1.初始化Setting.gradle文件,獲取setting實例,
  • 2.執(zhí)行setting中的腳本,根據(jù)include字段,創(chuàng)建對應(yīng)的project實例
  • 3.設(shè)置構(gòu)建需要的環(huán)境

注意:初始化階段執(zhí)行任何任務(wù)都會執(zhí)行一次。

Project實例關(guān)系如下:

圖片

gradleproject樹.png

2.配置階段

  • 1.下載所有插件和構(gòu)建腳本依賴項
  • 2.執(zhí)行build.gradle文件中的腳本信息
  • 3.實現(xiàn)task任務(wù)的拓?fù)鋱D,這個圖是一個有向無環(huán)圖,防止任務(wù)執(zhí)行進(jìn)入死循環(huán)。

注意:配置階段執(zhí)行任何任務(wù)都會執(zhí)行一次。

3.執(zhí)行階段

執(zhí)行階段就是根據(jù)當(dāng)前task拓?fù)鋱D進(jìn)行執(zhí)行task任務(wù)。

需要注意以下幾點:

  • 1.在項目中配置的doLast,doFirst操作,都會在任務(wù)執(zhí)行階段執(zhí)行,而不會在配置階段執(zhí)行,

    而如果任務(wù)需要執(zhí)行,需要掛接到gradle執(zhí)行生命周期中,筆者開始接觸gradle時就踩過這個坑。。這塊后面講解task的時候在來具體講解

  • 2.前面也說了初始化階段和配置階段在每個任務(wù)執(zhí)行前都會執(zhí)行,所以 不要在前兩個階段進(jìn)行一些耗時的操作 ,這樣可能每次編譯執(zhí)行你都會崩潰的

5.Gradle生命周期監(jiān)聽:

要查找Gradle是如何監(jiān)聽生命周期,可以到Gradle源碼中看看:

  • 1.監(jiān)聽初始化階段

    初始化階段主要用來初始化Setting.gradle文件,獲取setting實例,創(chuàng)建Project實例等,所以其可用下面代碼監(jiān)聽:

//開始初始化Setting.gradle前
this.gradle.beforeSettings {
    println "beforeSettings"
}
//Setting.gradle配置完畢后,創(chuàng)建了setting實例
this.gradle.settingsEvaluated {
    println "settingsEvaluated"
}
//執(zhí)行解析Setting.gradle文件后,創(chuàng)建了project實例列表
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);

看這兩個方法的說明就是用來監(jiān)聽配置階段,傳入的是一個Action或者傳入一個閉包,閉包的代理為當(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"
}

注意:這個監(jiān)聽只是針對當(dāng)前Project的配置階段而不是所有Project的配置

你也可以使用:

this.project.beforeEvaluate
this.project.afterEvaluate

那么有沒有可以監(jiān)聽所有Project的配置階段的api呢?安排

2.2:監(jiān)聽每個Project的配置前后:

使用this.gradle的內(nèi)部方法,因為gradle是相對于整個工程作為作用域

//監(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)聽整個project配置階段的:當(dāng)然有

2.3:監(jiān)聽全部project配置階段的前后

this.gradle.projectsEvaluated {
    println "all projectsEvaluated"
}

這個閉包可以監(jiān)聽整個項目的配置完畢后的事件

配置階段還有一些監(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完畢后其實才是真正的配置階段完畢 ,瞧瞧源碼:

在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)聽整個配置階段的結(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ù)階段開始

其實可以使用配置階段的this.gradle.taskGraph.whenReady,這個就是所有project配置完畢,且生成了task拓?fù)鋱D

下一步就是開始執(zhí)行任務(wù)了

3.3:監(jiān)聽執(zhí)行任務(wù)階段結(jié)束

this.gradle.buildFinished {}

這個可以監(jiān)聽所有任務(wù)執(zhí)行完畢后事件回調(diào):

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • DSL
    DSL
    +關(guān)注

    關(guān)注

    2

    文章

    58

    瀏覽量

    38259
  • AS
    AS
    +關(guān)注

    關(guān)注

    0

    文章

    27

    瀏覽量

    26041
  • gradle
    +關(guān)注

    關(guān)注

    0

    文章

    26

    瀏覽量

    692
收藏 人收藏

    評論

    相關(guān)推薦

    Gradle版本目錄功能的簡單應(yīng)用

    版本帝 Gradle 最新版本已經(jīng)到了 8.1.1 ,你是不是還在用著 Gradle 3 的功能?今天我們了解一下 Gradle 7.0 之后推出的新功能 Version Catalog 版本目錄
    的頭像 發(fā)表于 09-30 11:12 ?1178次閱讀

    gradle安裝與配置unity

    Gradle是一種用于構(gòu)建和自動化構(gòu)建過程的強大工具,而Unity則是一款跨平臺的游戲引擎。在Unity項目中使用Gradle可以幫助我們更方便地管理和構(gòu)建項目,同時能夠提供更高的自定義能力和穩(wěn)定性
    的頭像 發(fā)表于 12-07 14:48 ?1855次閱讀

    Android Studio與Gradle深入

    小語言規(guī)范用來處理一個特定的事情(大多情況下是配置)。Android 的插件的 DSL 文檔在 Android Gradle DSL有說明?! ±斫饬艘陨匣A(chǔ)之后,你就會知其然,知其所以然了?! ∫陨?b class='flag-5'>知識
    發(fā)表于 08-31 17:58

    Gradle for Android

    Gradle for Android
    發(fā)表于 07-16 15:50

    請問OpenHarmony鴻蒙demo gradle報錯怎么解決?

    鴻蒙demo gradle報錯怎么解決build.gradle:4: Could not find method ohos() for arguments
    發(fā)表于 04-01 11:27

    DevEco Studio自動配置gradle的方法分享

    方法①在項目右鍵 Find in Path輸入gradle-5.4.1-all.zip方法②下載gradle-5.4.1-all.zip解壓至不要含有中文名稱的目錄比如我解壓后的路徑是D
    發(fā)表于 06-09 10:26

    快速入門Gradle的方法

    我們前面的Gradle是一門基于Groov的DSL,可能很多童鞋就是因為你是這個Gradle的迷,第一覺得Gradle是一門獨立的語言呀,如果想進(jìn)入歧途了,我一開始也是這么迷糊的,當(dāng)你了解之后,你就可以這么理解
    的頭像 發(fā)表于 04-08 10:56 ?1232次閱讀
    快速<b class='flag-5'>入門</b><b class='flag-5'>Gradle</b>的方法

    Gradle入門知識Gradle詳解(下)

    大家回想一下自己第一次接觸`Gradle`是什么時候? 相信大家也都是和我一樣,在我們打開第一個AS項目的時候, 發(fā)現(xiàn)有很多帶gradle字樣的文件:`setting.gradle, build.
    的頭像 發(fā)表于 03-30 10:51 ?801次閱讀
    <b class='flag-5'>Gradle</b><b class='flag-5'>入門</b><b class='flag-5'>知識</b><b class='flag-5'>之</b><b class='flag-5'>Gradle</b><b class='flag-5'>詳解</b>(下)

    Gradle入門知識Gradle語法1

    很多開發(fā)喜歡把`Gradle`簡單定義為一種構(gòu)建工具,和`ant,maven`等作用類似, 誠然Gradle確實是用來做構(gòu)建,但是如果簡單得把Gradle拿來做構(gòu)建,就太小看Gradle
    的頭像 發(fā)表于 03-30 10:54 ?945次閱讀
    <b class='flag-5'>Gradle</b><b class='flag-5'>入門</b><b class='flag-5'>知識</b><b class='flag-5'>之</b><b class='flag-5'>Gradle</b>語法1

    Gradle入門知識Gradle語法2

    很多開發(fā)喜歡把`Gradle`簡單定義為一種構(gòu)建工具,和`ant,maven`等作用類似, 誠然Gradle確實是用來做構(gòu)建,但是如果簡單得把Gradle拿來做構(gòu)建,就太小看Gradle
    的頭像 發(fā)表于 03-30 10:54 ?684次閱讀

    Gradle入門知識Gradle api解析(上)

    由于Project源碼篇幅太長:這里只列出類的部分方法和屬性: 我們前面分析過,每個build.gradle對應(yīng)一個Project,Project在初始過程中會被構(gòu)建為`樹`形結(jié)構(gòu):
    的頭像 發(fā)表于 03-30 11:01 ?2270次閱讀
    <b class='flag-5'>Gradle</b><b class='flag-5'>入門</b><b class='flag-5'>知識</b><b class='flag-5'>之</b><b class='flag-5'>Gradle</b> api解析(上)

    Gradle入門知識Gradle api解析(下)

    由于Project源碼篇幅太長:這里只列出類的部分方法和屬性: 我們前面分析過,每個build.gradle對應(yīng)一個Project,Project在初始過程中會被構(gòu)建為`樹`形結(jié)構(gòu):
    的頭像 發(fā)表于 03-30 11:05 ?995次閱讀

    Gradle Plugin和AGP的區(qū)別1

    Gradle Plugin`和`AGP`的區(qū)別? `Gradle Plugin`是`Gradle`構(gòu)建過程中使用的插件的總稱,而`Android Gradle Plugin`是這
    的頭像 發(fā)表于 03-30 11:48 ?1162次閱讀
    <b class='flag-5'>Gradle</b> Plugin和AGP的區(qū)別1

    Gradle Plugin和AGP的區(qū)別2

    Gradle Plugin`和`AGP`的區(qū)別? `Gradle Plugin`是`Gradle`構(gòu)建過程中使用的插件的總稱,而`Android Gradle Plugin`是這
    的頭像 發(fā)表于 03-30 11:49 ?1105次閱讀

    Gradle Plugin和AGP的區(qū)別3

    Gradle Plugin`和`AGP`的區(qū)別? `Gradle Plugin`是`Gradle`構(gòu)建過程中使用的插件的總稱,而`Android Gradle Plugin`是這
    的頭像 發(fā)表于 03-30 11:50 ?1172次閱讀