Gradle學習總結(jié)

本篇主要是個人學習gradle的筆記總結(jié)

一.開始之前

1. 為什么學習Gradle

  • 采用DSL(Domain Specific Language)語言來描述和控制構(gòu)建邏輯。(所謂領(lǐng)域?qū)S谜Z言,其基本思想是“求專不求全”棠笑,不像通用目的語言那樣目標范圍涵蓋一切軟件問題汽抚,而是專門針對某一特定問題的計算機語言夜牡。)
  • 支持Maven或者Ivy的依賴管理。
  • 插件可以提供自己的DSL和API供文件使用拴清。
  • 讓代碼或資源復(fù)用更容易蚜点。
  • 讓創(chuàng)建同一應(yīng)用程序的不同版本變得更加容易滥壕,無論是多個 apk 發(fā)布版本還是同一個應(yīng)用的不同定制版本。

2. 學習條件

由于Android最新推薦的編譯方式是采用Gradle進行編譯朽们,因此我們必須學習Gradle的基本知識克伊, 而Gradle是基于Groovy語法編寫的,因此我們必須了解Groovy語法 华坦,而Groovy又是基于Java語言的愿吹,是java語言的擴展, 所以說只要我們會java語言就可以編寫出Gradle腳本惜姐。

3. 學習目標

A: 學習Groovy基本概念犁跪, 學習Groovy集合, 類歹袁,和閉包語法坷衍。
B: 學習Gradle 基本用法, 能夠編寫task条舔,理解project概念两嘴。
C: 可以理解android的編譯配置。

二.Groovy初探

1. 什么是Groovy

Grovvy是JVM的一個替代語言茵臭, 是指可以用Groovy在Java平臺上進行Java編程,使用方式基本和Java代碼先同钻心,它也是Java的擴展。

2. 開發(fā)環(huán)境配置

http://www.groovy-lang.org/learn.html
配置方式如下:

grovvy1.png

3. Groovy的特性

Groovy松散的java語法允許省略分號和修飾符铅协;除非另指定捷沸,groovy所有內(nèi)容都為public;允許定義簡單腳本狐史,無需定義正規(guī)的class對象痒给;允許省略變量類型。

4. Groovy和java的對比

http://www.groovy-lang.org/differences.html

如下:讀取文件

Path file = Paths.get("/path/to/file");
Charset charset = Charset.forName("UTF-8");
try (BufferedReader reader = Files.newBufferedReader(file, charset)) {      
    String line;
    while ((line = reader.readLine()) != null) { 
       System.out.println(line); 
    }
} catch (IOException e) { 
    e.printStackTrace();
}

can be written like this:

new File('/path/to/file').eachLine('UTF-8') { 
  println it
}

or, if you want a version closer to Java:

new File('/path/to/file').withReader('UTF-8') { 
  reader -> reader.eachLine { 
    println it 
  }
}

5. Groovy集合骏全,閉包苍柏,映射

  1. 范圍 :for (i in 0..4) 將包含的范圍限制在0-4間。
    
  2. 集合姜贡。def coll = ["Groovy", "Java", "Ruby"]   coll << “smalltalk”
    
  3. 映射  def hash = [“name”:”andy”, “vip”:”45”]
    
  4. 閉包  coll.each{ println it}  或 coll.each{value -> println value}
    

如果閉包沒有定義參數(shù)序仙,那么隱含一個參數(shù)it, 和this作用類似鲁豪。

對于閉包的參數(shù)需要查看api文檔潘悼。

6. 類

Groovy類就是java類,初始化時Groovy 自動提供一個構(gòu)造函數(shù)爬橡,構(gòu)造函數(shù)接受一個名稱-值對的映射治唤,這些名稱-值對與類的屬性相對應(yīng)。這是 Groovy 的一項開箱即用的功能 — 用于類中定義的任何屬性糙申,Groovy 允許將存儲了大量值的映射傳給構(gòu)造函數(shù)宾添。還會對成員變量定義get,set方法柜裸,所以可以直接點引用缕陕。

7. 看具體例子。

Demo地址:

Groovy API文檔為: http://www.groovy-lang.org/api.html

三.Groovy深入

1. Groovy和JVM的關(guān)系

