要點(diǎn)提煉| Gradle指南

在使用Android Studio過(guò)程中沒(méi)少被Gradle坑過(guò)藐石,雖然網(wǎng)上有很多簡(jiǎn)單粗暴的解決方案,但極少會(huì)說(shuō)清楚緣由梅割,所以一直想看一本叫《Android Gradle權(quán)威指南》扇调。
不過(guò)由于書(shū)中實(shí)踐內(nèi)容很多,更像一本工具書(shū)沪伙,而且Gradle現(xiàn)已發(fā)行了好幾版,因此本篇僅僅是陳列出一些大的要點(diǎn)县好,尤其是那些熟悉又陌生的名詞围橡,如果想要具體了解細(xì)節(jié)和操作流程,一定要跟著書(shū)探索喲~

  • Gradle入門(mén)
  • Groovy基礎(chǔ)
  • Gradle構(gòu)建腳本基礎(chǔ)
  • Gradle插件
  • Java Gradle插件
  • Android Gradle插件

一.Gradle入門(mén)

1.本書(shū)環(huán)境

  • JDK:OpenJDK 1.8.0
  • Gradle:Gradle 2.14.1 All 版
  • IDE:Android Studio 2.2.3
  • Android Plugin:Android Gradle 2.2.3
  • Android:API 23

2.Eclipse和Android Studio

a.開(kāi)發(fā)配置區(qū)別

  • Eclipse+ADT+Ant
  • Android Studio+Gradle:Gradle比Ant更靈活缕贡,有效提高開(kāi)發(fā)效率

b.Eclipse遷移到AndroidStudio兩種方式

  • 使用AndroidStudio直接導(dǎo)入Eclipse工程
    • 特點(diǎn):使用AS默認(rèn)推薦目錄結(jié)構(gòu)
  • 使用Eclipse導(dǎo)出Android Gradle配置文件翁授,并轉(zhuǎn)換成Gradle工程,再使用Android Studio把它作為Gradle工程導(dǎo)入
    • 特點(diǎn):保留原項(xiàng)目結(jié)構(gòu)

3.Gradle的ZIP解壓后目錄

  • docs:API晾咪、 DSL收擦、指南等文檔
  • init.d:gradle初始化腳本目錄
  • lib:相關(guān)庫(kù)
  • media:一些icon資源
  • samples:示例
  • src:源文件
  • getting-started.html:入門(mén)鏈接
  • LICENSE
  • NOTICE


4.引例:Gradle版Hello World

//build.gradle:
    task hello{//定義一個(gè)任務(wù)Task名為hello
        doLast{//添加一個(gè)動(dòng)作Action,表示在Task執(zhí)行完畢后回調(diào)doLast閉包中的代碼
            println'Hello World'//輸出字符串谍倦,單雙號(hào)均可
        }
    }
//終端:
    gradle hello//執(zhí)行build.gradle中名為Hello的任務(wù)
//輸出:
    Hello World

5.Gradle Wrapper

a.含義:對(duì)Gradle一層包裝炬守,便于使用統(tǒng)一Gradle構(gòu)建

b.目錄結(jié)構(gòu):

|--gradle
|   |--wrapper
|        |--gradle-wrapper.jar
|        |--gradle-wrapper.properties
|--gradlew
|--gradlew.bat
  • gradle-wrapper.jar:具體業(yè)務(wù)邏輯實(shí)現(xiàn)的jar包
  • gradle-wrapper.properties:配置文件,包含篇配置信息如下圖:
  • gradlew:Linux下可執(zhí)行腳本
  • gradlew.bat:Windows下可執(zhí)行腳本

c.常用命令

  • 生成:gradle wrapper剂跟,由Wrapper Task生成
  • 配置參數(shù):
    • gradle wrapper --gradle-version XXX用于指定使用的Gradle版本
    • gradle wrapper --distribution-url XXX用于指定下載Gradle發(fā)行版的url地址
  • 自定義:task wrapper(type:Wrapper){ //配置信息 }

6.Gradle日志

a.日志級(jí)別


b.日志輸出代碼

  • 使用print方法,屬于quiet級(jí)別日志:println 'XX'X
  • 使用內(nèi)置logger:

    c.日志輸出控制

    例如酣藻,輸出QUIET級(jí)別及其之上的日志信息:gradle -q tasks

7.Gradle命令行

  • 查看所有可執(zhí)行tasks:./gradlew tasks
  • 強(qiáng)制刷新依賴(lài):./gradlew --refresh-dependencies assemble
  • 多任務(wù)調(diào)用:./gradlew clean jar
  • 查看幫助:./gradlew -?./gradlew -h./gradlew -help

二.Groovy基礎(chǔ)

一句話表明Groovy的地位:Groovy于Gradle曹洽,好比Java于Android

1.特性:Groovy是個(gè)靈活的動(dòng)態(tài)腳本語(yǔ)言,語(yǔ)法和Java很相似辽剧,又兼容Java送淆,且在此基礎(chǔ)上增加了很多動(dòng)態(tài)類(lèi)型和靈活的特性,如支持閉包和DSL

2.語(yǔ)法

  • 分號(hào)不必需
  • 字符串:?jiǎn)我?hào)和雙引號(hào)均可定義一個(gè)字符串常量怕轿,區(qū)別在于單引號(hào)不能對(duì)字符串表達(dá)式做運(yùn)算偷崩,而雙引號(hào)可以
