Gradle系列第(二)篇---Gradle編程主要對象

版權(quán)聲明:本文為LooperJing原創(chuàng)文章哩照,轉(zhuǎn)載請注明出處弧烤!

學習Gradle前涧黄,需要有一個Groovy語言的基礎(chǔ)漓帚,以免被Groovy的語法困擾母债,反而忽略了Gradle的知識,可以大致看下上篇文章Gradle系列第(一)篇---Groovy語法初探1胰默。作為一個菜鳥场斑,很想知道 Gradle 的腳本怎么去寫,也看了很多網(wǎng)上的文章牵署,大多都是從腳本的角度來介紹Gradle漏隐,給我的感覺就是,只記住參數(shù)怎么配置奴迅,卻不知道它們都是函數(shù)調(diào)用青责,有相關(guān)API對應(yīng)的。比如我們很常見的一行代碼 apply plugin: 'com.android.application' 是什么意思呢取具?原來一個 build.gradle 對應(yīng)一個 Project , apply 是一個Project 的一個函數(shù) 脖隶,這段代碼其實就是調(diào)用了project對象的apply方法,傳入了一個以plugin為key的map暇检。完整寫出來就是這樣的:project.apply([plugin: 'com.android.application'])产阱。這樣就明白了。所以我們先要學習Gradle的API块仆,然后才能熟練用Gradle構(gòu)建項目构蹬。

1、Project悔据、Task庄敛、Action的關(guān)系

創(chuàng)建Android項目的時候,每一個項目中都有一個build.gradle文件科汗,我們稱build.gradle文件為構(gòu)建腳本,后面你會了解到這個構(gòu)建腳本定義了一個project和一些默認的task藻烤,在解析 Gradle 的編譯過程之前我們需要理解在 Gradle 中非常重要的兩個對象。Project和Task头滔。每個項目的編譯至少有一個 Project,一個 build.gradle就代表一個project,每個project里面包含了多個task,每個task代表了構(gòu)建過程當中的一個原子性操作怖亭,比如編譯,打包坤检,生成javadoc兴猩,發(fā)布等這些操作。task 里面又包含很多action缀蹄,action是一個代碼塊,里面包含了需要被執(zhí)行的代碼。

2缺前、Gradle對象

Gradle基于Groovy蛀醉,Groovy又基于Java。所以衅码,Gradle執(zhí)行的時候和Groovy一樣拯刁,會把腳本轉(zhuǎn)換成Java對象。Gradle主要有三種對象逝段,這三種對象和三種不同的腳本文件對應(yīng)垛玻,在gradle執(zhí)行的時候,會將腳本轉(zhuǎn)換成對應(yīng)的對象:
Gradle對象:當我們執(zhí)行g(shù)radle xxx或者什么的時候奶躯,gradle會從默認的配置腳本中構(gòu)造出一個Gradle對象帚桩。在整個執(zhí)行過程中,只有這么一個對象嘹黔。Gradle對象的數(shù)據(jù)類型就是Gradle账嚎。我們一般很少去定制這個默認的配置腳本。
Project對象:每一個build.gradle會轉(zhuǎn)換成一個Project對象儡蔓。
Settings對象:每一個settings.gradle都會轉(zhuǎn)換成一個Settings對象郭蕉。

既然當我們執(zhí)行g(shù)radle xxx或者什么的時候,gradle會從默認的配置腳本中構(gòu)造出一個Gradle對象喂江,那么看一看Gradle對象的信息有哪些召锈。在build.gradle文件中定義一個Task,如下:

task printGradleInfo{
    println "----------------------------------------------- "
    println "In posdevice, gradle id is " +gradle.hashCode()
    println "Home Dir:" + gradle.gradleHomeDir
    println "User Home Dir:" + gradle.gradleUserHomeDir
    println "Parent: " + gradle.parent
}

執(zhí)行g(shù)radlew -q printGradleInfo
輸出