除了語言和Java相通外疙挺,Groovy有時候又像一種腳本語言扛邑。當我執(zhí)行Groovy腳本時,Groovy會先將其編譯成Java類字節(jié)碼铐然,然后通過Jvm來執(zhí)行這個Java類蔬崩。

grovvy2.png

實際上,由于Groovy Code在真正執(zhí)行的時候已經(jīng)變成了Java字節(jié)碼搀暑,所以JVM根本不知道自己運行的是Groovy代碼.

2. 腳本和類

既然是基于java來執(zhí)行的沥阳,那我們將groovy轉(zhuǎn)會為java類。

執(zhí)行 groovyc-d classes test.groovy

groovyc是groovy的編譯命令自点,-d classes用于將編譯得到的class文件拷貝到classes文件夾下桐罕。

我們可以看到helloworld.groovy 被轉(zhuǎn)化為java class類,繼承自Script。

Song 類被轉(zhuǎn)化為實現(xiàn)GroovyObject的類功炮,并封裝了get溅潜,set方法。

可以看出死宣, groovy既可以作為類來使用, 又可以作為腳本來使用碴开。

Groovy 腳本的代碼其實都會被放到run函數(shù)中執(zhí)行的毅该。變量作用域,區(qū)分def和不用def定義潦牛, def定義的為run函數(shù)作用域眶掌,無def的為全局屬性,細節(jié)可以看字節(jié)碼巴碗。

3. IO操作

def targetFile = new File(xxx)

targetFile.eachLine{ line ->

    println line

}

直接讀取文件: targetFile.getBytes()

獲取輸入流: def is = targetFile.newInputStream() is.close

閉包輸入流:

targetFile.withInputStream{ is ->

   操作is朴爬, 無需關(guān)閉輸入流, 閉包會自動關(guān)閉橡淆。

}

寫文件:

def srcFile = new File(源文件)

def targetFile = new File(目標文件)

targetFile.withOutputStream{os ->

srcFile.withInputStream{ is ->

    os << is

}

}

這里重載了<< 操作符召噩, 細節(jié)可以查看api文檔,方法名為leftShift

四.Gradle初探

1. 什么是Gradle

用戶手冊:https://docs.gradle.org/current/userguide/userguide.html

API文檔:https://docs.gradle.org/current/javadoc/

DSL手冊:https://docs.gradle.org/current/dsl/

Gradle 是配置編譯腳本逸爵, 也是編程開發(fā)框架具滴。

Gradle 由一個或多個proejct組成, 每一個待編譯的工程都叫一個project师倔,每一個project在構(gòu)建的時候都包含一系列的task构韵。比如一個Android apk的編譯可能包含:java源碼編譯Task,資源編譯Task趋艘,JNI編譯Task疲恢,lint檢查Task, 打包生成APK的task瓷胧,簽名Task等等显拳。一個project到底包含多少Task,其實是由編譯腳本指定的插件決定搓萧。插件就是用來定義Task萎攒,并且具體執(zhí)行這些task的東西。

2. 開發(fā)環(huán)境配置

http://gradle.org/ 下載對應(yīng)的gradle文件到本地矛绘,配置環(huán)境變量即可耍休。

GRADLE_HOME=/Users/zhangyuqiang/work/soft/gradle-2.2.1;

加到~/.bash_profile 中, export GRADLE_HOME即可.

下面Demo地址:https://github.com/davenkin/gradle-learning

3. Task

Task是gradle中的一種數(shù)據(jù)類型,它代表了一些藥執(zhí)行或者要干的工作货矮。每一個task都要和一個project關(guān)聯(lián)羊精。

創(chuàng)建一個task

task hello {

 doLast{

    println “hello gradle”

 }

}

或者

task hello << {

   println “hello gradle”

}

參考Demo: 2-define-task, 3-undertand-gradle-syntax,

4. Project

每一個build.gradle 就是一個project。一個project中會有一個或多個task喧锦。

5. 屬性

(Demo: 5-define-custom-properties)

gradle 的project中會有一些默認的屬性读规,可以理解為類的成員變量,我們還可以給project增加一些額外屬性燃少, 通過ext束亏。

6. 依賴關(guān)系

(Demo: 7-dependency-management, 8-multi-project)
project依賴可以通過dependencies{}來設(shè)置依賴,task依賴可以通過dependsOn 來設(shè)置阵具。

7. Multi-Project組織