task printStringVar << {
    def name = "張三”
    println '單引號(hào)的變量計(jì)算:${name}'
    println "雙引號(hào)的變量計(jì)算:${name}"
}
運(yùn)行./gradlew printStringVar輸出結(jié)果:
單引號(hào)的變量計(jì)算:${name}
雙引號(hào)的變量計(jì)算:張三
  • 集合:以List和Map為例辟拷,介紹如何定義集合和訪問(wèn)集合元素
//List
task printList<<{
      def numList = [1,2,3,4,5,6];//定義一個(gè)List

      println numList[1]//輸出第二個(gè)元素
      println numList[-1]//輸出最后一個(gè)元素
      println numList[1..3]//輸出第二個(gè)到第四個(gè)元素
      numList.each{
          println it//輸出每個(gè)元素
      }
}
//Map
task printlnMap<<{
    def map1 =['width':1024,'height':768]//定義一個(gè)Map
    
    println mapl['width']//輸出width的值
    println mapl.height//輸出height的值
    map1.each{
        println "Key:${it.key},Value:${it.value}"http://輸出所有鍵值對(duì)
    }
}

  • 方法:方法調(diào)用傳參的括號(hào)可省略;return不必需阐斜,無(wú)return時(shí)會(huì)將最后一行代碼作為其返回值衫冻;允許將代碼塊(閉包)作為參數(shù)傳遞
//以集合的each方法為例,接受的參數(shù)就是一個(gè)閉包
numList.each({println it})
//省略傳參的括號(hào)谒出,并調(diào)整格式隅俘,有以下常見(jiàn)形式
numList.each{
    println it
}
  • 不是一定要定義成員變量才能作為類(lèi)屬性被訪問(wèn),用get/set方法也能當(dāng)作類(lèi)屬性
task helloJavaBean<<{
      Person p = new Person()
      p.name = "張三"
      println "名字是: ${p.name}"http://輸出類(lèi)屬性name笤喳,為張三
      println "年齡是: ${p.age}"http://輸出類(lèi)屬性age为居,為12
}
class Person{
      private String name
      public int getAge(){//省略return
          12
      }
}
  • 閉包:當(dāng)閉包有一個(gè)參數(shù)時(shí),默認(rèn)為it杀狡,多個(gè)參數(shù)時(shí)需要一一羅列
//單個(gè)參數(shù)
task helloClosure<<{
    customEach{
        println it
    }
}
def customEach(closure){
    for(int i in 1..10){
        closure(i)
    }
}
//多個(gè)參數(shù)
task helloClosure<<{
    eachMap{k,v->
        println "${k} is ${v}"
    }
}
def eachMap(closure){
    def map1 = ["name":"張三","age":18]
    map1.each{
        closure(it.key,it.value)
    }
}

三.Gradle構(gòu)建腳本基礎(chǔ)

1.Settings文件

  • 作用:初始化蒙畴、設(shè)置工程樹(shù)
  • 文件名settings.gradle,放在Project下
  • 常用方法:include方法指定能被Gradle識(shí)別的Module
//添加:app和:common這兩個(gè)module參與構(gòu)建
include ':app'
project(':app').projectDir = new File('存放目錄')
include':common'
project(':common').projectDir = new File('存放目錄')

2.Build文件

  • Project的build.gradle:整個(gè)Project的共有屬性呜象,包括配置版本膳凝、插件、依賴(lài)庫(kù)等信息
  • Module的build.gradle:各個(gè)module私有的配置文件

3.Gradle任務(wù)

a.含義:指原子性操作

b.關(guān)系:一個(gè)Gradle可包含多個(gè)Project董朝,一個(gè) Project可包含多個(gè)Task鸠项,即每個(gè)Project是由多個(gè)Task組成的;Task是Project的屬性子姜,屬性名就是任務(wù)名

c.創(chuàng)建

  • 以任務(wù)名創(chuàng)建:接受一個(gè)name參數(shù)
def task myTask = task(myTask)
myTask.doLast{
    println "第一種創(chuàng)建Task方法祟绊,原型為T(mén)ask task(String name) throws InvalidUserDataException"
}
  • 以任務(wù)名+Map創(chuàng)建:Map參數(shù)用于對(duì)創(chuàng)建的task進(jìn)行配置,可用配置如下圖


def task myTask = task(myTask,group:BasePlugin.BUILD_GROUP)
myTask.doLast{
    println "第二種創(chuàng)建Task方法哥捕,原型為T(mén)ask task(String name,Map<String,?> args) throws InvalidUserDataException"
}
  • 以任務(wù)名+閉包創(chuàng)建:常見(jiàn)形式
task myTask{
    doLast{
        println "第三種創(chuàng)建Task方法牧抽,原型為T(mén)ask task(String name,Closure configureClosure)"
    }
}

以上創(chuàng)建方式實(shí)際上最終都會(huì)調(diào)用TaskContainter#create()方法,使用./gradlew myTask命令執(zhí)行任務(wù)