F:\StudyProject\GradleTest2>gradlew -q printGradleInfo
In posdevice, gradle id is 635573988
Home Dir:C:\Users\wangjing\.gradle\wrapper\dists\gradle-2.14.1-all\8bnwg5hd3w55i
User Home Dir:C:\Users\wangjing\.gradle
Parent: null

如果你在打印gradle的hashCode,得到的輸出也是635573988获询,也驗證了在整個執(zhí)行過程中涨岁,只有這么一個對象

3筐付、Gradle的生命周期

項目結(jié)構(gòu).png

如上圖,執(zhí)行g(shù)radlew -q project
輸出

Root project 'GradleTest'
+--- Project ':app'
+--- Project ':library'
\--- Project ':library2'

每一個Library和每一個App都是單獨的Project卵惦。根據(jù)Gradle的要求,每一個Project在其根目錄下都需要有一個build.gradle瓦戚。build.gradle文件就是該Project的編譯腳本沮尿。因為包含了多個項目,所以還要有一個setting.gradle用于多項目的構(gòu)建较解。Gradle的生命周期總共分成三個階段畜疾,初始化階段,配置階段印衔,執(zhí)行任務(wù)階段啡捶。首先是初始化階段,這個時候settings.gradle會執(zhí)行奸焙。初始化的下一個階段是配置階段瞎暑。配置階段的目標是解析每個project中的build.gradle彤敛,其內(nèi)部的任務(wù)也會被添加到一個有向圖里,用于解決執(zhí)行過程中的依賴關(guān)系了赌。在上圖中墨榄,gradle的解析順序是:rootproject 的setting.gradle,然后是rootproject的build.gradle,然后是各個subproject。最后一個階段就是執(zhí)行任務(wù)了勿她,你在gradle xxx中指定什么任務(wù)袄秩,gradle就會將這個xxx任務(wù)鏈上的所有任務(wù)全部按依賴順序執(zhí)行一遍!
gradle整個編譯過程都是可控的逢并,通過實現(xiàn)TaskExecutionListener和BuildListener可以對整個編譯過程進行監(jiān)聽之剧。下面的代碼打印了一下task的名字。

gradle.addListener(new LifecycleListener())
class LifecycleListener implements  TaskExecutionListener,BuildListener{
    @Override
    void buildStarted(Gradle gradle) {

    }

    @Override
    void settingsEvaluated(Settings settings) {

    }

    @Override
    void projectsLoaded(Gradle gradle) {

    }

    @Override
    void projectsEvaluated(Gradle gradle) {

    }

    @Override
    void buildFinished(BuildResult result) {

    }

    @Override
    void beforeExecute(Task task) {

        println("beforeExecute "+task.name)
    }

    @Override
    void afterExecute(Task task, TaskState state) {
        println("afterExecute  name="+task.name+" state="+state.toString() )
    }
}

輸出結(jié)果:

beforeExecute printGradleInfo
afterExecute  name=printGradleInfo state=org.gradle.api.internal.tasks.TaskState

4砍聊、Project

一般app.build文件的第一行是apply plugin: 'com.android.application'背稼,這句話是什么意思,剛剛解釋過辩恼,我們之前說在 Gradle 中構(gòu)建腳本定義了一個項目(project)雇庙。在構(gòu)建的每一個項目中,Gradle 創(chuàng)建了一個Project類型的實例灶伊,并在構(gòu)建腳本中關(guān)聯(lián)此Project對象疆前。并且Project接口是你在 Gradle API 中訪問一切 的入點,當構(gòu)建腳本執(zhí)行時聘萨,它會配置此Project對象竹椒。調(diào)用project的api來獲取和項目有關(guān)的信息。

task queryInfo<<{
    println name
    println project.name
}

執(zhí)行命令gradlew -q queryInfo
輸出

queryInfo
app

第一個獲取的是任務(wù)名稱米辐,第二個獲取的是Project名稱胸完,如果把queryInfo中的 println name放在外面,他會打印項目名稱翘贮。