(Demo: 8-multi-project)

多project管理碍遍,主要依靠settings.gradle ,在該文件中include 需要編譯的模塊名即可阳液∨戮矗可以在該文件中增加函數(shù),如initGradleEnvironment()帘皿,這些函數(shù)會在gradle構(gòu)建整個工程任務(wù)的時候執(zhí)行东跪。其實include也是函數(shù)。

8. Gradle命令

gradle projects

gradle tasks

gradle taskname 執(zhí)行任務(wù)

gradle clean, assembleDebug, aR, build …

五.Gradle深入

1. Gradle工作流程

gradle1.png

首先是初始階段鹰溜,對于multi-project而言虽填,就是settings.gradle配置執(zhí)行。

其次是配置階段曹动,該階段解析每個project中的build.gradle卤唉。這兩個階段我們可以增加hook進來,執(zhí)行相關(guān)任務(wù)仁期。

最后是執(zhí)行階段桑驱,執(zhí)行完成后我們也可以增加hook。

Gradle基于groovy跛蛋,所以編譯執(zhí)行時gradle也會把腳本轉(zhuǎn)化為java對象熬的。

Gradle中主要有三種對象, 這三種對象和三種不同的腳本文件對應(yīng)赊级, 在Gradle執(zhí)行的時候押框,會將腳本轉(zhuǎn)化成對應(yīng)的對象,分別為Gradle對象理逊,Project對象橡伞,Settings對象。

2. Gradle編程模型及生命周期

https://docs.gradle.org/current/userguide/build_lifecycle.html

3. Gradle對象

當我們執(zhí)行g(shù)radle xxx時晋被,Gradle會從默認的配置腳本中構(gòu)造出一個Gradle對象兑徘, 在整個執(zhí)行過程中只有這么一個對象, Gradle對象的數(shù)據(jù)類型就是Gradle羡洛。我們一般很少去定制這個腳本

4. Settings對象

settings.gradle 會被轉(zhuǎn)化為一個Settings對象挂脑。

5. Project對象

每個build.gradle 都會轉(zhuǎn)化為一個Project對象。由于project對應(yīng)到具體工程, 因此要為project加載對應(yīng)的插件崭闲。其實每一個project具體包含多少個task是由插件決定的肋联。

6. 代理機制

Gradle大量地使用了Groovy閉包的delegate機制。簡單來說刁俭,delegate機制可以使我們將一個閉包中的執(zhí)行代碼的作用對象設(shè)置成任意其他對象橄仍。3-undertand-gradle-syntax。

apply方法牍戚, 使用: apply plugin: ‘com.android.library’, 如果編譯lib侮繁,則使用此插件, 也可以加載一個gradle文件,如: apply from : ‘utils.gradle’翘魄。

此處可以utils.gradle定義的屬性和方法鼎天。為什么可以使用呢舀奶? 我們知道gradle和groovy一樣暑竟,每個腳本都繼承自Script。utils.gradle 也會被轉(zhuǎn)化為一個Script對象育勺, Script對象中有一個delegate對象但荤, 在apply函數(shù)中有個from參數(shù),還有個to參數(shù)涧至, 通過to參數(shù)可以將delegate對象指向別的東西腹躁,這里即utils 的Scrpit類, 當你在自己的Script中操作一些不是自己定義的變量或者函數(shù)時南蓬,gradle會到Script的delegate對象中去找纺非。

7. BuildScriptBlock

gradle2.png

六.Android中g(shù)radle基本配置

https://developer.android.com/intl/zh-cn/tools/building/plugin-for-gradle.html

http://google.github.io/android-gradle-dsl/current/

1. 插件

gradle3.png

2. 各Script配置

android中的BuildScriptBlock

gradle4.png

3. gradle命令及依賴配置

依賴配置有:模塊依賴,本地依賴赘方,遠程依賴烧颖。

gradle5.png

命令:頂級命令有4個

  assemble  Builds the project output.

  Check  Runs checks and tests.

  Build   Runs both assemble and check.

  Clean  Performs the clean

常用的有g(shù)radle assembleDebug 編譯debug包。

Gradle assembleRelease, 編譯release包窄陡, 縮寫為gradle aR.

4. multi-dex 配置

https://developer.android.com/intl/zh-cn/tools/building/multidex.html