d.訪問(wèn)

  • 通過(guò)任務(wù)名訪問(wèn):名稱(chēng).方法
  • 通過(guò)TaskContainter訪問(wèn):tasks['名稱(chēng)'].方法
  • 通過(guò)路徑訪問(wèn):參數(shù)可以為路徑或名稱(chēng)
    • get方式:tasks.getByPath('路徑/名稱(chēng)')遥赚,若不存在會(huì)拋出UnknownTaskException異常
    • find方式:tasks.findByPath('路徑/名稱(chēng)')扬舒,若不存在返回null
  • 通過(guò)名稱(chēng)訪問(wèn):參數(shù)只能為名稱(chēng)
    • get方式:tasks.getByName('名稱(chēng)'),若不存在會(huì)拋出UnknownTaskException異常
    • find方式:tasks.findByName('名稱(chēng)')凫佛,若不存在返回null

可見(jiàn)任務(wù)名稱(chēng)是唯一的讲坎,這是因?yàn)門(mén)askContainer的父類(lèi) NamedDomainObjectCopllection是個(gè)具有唯一不變名字的域?qū)ο蟮募?/p>

e.依賴(lài):在創(chuàng)建任務(wù)時(shí)通過(guò)dependsOn指定其依賴(lài)的任務(wù),可以控制任務(wù)的執(zhí)行順序

task task1<<{
    println 'hello'
}
task task2<<{
    println 'world'
}
//依賴(lài)單個(gè)任務(wù)
task task3(dependsOn:task1){
    doLast{
        println 'one'
    }
}
//依賴(lài)多個(gè)任務(wù)
task task4{
    dependsOn task1,task2
    doLast{
        println 'two'
    }
}

當(dāng)執(zhí)行task4時(shí)愧薛,會(huì)發(fā)現(xiàn)task1晨炕、task2會(huì)先執(zhí)行,再執(zhí)行task4

注:操作符<< 用在Task定義上相當(dāng)于doLast

f.排序:除了通過(guò)強(qiáng)依賴(lài)來(lái)控制任務(wù)的執(zhí)行順序毫炉,還可以通過(guò) shouldRunAftermustRunAfter 實(shí)現(xiàn)

taskB.shouldRunAfter(taskA) //表示taskB應(yīng)該在taskA執(zhí)行之后執(zhí)行瓮栗,有可能不會(huì)按預(yù)設(shè)執(zhí)行
taskB.mustRunAfter(taskA) //表示taskB必須在taskA執(zhí)行之后執(zhí)行

g.分組& 描述:分組是對(duì)任務(wù)的分類(lèi),便于歸類(lèi)整理;描述是說(shuō)明任務(wù)的作用费奸;建議兩個(gè)一起配置弥激,便于快速了解任務(wù)的分類(lèi)和用途

def task myTask = task(myTask)
myTask .group = BasePlugin.BUILD_GROUP
myTask .description = '這是一個(gè)構(gòu)建的引導(dǎo)任務(wù)'

h.啟用 & 禁用:enable屬性可以啟動(dòng)和禁用任務(wù),執(zhí)行被禁用的任務(wù)輸出提示該任務(wù)被跳過(guò)

def task myTask = task(myTask)
myTask.enable = false //禁用任務(wù)

i.執(zhí)行分析:執(zhí)行Task的時(shí)候?qū)嶋H上是執(zhí)行其擁有的actions List愿阐,它是Task對(duì)象實(shí)例的成員變量微服;在創(chuàng)建任務(wù)時(shí)Gradle會(huì)解析其中被TaskAction注解的方法作為其Task執(zhí)行的action,并添加到 actions List换况,其中doFirst和doList會(huì)被添加到action List第一位和最后一位

4.自定義屬性

Project职辨、Task和SourceSet都允許用戶添加額外的自定義屬性、并對(duì)自定義屬性進(jìn)行讀取和設(shè)置

  • 方式:通過(guò)ext屬性戈二,添加多個(gè)通過(guò)ext代碼塊
  • 優(yōu)點(diǎn):相比局部變量有廣泛的作用域舒裤,可以跨Project、跨Task訪問(wèn)觉吭,只要能訪問(wèn)這些屬性所屬的對(duì)象即可
//給Project添加自定義屬性
ext.age = 18
ext{
    phone = 13888888888
    address = 'Beijing'
}
//給Task添加自定義屬性
task customProperty {   
    ext.inner = 'innnnnner'                 
                    
    doLast{
        println project.hasProperty('customProperty') //true
        println project.hasProperty('age') //true
        println project.hasProperty('inner')//返回fasle
                
        println "${age}"
        println "${phone}"
        println "${inner}"
    }
}

四.Gradle插件

1.作用

  • 可以添加任務(wù)到項(xiàng)目腾供,比如測(cè)試、編譯鲜滩、打包等
  • 可以添加依賴(lài)配置到項(xiàng)目伴鳖,幫助配置項(xiàng)目構(gòu)建過(guò)程中需要的依賴(lài),比如第三方庫(kù)等
  • 可以向項(xiàng)目中現(xiàn)有的對(duì)象類(lèi)型添加新的擴(kuò)展屬性和方法等徙硅,幫助配置和優(yōu)化構(gòu)建
  • 可以對(duì)項(xiàng)目進(jìn)行一些約定榜聂,比如約定源代碼存放位置等