println name
task check<<{
 println project.name
}
app
app

查詢項目的項目信息:

task queryProjectInfo<<{
    //項目名
    println project.name
    //項目相對路徑
    println project.path
    //項目描述
    println project.description
    //項目的絕對路徑
    println project.projectDir
    //項目的build文件絕對路徑
    println project.buildDir
    //項目所在的group
    println project.group
    //項目的版本號
    println project.version
    //項目的ant對象
    println project.ant
}

執(zhí)行命令gradlew -q queryInfo
輸出

app
:app
null
E:\Programs\android_studio\GradleTest\app
E:\Programs\android_studio\GradleTest\app\build
GradleTest
unspecified
org.gradle.api.internal.project.DefaultAntBuilder@3f1ae6ad

還有若干方法的使用

比如赊窥,在解析setting.gradle之后,開始解析build.gradle之前狸页,這里如果要干些事情可以寫在beforeEvaluate锨能。

在所有build.gradle解析完成后,開始執(zhí)行task之前芍耘,此時所有的腳本已經(jīng)解析完成址遇,task,plugins等所有信息可以獲取斋竞,task的依賴關(guān)系也已經(jīng)生成倔约,如果此時需要做一些事情,可以寫在afterEvaluate坝初。文檔對afterEvaluate(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.

舉個列子:過濾掉一些我不想執(zhí)行的task.

def disableDebugBuild(){
    //project.tasks包含了所有的tasks浸剩,下面的findAll是尋找那些名字中帶debug的Task钾军。
    //返回值保存到targetTasks容器中
    def targetTasks = project.tasks.findAll{task ->
        task.name.contains("Debug")
    }
    //對滿足條件的task,設(shè)置它為disable绢要。如此這般巧颈,這個Task就不會被執(zhí)行
    targetTasks.each{
        println"disable debug task  :${it.name}"
        it.setEnabled false
    }
}

project.afterEvaluate{
    disableDebugBuild()
}

又比如

apply plugin: 'com.android.application'  的原形是
project.apply([plugin: 'com.android.application'])
dependencies {
       compile 'com.google.code.gson:gson:2.3'
}

原形:

project.dependencies({
       add('compile', 'com.google.code.gson:gson:2.3', {
           // Configuration statements
       })
})

看看下面的圖,Project的方法和屬性很多

這是Project官方文檔:https://docs.gradle.org/current/dsl/org.gradle.api.Project.html

project的方法.png

5袖扛、Task

如果你想知道你多少tasks可以用,直接運行g(shù)radlew tasks十籍,其會為你展示所有可用的tasks蛆封。當你創(chuàng)建了一個Android工程,那么將包含Android tasks勾栗,build tasks惨篱,build setup tasks,help tasks围俘,install tasks砸讳,verification tasks等。

項目構(gòu)建過程中那么多任務(wù)界牡,有些test相關(guān)的任務(wù)可能根本不需要簿寂,可以直接關(guān)掉,在build.gradle中加入如下腳本:

tasks.whenTaskAdded { task ->
    if (task.name.contains('AndroidTest')) {
        task.enabled = false
    }
}

tasks會獲取當前project中所有的task宿亡,enabled屬性控制任務(wù)開關(guān)常遂,whenTaskAdded后面的閉包會在gradle配置階段完成。

一般我們定義任務(wù)的時候采用的是task + 任務(wù)名的方式挽荠。例如

task hello << {
        println "hello"
}

現(xiàn)在再介紹另外兩種方式克胳,和上面的定義是等價的。

task(hello)<<{
        println "hello"
}
task('hello')<<{
        println "hello"
}

gradle還提供了一個tasks容器來創(chuàng)建任務(wù)圈匆,通過調(diào)用create方法:

tasks.create(name:'hello')<<{
        println "hello"
}

如何獲取一個任務(wù)呢漠另?

將任務(wù)看成項目的屬性的方式
println tasks.hello.name
println tasks['hello'].name

使用tasks容器來定位
println hello.name
println project.hello.name

tasks.getByPath()方式來獲得
println tasks.getByPath('hello').path
println tasks.getByPath(':hello').path

每個Task包含了Action對象的集合。當Task被執(zhí)行的時候跃赚,其內(nèi)部的Action集合會按次序逐個執(zhí)行笆搓,所以借助doFirst(),doLast()等方法來控制Action在隊列中的順序,同時也是執(zhí)行的順序来累。

task testAction {
    doFirst {
        println("first")
    }
    doLast {
        println("last")
    }
}

輸出

first
last

其中對于doLast這個Action還有一個簡便的寫法

task testAction <<{
    println("last")
}

<<就代表doLast操作

task與task之間是有關(guān)聯(lián)的砚作,關(guān)聯(lián)可以使用dependsOn和finalizedBy。

task A <<{
    println("i am task A")
}
task B <<{
    println("i am task B")
}

A.dependsOn B

執(zhí)行g(shù)radlew -q A
輸出:

i am task B
i am task A

如果是 A.finalizedBy B

i am task A
i am task B

相關(guān)鏈接:

Gradle官網(wǎng)https://gradle.org/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘹锁,一起剝皮案震驚了整個濱河市葫录,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌领猾,老刑警劉巖米同,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骇扇,死亡現(xiàn)場離奇詭異,居然都是意外死亡面粮,警方通過查閱死者的電腦和手機少孝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熬苍,“玉大人稍走,你說我怎么就攤上這事〔竦祝” “怎么了婿脸?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長柄驻。 經(jīng)常有香客問我狐树,道長,這世上最難降的妖魔是什么鸿脓? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任抑钟,我火速辦了婚禮,結(jié)果婚禮上野哭,老公的妹妹穿的比我還像新娘在塔。我一直安慰自己,他們只是感情好拨黔,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布心俗。 她就那樣靜靜地躺著,像睡著了一般蓉驹。 火紅的嫁衣襯著肌膚如雪城榛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天态兴,我揣著相機與錄音狠持,去河邊找鬼。 笑死瞻润,一個胖子當著我的面吹牛喘垂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绍撞,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼正勒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了傻铣?” 一聲冷哼從身側(cè)響起章贞,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎非洲,沒想到半個月后鸭限,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜕径,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年败京,在試婚紗的時候發(fā)現(xiàn)自己被綠了兜喻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡赡麦,死狀恐怖朴皆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情泛粹,我是刑警寧澤车荔,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站戚扳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏族吻。R本人自食惡果不足惜帽借,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望超歌。 院中可真熱鬧砍艾,春花似錦、人聲如沸巍举。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽懊悯。三九已至蜓谋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炭分,已是汗流浹背桃焕。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捧毛,地道東北人观堂。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像呀忧,于是被迫代替她去往敵國和親师痕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

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

  • Gradle簡介 Gradle是一個構(gòu)建工具而账,同時它也是一個編程框架胰坟。 當你把Gradle當構(gòu)建工具看的時候,我們...
    Rangethan閱讀 2,319評論 1 8
  • 參考資料:http://gold.xitu.io/post/580c85768ac247005b5472f9htt...
    zhaoyubetter閱讀 10,996評論 0 6
  • 是什么泞辐? 在語法上是基于Groovy語言的(Groovy 是一種基于JVM的敏捷開發(fā)語言腕铸,可以簡單的理解為強類型語...
    千山萬水迷了鹿閱讀 99,558評論 4 122
  • 這篇文章講給大家?guī)韌radle打包系列中的高級用法-自己動手編寫gradle插件惜犀。我們平常在做安卓開發(fā)時,都會在...
    呆萌狗和求疵喵閱讀 15,984評論 22 80
  • 前言 從2013年Google推出Android Studio(后面以AS簡稱)開始狠裹,到現(xiàn)在已經(jīng)歷經(jīng)3年虽界,版本也發(fā)...
    dfqin閱讀 1,836評論 1 3