七.Android中g(shù)radle的高級配置

1. 構(gòu)建變種版本-BuidVariant炕淮。

構(gòu)建類型+定制產(chǎn)品=構(gòu)建變種版本

BuildType + ProductFlavor 任何一種組合都會是一個版本。

http://wiki.jikexueyuan.com/project/android-gradle-guide/build-variants.html

BuildType : 可以分為debug, release, publish , product, demo 等等跳夭。

ProductFlavor:可自定義為flavor1涂圆,flavor2…

android {
        ...

        defaultConfig {
            minSdkVersion 8
            versionCode 10
        }

        productFlavors {
            flavor1 {
                packageName "com.example.flavor1"
                versionCode 20
            }

            flavor2 {
                packageName "com.example.flavor2"
                minSdkVersion 14
            }
        }
    }
每一個Variant也會創(chuàng)建額外的sourceSet:
android.sourceSets.flavor1Debug
 位于src/flavor1Debug/
android.sourceSets.flavor1Release
 位于src/flavor1Release/
android.sourceSets.flavor2Debug
 位于src/flavor2Debug/
android.sourceSets.flavor2Release
 位于src/flavor2Release/

這些sourceSet擁有比Build Type的sourceSet更高的優(yōu)先級,并允許在Variant的層次上做一些定制币叹。

2. 高級構(gòu)建選項

  android {
        aaptOptions {
            noCompress 'foo', 'bar'
            ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
        }
    }

aapt操作配置將應(yīng)用到所有task上润歉。

3. 操作Task

Android項目中會有大量的task, 并且他們基于buildType和productFlavor生成的task颈抚, 從而我們直接引用到該task的編譯成java后的class卡辰,為了解決該問題, android對象提供了三個Collection屬性:

applicationVariants(只適用于app plugin)

libraryVariants(只適用于library plugin)

testVariants(兩個plugin都適用)

這三個collection中的任意一個都會觸發(fā)生成所有對應(yīng)的task。

android.applicationVariants.each { variant ->
        ....
    }

http://wiki.jikexueyuan.com/project/android-gradle-guide/advanced-build-customization.html

通過這些變量和方法可定制對應(yīng)的功能九妈。

官方詳細文檔:http://tools.android.com/tech-docs/new-build-system/user-guide

八.Gradle自定義Task和Plugin

Gradle本身只是一個架子反砌,真正起作用的是Task和Plugin。要真正了解Task和Plugin的工作機制并熟練運用萌朱,學會自定義Task類型和Plugin是大有裨益的宴树。

1. 自定義Task。

Gradle中的Task要么是由不同的Plugin引入的晶疼,要么是我們自己在build.gradle文件中直接創(chuàng)建的酒贬。在默認情況下,我們所創(chuàng)建的Task是DefaultTask類型翠霍,該類型是一個非常通用的Task類型锭吨,而在有些時候,我們希望創(chuàng)建一些具有特定功能的Task寒匙,比如Copy和Jar等零如。

Demo: 9-custom-task, 分為三部分,1锄弱,在build.gradle中直接定義Task考蕾,2.在當前工程中定義Task,3.在單獨的項目中定義Task会宪,將其上傳maven庫中肖卧,其他項目來引用。

2. 自定義Plugin掸鹅。

在Plugin中塞帐,我們可以向Project中加入新的Task,定義configurations和property等巍沙。我們3種方法可以自定義Plugin葵姥,這些方法和自定義Task類型的3種方法相似。

Demo:10-custom-plugin 每一個自定義的Plugin都需要實現(xiàn)Plugin<T>接口赎瞎,事實上牌里,除了給Project編寫Plugin之外,我們還可以為其他Gradle類編寫Plugin务甥。該接口定義了一個apply()方法牡辽,在該方法中,我們可以操作Project敞临,比如向其中加入Task态辛,定義額外的Property等。

九.通過Gradle發(fā)布jar,aar,plugin到JCenter和Maven Central

1. 發(fā)布到j(luò)center中

http://www.cnblogs.com/qianxudetianxia/p/4322331.html

2. 發(fā)布到maven central

http://my.oschina.net/specialcyci/blog/371352#OSC_h3_2

3. 發(fā)布到本地maven庫


apply plugin:‘maven’

uploadArchives{

repositories.mavenDeployer{

   repository(url: ‘file:../lib’)

}

}