Gradle本身內(nèi)置許多常用的插件,如若需要還可以擴(kuò)展現(xiàn)有插件或者自定義插件嗓蘑,如Android Gradle插件就是基于內(nèi)置的Java插件實(shí)現(xiàn)的

2.擴(kuò)展現(xiàn)有插件

a.插件種類(lèi)

  • 二進(jìn)制插件:實(shí)現(xiàn)org.gradle.api.Plugin接口的插件须肆,可以有plugin id
  • 腳本插件:嚴(yán)格上只是一個(gè)腳本,可以來(lái)自本地或網(wǎng)路

b.應(yīng)用插件:通過(guò)Project#apply()方法桩皿,有三種用法

  • Map參數(shù):void apply (Map<String, ?> options)
    • 二進(jìn)制插件:
      • id:apply plugin:'java'
      • 類(lèi)型:apply plugin:org.gradle.api.plugins.JavaPlugin
      • 簡(jiǎn)寫(xiě):apply plugin:JavaPlugin
    • 腳本插件:apply from:'version.gradle'
    • 第三方發(fā)布插件:apply plugin:'com.android.application'

注意:應(yīng)用第三方發(fā)布的作為jar的二進(jìn)制插件時(shí)豌汇,必須先在buildscript{}配置其classpath才能使用,否則會(huì)提示找不到該插件

//buildscript:為項(xiàng)目進(jìn)行前提準(zhǔn)備和初始化相關(guān)配置依賴(lài)
buildscript {
    repositories {
        jcenter ()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0"
    }
}
apply plugin:'com.android.application
  • 閉包:void apply (Closure closure)
apply {
    plugin:'java'
}
  • Action:void apply (Action<? super ObjectConfigurationActicn> action)

3.自定義插件:實(shí)現(xiàn)Plugin接口泄隔、重寫(xiě)apply()方法


五.Java Gradle插件

1.項(xiàng)目結(jié)構(gòu)

使用Java插件要先應(yīng)用進(jìn)來(lái):

apply plugin:'java'

此時(shí)會(huì)添加許多默認(rèn)設(shè)置和約定拒贱,比如有以下默認(rèn)項(xiàng)目結(jié)構(gòu):

|-example
|  |-build.gradle
|  |-src
|    |-main
|       |-java  源代碼存放目錄
|       |-resources  打包文件存放目錄
|    |-test
|       |-java 單元測(cè)試用例存放目錄
|       |-resources 單元測(cè)試中使用的文件

2.源集(SourceSet)

  • 作用:用于描述和管理源代碼(java)及其資源(resources),如訪問(wèn)源代碼目錄佛嬉、設(shè)置源集屬性逻澳、更改Java原代碼目錄等
  • 方式:通過(guò)sourceSets屬性(是一個(gè)SourceSetsContainer)和sourceSets{}閉包
  • 常用屬性

比如,在上述Java插件默認(rèn)項(xiàng)目結(jié)構(gòu)中的main和test就是內(nèi)置的兩個(gè)源集暖呕,現(xiàn)在更改main源集的Java源文件的存放目錄到src/java下:

apply plugin:'java'
sourceSets{
    main{
        java{
            srcDir 'src/java'
        }
    }
}
  • 定義新源集:通過(guò)sourceSets{}閉包添加
apply plugin:'java'
sourceSets{
    vip{
    }
}

此時(shí)會(huì)新建兩個(gè)目錄:src/vip/java和src/vip/resources

補(bǔ)充:除了SourceSet斜做,Java插件里常用的其他屬性:

3.配置第三方依賴(lài)

a.依賴(lài)方式

  • 外部依賴(lài):依賴(lài)外部倉(cāng)庫(kù),如Maven缰揪、Ivy等
  • 項(xiàng)目依賴(lài):依賴(lài)項(xiàng)目,依賴(lài)后可以使用該項(xiàng)目的Java類(lèi)
  • 文件依賴(lài):如依賴(lài)Jar包,出于安全考慮不發(fā)布到Maven而是放在項(xiàng)目的libs文件夾下

b.具體方法

  • 對(duì)于外部依賴(lài)钝腺,需要先在repositories{}閉包里聲明依賴(lài)庫(kù)的位置
  • dependencies{}閉包添加依賴(lài)
    • 外部依賴(lài):說(shuō)明依賴(lài)庫(kù)的group:name:version
    • 項(xiàng)目依賴(lài):project('項(xiàng)目名稱(chēng)')
    • 文件依賴(lài):files('文件名稱(chēng)')抛姑,多個(gè)文件逗號(hào)分開(kāi),或者fileTree(dir:'文件名稱(chēng)',include:'*.擴(kuò)展名稱(chēng)')依賴(lài)指定文件夾下指定擴(kuò)展名文件
  • 幾種依賴(lài)類(lèi)型


舉例:

apply plugin:'java'
repositories {
    //外部依賴(lài) 依賴(lài)Maven中心庫(kù)
    maveCentral() 
}
dependencies {
    //外部依賴(lài) 完整寫(xiě)法
    compile group:'com.squareup.okhttp3',name:'okhttp', version:'3.0.1'   
    //外部依賴(lài) 簡(jiǎn)單寫(xiě)法
    compile 'com.squareup.okhttp3:okhttp:3.0.1'    
    //外部依賴(lài) 指定main源集依賴(lài)
    mainCompile 'com.squareup.okhttp3:okhttp:3.0.1'   
    //項(xiàng)目依賴(lài)
    compile project(':example')    
    //文件依賴(lài) 依賴(lài)libs下兩個(gè)Jar包
    compile files('libs/example01.jar', 'libs/example02.jar')   
    //文件依賴(lài) 指定依賴(lài)libs下所有Jar包
    compile fileTree(dir: 'libs',include: '*.jar')
}

4.內(nèi)置任務(wù)

常用幾種任務(wù):

  • build任務(wù):構(gòu)建項(xiàng)目
  • clean任務(wù):刪除build目錄及構(gòu)建生成的文件
  • assemble任務(wù):不執(zhí)行單元測(cè)試艳狐,只編譯和打包
  • check任務(wù):只執(zhí)行單元測(cè)試
  • javadoc任務(wù):生成Java格式的doc api文檔

還有些通用任務(wù)定硝、對(duì)源集適用的任務(wù):


5.多項(xiàng)目構(gòu)建

  • 含義:多個(gè)Gradle項(xiàng)目一起構(gòu)建
  • 方式:通過(guò)settings.gradle配置管理多項(xiàng)目;在每個(gè)項(xiàng)目都有一個(gè)build.gradle毫目,采用項(xiàng)目依賴(lài)就能實(shí)現(xiàn)多項(xiàng)目協(xié)作
//settings.gradle
include ':app'
project(':app').projectDir = new File('存放目錄')
include ':base'
project(':base').projectDir = new File('存放目錄')

//app/build.gradle
apply plugin:'java'
dependencies {
    compile project(':base')    
}

6.發(fā)布構(gòu)件

  • 構(gòu)件:Gradle構(gòu)建的產(chǎn)物蔬啡,如Jar包、Zip包等
  • 意義:發(fā)布構(gòu)建給其他工程使用镀虐,可以發(fā)布到本地目錄箱蟆、Maven、Ivy等
  • 方式:明確構(gòu)件類(lèi)型刮便,并通過(guò)artifacts{}閉包配置需要發(fā)布的構(gòu)建空猜,在uploadArchives{}上傳發(fā)布構(gòu)件
//以發(fā)布jar構(gòu)件為例
apply plugin:'java '
task publishJar(type:Jar)
artifacts{
    archives publishJar
}
uploadArchives{
    repositories{
        //發(fā)布到本地目錄
        flatDir{
            name 'libs'
            dirs "$projectDir/libs"
        }
        //發(fā)布到本地Maven庫(kù)
        mavenLocal()
    }
}

六.Android Gradle插件

1.概述

Android Gradle插件繼承于Java插件,具有Java插件的所有特性恨旱,也有自己的特性辈毯,看下官方介紹:

  • 可以很容易地重用代碼和資源
  • 可以很容易地創(chuàng)建應(yīng)用的衍生版本
  • 可以很容易地配置、擴(kuò)展以及自定義構(gòu)建過(guò)程
  • 和IDE無(wú)縫整合

2.插件分類(lèi)

  • App應(yīng)用工程:生成可運(yùn)行apk應(yīng)用搜贤;id: com.android.application
  • Library庫(kù)工程:生成aar包給其他的App工程公用谆沃;id: com.android.library
  • Test測(cè)試工程:對(duì)App應(yīng)用工程或Library庫(kù)工程進(jìn)行單元測(cè)試;id: com.android.test

3.項(xiàng)目結(jié)構(gòu)

|-example
|  |-build.gradle
|  |-example.iml
|  |-libs
|  |-proguard-rules.pro  混淆配置文件
|  |-src
|    |-androidTest
|       |-java  Android單元測(cè)試代碼
|    |-main
|       |-java  App主代碼
|       |-res   資源文件
|       |-AndroidManifest.xml  配置文件
|    |-test
|       |-java 普通單元測(cè)試代碼

4.內(nèi)置任務(wù)

  • Java插件內(nèi)置任務(wù):如build仪芒、assemble唁影、check等
  • Android特有的常用任務(wù):
    • connectedCheck任務(wù):在所有連接的設(shè)備或者模擬器上運(yùn)行check檢查
    • deviceCheck任務(wù):通過(guò)API連接遠(yuǎn)程設(shè)備運(yùn)行checks
    • lint任務(wù):在所有ProductFlavor上運(yùn)行l(wèi)int檢查
    • installuninstall任務(wù):在已連接的設(shè)備上安裝或者卸載App
    • signingReport任務(wù):打印App簽名
    • androidDependencies任務(wù):打印Android 依賴(lài)

5.應(yīng)用實(shí)例