使用時

buildScript{

       repositories{

maven{

  url ‘file:../lib’}}}

十. 新的構(gòu)建方案

  1. facebook buck https://buckbuild.com/
    
  2. http://www.voidcn.com/blog/u014077888/article/p-4146683.html
    

十一. 例子

helloworld.groovy


//1. 打印helloworld
println 'helloworld'
//2. 類型定義
def value = "hello"
println value
//3. 查看類型是什么
println value.class
def value1 = 4
println value1.class 
def value2 = 'a'
println value2.class
 

//4. groovy for循環(huán),int無需定義類型
def repeat(val) {
   /*for(i = 0; i < 5; i++) {
      println val;
   }*/
   //groovy中的范圍, 0..5 是一個集合
   /*for(i in 0..5) {
      println val;
   }*/
   //將范圍改為排除
   for(i in 0..<5) {
      println val
   }
}
repeat("helloworld")

//5. 默認參數(shù)
def repeat1(val, repeat=5) {
   for(i in 0..<repeat) {
      println val
   }
}
repeat1("hello", 3)
repeat1("world")

//6. groovy 集合
def coll = ["Groovy", "Java", "Ruby"]
println coll.class
assert  coll instanceof Collection
assert coll instanceof ArrayList

//7. 插入符號, 集合操作挺尿。
coll.add("Python")
coll << "Smalltalk"
coll[5] = "Perl"

println coll
//8. * 操作符
def upper = ["Java", "Groovy"]*.toUpperCase()
println upper

//9. 映射
def hash = [name:"Andy", "VPN-#":45]
assert hash.getClass() == java.util.LinkedHashMap

hash.put("id", 23)
assert hash.get("name") == "Andy"

//或者用. 設(shè)置 奏黑,讀取
hash.dob = "01/29/76"

println hash.name
println hash['name']
println hash

//11. 閉包
coll.each{ println it}
coll.each{name -> 
   println name
}

//12. 定義閉包
def excite = {word ->
   return "${word}!!!"
}

println excite('helloworld')

//默認參數(shù)為it
def greeting = { "Hello, ${it}!" }
println greeting('hello')

//當函數(shù)的最后一個參數(shù)是閉包的話炊邦,可以省略()
def testClosure(int a1, String b1, Closure closure) {
   closure() //調(diào)用閉包
}

testClosure(3, "test", {
   println 'I am a closure'
   })
//如android gradle中的
/*doLast({
   println'Hello world!'
})*/

///////groovy 深入//////

//查看變量作用范圍
//run作用域
/*def x = 1
def printx() {
   println x
}

printx()
*/

//全局作用域
y = 1
def printy() {
   println y
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市熟史,隨后出現(xiàn)的幾起案子馁害,更是在濱河造成了極大的恐慌,老刑警劉巖蹂匹,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碘菜,死亡現(xiàn)場離奇詭異,居然都是意外死亡限寞,警方通過查閱死者的電腦和手機忍啸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來履植,“玉大人计雌,你說我怎么就攤上這事∶钓” “怎么了凿滤?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鼠渺。 經(jīng)常有香客問我鸭巴,道長眷细,這世上最難降的妖魔是什么拦盹? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮溪椎,結(jié)果婚禮上普舆,老公的妹妹穿的比我還像新娘。我一直安慰自己校读,他們只是感情好沼侣,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著歉秫,像睡著了一般蛾洛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上雁芙,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天轧膘,我揣著相機與錄音,去河邊找鬼兔甘。 笑死谎碍,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的洞焙。 我是一名探鬼主播蟆淀,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼拯啦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了熔任?” 一聲冷哼從身側(cè)響起褒链,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疑苔,沒想到半個月后碱蒙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡夯巷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年赛惩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趁餐。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡喷兼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出后雷,到底是詐尸還是另有隱情季惯,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布臀突,位于F島的核電站勉抓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏候学。R本人自食惡果不足惜藕筋,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梳码。 院中可真熱鬧隐圾,春花似錦、人聲如沸掰茶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽濒蒋。三九已至盐碱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沪伙,已是汗流浹背瓮顽。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留焰坪,地道東北人趣倾。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像某饰,于是被迫代替她去往敵國和親儒恋。 傳聞我的和親對象是個殘疾皇子善绎,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

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