//應(yīng)用插件桌硫,Android Gradle屬于Android發(fā)布的第三方插件
buildscript{
    repositories{
        jcenter()
    }
    dependencies{
        classpath 'com.android.tcols.build:gradle:1.5.0'
    }
}
apply plugin:'com.android.application'
//自定義配置入口夭咬,后續(xù)詳解
android{
    compileSdkVersion 23 //編譯Android工程的SDK版本
    buildToolsVersion "23.0.1" //構(gòu)建Android工程所用的構(gòu)建工具版本

    defaultConfig{
        applicationId "org.minmin.app.example"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes{
        release{
            minifyEnabled false
            proguardFiles getDefaultPraguardFile('proguard-andrcid.txt'), 'proguard-rules.pro'
        }
    }
}
//配置第三方依賴(lài)
dependencies{
    compile fileTree(dir:'libs', include:['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcorpat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
}

a.defaultConfig

  • 作用:用于定義所有的默認(rèn)配置,是一個(gè)ProductFlavor铆隘,若ProductFlavor沒(méi)有被特殊定義卓舵,默認(rèn)使用defaultConfig塊指定的配置
  • 常用配置
屬性名 含義
applicationId 指定App包名
minSdkVersion 指定App最低支持的Android SDK
targetSdkVersion 指定基于的Android SDK
versionCode 配置Android App的內(nèi)部版本號(hào)
versionName 配置Android App的版本名稱(chēng)
testApplicationId 配置測(cè)試App的包名,默認(rèn)為applicationId + “.test”
testInstrumentationRunner 配置單元測(cè)試使用的Runner膀钠,默認(rèn)為android.test.InstrumentationTestRunner
proguardFile 配置App ProGuard混淆所使用的ProGuard配置文件
proguardFiles 同時(shí)配置多個(gè)ProGuard配置文件
signingConfig 配置默認(rèn)的簽名信息掏湾,也是一個(gè)ProductFlavor,可直接配置

b.buildTypes

  • 作用:是構(gòu)建類(lèi)型肿嘲,在Android Gradle中內(nèi)置了debug和release兩個(gè)構(gòu)建類(lèi)型融击,差別在于能否在設(shè)備上調(diào)試和簽名不同
  • 每一個(gè)BuildType都會(huì)生成一個(gè)SourceSet以及相應(yīng)的assemble<BuildTypeName>任務(wù)
  • 常用配置
屬性名 含義
applicationIdSuffix 配置基于默認(rèn)applicationId的后綴
debuggable 是否生成一個(gè)可供調(diào)試的Apk
jniDebuggable 是否生成一個(gè)可供調(diào)試JNI代碼的Apk
minifyEnabled 是否啟用Proguard混淆
multiDexEnabled 是否啟用自動(dòng)拆分多個(gè)Dex的功能
zipAlignEnabled 是否開(kāi)啟開(kāi)啟zipalign優(yōu)化,提高apk運(yùn)行效率
shrinkResources 是否自動(dòng)清理未使用的資源雳窟,默認(rèn)為false
proguardFile 配置Proguard混淆使用的配置文件
proguardFiles 同時(shí)配置多個(gè)ProGuard配置文件
signingConfig 配置默認(rèn)的簽名信息尊浪,也是一個(gè)ProductFlavor匣屡,可直接配置

c.signingConfigs

  • 作用:配置簽名設(shè)置,標(biāo)記App唯一性拇涤、保護(hù)App
  • 可以對(duì)不同構(gòu)建類(lèi)型采用不同簽名方式:debug模式用于開(kāi)發(fā)調(diào)試捣作,可以直接使用Android SDK提供的默認(rèn)debug簽名證書(shū);release模式用于發(fā)布鹅士,需要手動(dòng)配置
  • 常用配置
屬性名 含義
storeFile 簽名證書(shū)文件
storePassword 簽名證書(shū)文件的密碼
storeType 簽名證書(shū)的類(lèi)型
keyAlias 簽名證書(shū)中密鑰別名
keyPassword 簽名證書(shū)中該密鑰的密碼
android {
    signingConfigs {
        release{
            storeFile file('myFile.keystore')
            storePassword 'psw'
            keyAlias 'myKey'
            keyPassword 'psw'
        }
    }
}

d.productFlavors

  • 作用:添加不同的渠道券躁、并對(duì)其做不同的處理
  • 常用配置
屬性名 含義
applicationId 設(shè)置該渠道的包名
consumerProguardFiles 對(duì)aar包進(jìn)行混淆
manifestPlaceholders
multiDexEnabled 啟用多個(gè)dex的配置,可突破65535方法問(wèn)題
proguardFiles 混淆使用的文件配置
signingConfig 簽名配置
testApplicationId 適配測(cè)試包的包名
testFunctionalTest 是否是功能測(cè)試
testHandleProfiling 是否啟用分析功能
testInstrumentationRunner 配置運(yùn)行測(cè)試使用的Instrumentation Runner的類(lèi)名
testInstrumentationRunnerArguments 配置Instrumentation Runner使用的參數(shù)
useJack 標(biāo)記是否啟用Jack和Jill這個(gè)全新的掉盅、高性能的編譯器
dimension 維度也拜,通過(guò)flavorDimensions方法聲明,聲明前后代表優(yōu)先級(jí)
//定義baidu和google兩個(gè)渠道趾痘,并聲明兩個(gè)維度慢哈,優(yōu)先級(jí)為abi>version>defaultConfig
android{
    flavorDimensions "abi", "version"
    productFlavors{
        google{
            dimension "abi"
        }
       baidu{ 
           dimension "version"
       } 
}

e.buildConfigFiled

  • 作用:在buildTypes、ProductFlavor自定義字段等配置
  • 方法buildConfigField(String type,String name,String value)
    • type:字段類(lèi)型
    • name:字段常量名
    • value:字段常量值
android{
   buildTypes{
        debug{
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "URL", ' "http://www.ecjtu.jx.cn/" '
        }
    }
}

6.多項(xiàng)目構(gòu)建

和Java Grdle多項(xiàng)目構(gòu)建一樣的扼脐,通過(guò)settings.gradle配置管理多項(xiàng)目岸军;在每個(gè)項(xiàng)目都有一個(gè)build.gradle,采用項(xiàng)目依賴(lài)就能實(shí)現(xiàn)多項(xiàng)目協(xié)作瓦侮。

項(xiàng)目直接依賴(lài)一般適用于關(guān)聯(lián)較緊密艰赞、不可復(fù)用的項(xiàng)目,如果想讓項(xiàng)目被其他項(xiàng)目所復(fù)用肚吏,比如公共組件庫(kù)方妖、工具庫(kù)等,可以單獨(dú)發(fā)布出去罚攀。

7.多渠道構(gòu)建

a.基本原理

  • 構(gòu)建變體(Build Variant)=構(gòu)建類(lèi)型(Build Type)+構(gòu)建渠道(Product Flavor)

Build Type有release党觅、debug兩種構(gòu)建類(lèi)型
Product Flavor有baidu、google兩種構(gòu)建渠道
Build Variant有baiduRelease斋泄、baiduDebug杯瞻、googleRelease、googleDebug四種構(gòu)件產(chǎn)出

  • 構(gòu)建渠道(Product Flavor)還可以通過(guò)dimension進(jìn)一步細(xì)化分組

  • assemble開(kāi)頭的負(fù)責(zé)生成構(gòu)件產(chǎn)物(Apk)

assembleBaidu:運(yùn)行后會(huì)生成baidu渠道的release和debug包
assembleRelease:運(yùn)行后會(huì)生成所有渠道的release包
assembleBaiduRelease:運(yùn)行后只會(huì)生成baidu的release包

b.構(gòu)建方式:通過(guò)占位符manifestPlaceholders實(shí)現(xiàn):

//AndroidManifest
<meta-data 
    android: value="Channel ID" 
    android:name="UMENG_ CHANNEL"/>
//build.gradle
android{
    productFlavors{
        google{
            manifestPlaceholders.put("UMENG_ CHANNEL", "google")
        }
       baidu{
            manifestPlaceholders.put("UMENG_ CHANEL", "baidu")
       }
}
//改進(jìn):通過(guò)productFlavors批量修改
android{
    productFlavors{
        google{
        }
       baidu{
       }
       ProductFlavors.all{ flavor->
           manifestPlaceholders.put("UMENG_ CHANEL", name) 
       }        
}

8.高級(jí)應(yīng)用

a. 使用共享庫(kù)

  • android sdk庫(kù):系統(tǒng)會(huì)自動(dòng)鏈接
  • 共享庫(kù):獨(dú)立庫(kù)炫掐,不會(huì)被系統(tǒng)自動(dòng)鏈接魁莉,使用時(shí)需要在AndroidManifest通過(guò)<uses-library>指定
//聲明需要使用maps共享庫(kù),true表示如果手機(jī)系統(tǒng)不滿足將不能安裝該應(yīng)用
<uses-library
    android:name="com.google.android.maps"
    android:required="true" 
/>
  • add-ons庫(kù):存于add-ons目錄下募胃,大部分由第三方廠商或公司開(kāi)發(fā)旗唁,會(huì)被自動(dòng)解析添加到classpath
  • optional可選庫(kù):位于platforms/android-xx/optional目錄下,通常為了兼容舊版本的API痹束,使用時(shí)需要手動(dòng)添加到classpath

b. 批量修改生成的apk文件名

  • 類(lèi)型:
    • applicationVariants :僅僅適用于Android應(yīng)用Gradle插件
    • libraryVariants :僅僅適用于Android庫(kù)Gradle插件
    • testVariants :以上兩種Gradle插件都使用
  • 示例:


applicationVariants是一個(gè)DomainObjectCollection集合检疫,通過(guò)all方法遍歷每一個(gè)ApplicationVariant,這里有g(shù)oogleRelease和googleDebug兩個(gè)變體祷嘶;然后判斷名字是否以.apk結(jié)尾屎媳,如果是就修改其文件名夺溢。示例中共有。

c.動(dòng)態(tài)生成版本信息

  • 原始方式:由defaultConfig中的versionName指定
  • 分模塊方式:把版本號(hào)等配置抽出放在單獨(dú)的文件里烛谊,并用ext{}括起來(lái)企垦,通過(guò)apply from將其引入到build.gradle,版本信息就被當(dāng)作擴(kuò)展屬性直接使用了
  • 從git的tag中獲取
  • 從屬性文件中動(dòng)態(tài)獲取和遞增

d.隱藏簽名文件信息

  • 必要性:為保證簽名信息安全晒来,最好直接放在項(xiàng)目中,而是放在服務(wù)器上
  • 一種思路
    • 服務(wù)器:配置好環(huán)境變量郑现,打包時(shí)直接使用
    • 本地:直接使用android提供的debug簽名
    • 在signingConfigs加入以下判斷
signingConfigs {
    if (System.env.KEYSTORE_PATH != null) {
        //打包服務(wù)器走這個(gè)邏輯
        storeFile file(System.env.KEYSTORE_PATH)
        keyAlias System.env.ALIAS
        keyPassword System.env.KEYPASS
        storePassword System.env.STOREPASS
    } else {
        //當(dāng)不能從環(huán)境變量取到簽名信息時(shí)梦碗,使用本地debug簽名
        storeFile file('debug.keystore')
        storePassword 'android'
        keyAlias 'androiddebugkey'
        keyPassword 'android'
    }
}

e.動(dòng)態(tài)添加自定義的資源

  • 針對(duì)res/values中的資源龄减,除了使用xml定義,還可以通過(guò)Android Gradle定義
  • 方法:resValue(String type, String name, String value)
    • type:資源類(lèi)型,如有string匾寝、id、bool
    • name:資源名稱(chēng)毅哗,以便在工程中引用
    • value:資源值
productFlavors{
   google{
       resValue 'string', 'channel_tips', 'google渠道歡迎你'
   }
}

以google為例率寡,在debug模式下,資源文件保存目錄:build/generated/res/resValues/google/debug/values/generated.xml

f.Java編譯選項(xiàng)

通過(guò)compileOptions{}閉包進(jìn)行編譯配置废累,可配置項(xiàng):

  • encoding:配置源文件的編碼
  • sourceCompatibility:配置Java源代碼的編譯級(jí)別
  • targetCompatibility:配置生成Java字節(jié)碼的版本
 android{
      compileOptions{
         encoding = 'utf-8'
         sourceCompatibility = JavaVersion.VERSI0N_ 1_ 6
         targetCompatibility = JavaVersion.VERSION_ 1_ 6
     }
}

g. adb選項(xiàng)配置

通過(guò)adbOptions{}閉包進(jìn)行adb配置邓梅,可配置項(xiàng):

  • timeOutInMs:設(shè)置執(zhí)行adb命令的超時(shí)時(shí)間,單位毫秒
  • installOptions:設(shè)置adb install安裝設(shè)置項(xiàng)
    • -l:鎖定該應(yīng)用程序
    • -r:替換已存在的應(yīng)用程序邑滨,即強(qiáng)制安裝
    • -t:允許測(cè)試包
    • -s:把應(yīng)用程序安裝到SD卡上
    • -d:允許進(jìn)行降級(jí)安裝日缨,即安裝版本比手機(jī)自帶的低
    • -g:為該應(yīng)用授予所有運(yùn)行時(shí)的權(quán)限
android{
    adbOptions{
        timeOutInMs = 5*1000
        installOptions '-r', '-s'
    }
}

h.DEX選項(xiàng)配置

通過(guò)dexOptions {}閉包進(jìn)行dex配置,可配置項(xiàng):

  • incremental:配置是否啟用dx的增量模式掖看,默認(rèn)值為false
  • javaMaxHeapSize:配置執(zhí)行dx命令時(shí)為其分配的最大堆內(nèi)存
  • jumboMode:配置是否開(kāi)啟jumbo模式
  • preDexLibraries:配置是否預(yù)dex Libraries庫(kù)工程匣距,默認(rèn)值為true,開(kāi)啟后會(huì)提高增量構(gòu)建的速度
  • threadCount:配置Android Gradle運(yùn)行dx命令時(shí)使用的線程數(shù)量

PS:這周沒(méi)有周記哎壳,期待明天開(kāi)始的團(tuán)建活動(dòng)~
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末毅待,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子归榕,更是在濱河造成了極大的恐慌尸红,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹲坷,死亡現(xiàn)場(chǎng)離奇詭異驶乾,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)循签,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)级乐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人县匠,你說(shuō)我怎么就攤上這事风科∪雎郑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵贼穆,是天一觀的道長(zhǎng)题山。 經(jīng)常有香客問(wèn)我,道長(zhǎng)故痊,這世上最難降的妖魔是什么顶瞳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮愕秫,結(jié)果婚禮上慨菱,老公的妹妹穿的比我還像新娘。我一直安慰自己戴甩,他們只是感情好符喝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著甜孤,像睡著了一般协饲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缴川,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天茉稠,我揣著相機(jī)與錄音,去河邊找鬼把夸。 笑死战惊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的扎即。 我是一名探鬼主播吞获,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼谚鄙!你這毒婦竟也來(lái)了各拷?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤闷营,失蹤者是張志新(化名)和其女友劉穎烤黍,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體傻盟,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡速蕊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了娘赴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片规哲。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖诽表,靈堂內(nèi)的尸體忽然破棺而出唉锌,到底是詐尸還是另有隱情隅肥,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布袄简,位于F島的核電站腥放,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏绿语。R本人自食惡果不足惜秃症,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吕粹。 院中可真熱鬧伍纫,春花似錦、人聲如沸昂芜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泌神。三九已至,卻和暖如春舞虱,著一層夾襖步出監(jiān)牢的瞬間欢际,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工矾兜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留损趋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓椅寺,卻偏偏與公主長(zhǎng)得像浑槽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子返帕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353