要點提煉| Gradle指南

釐米姑娘發表於2019-02-28

在使用Android Studio過程中沒少被Gradle坑過,雖然網上有很多簡單粗暴的解決方案,但極少會說清楚緣由,所以一直想看一本叫《Android Gradle權威指南》。 不過由於書中實踐內容很多,更像一本工具書,而且Gradle現已發行了好幾版,因此本篇僅僅是陳列出一些大的要點,尤其是那些熟悉又陌生的名詞,如果想要具體瞭解細節和操作流程,一定要跟著書探索喲~

  • Gradle入門
  • Groovy基礎
  • Gradle構建指令碼基礎
  • Gradle外掛
  • Java Gradle外掛
  • Android Gradle外掛

一.Gradle入門

1.本書環境

  • 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.開發配置區別

  • Eclipse+ADT+Ant
  • Android Studio+Gradle:Gradle比Ant更靈活,有效提高開發效率

b.Eclipse遷移到AndroidStudio兩種方式

  • 使用AndroidStudio直接匯入Eclipse工程
    • 特點:使用AS預設推薦目錄結構
  • 使用Eclipse匯出Android Gradle配置檔案,並轉換成Gradle工程,再使用Android Studio把它作為Gradle工程匯入
    • 特點:保留原專案結構

3.Gradle的ZIP解壓後目錄

  • docs:API、 DSL、指南等文件
  • init.d:gradle初始化指令碼目錄
  • lib:相關庫
  • media:一些icon資源
  • samples:示例
  • src:原始檔
  • getting-started.html:入門連結
  • LICENSE
  • NOTICE
    要點提煉| Gradle指南

4.引例:Gradle版Hello World

//build.gradle:
    task hello{//定義一個任務Task名為hello
        doLast{//新增一個動作Action,表示在Task執行完畢後回撥doLast閉包中的程式碼
            println'Hello World'//輸出字串,單雙號均可
        }
    }
//終端:
    gradle hello//執行build.gradle中名為Hello的任務
//輸出:
    Hello World
複製程式碼

5.Gradle Wrapper

a.含義:對Gradle一層包裝,便於使用統一Gradle構建

b.目錄結構:

|--gradle
|   |--wrapper
|        |--gradle-wrapper.jar
|        |--gradle-wrapper.properties
|--gradlew
|--gradlew.bat
複製程式碼

要點提煉| Gradle指南

  • gradle-wrapper.jar:具體業務邏輯實現的jar包
  • gradle-wrapper.properties:配置檔案,包含篇配置資訊如下圖:
    要點提煉| Gradle指南
  • gradlew:Linux下可執行指令碼
  • gradlew.bat:Windows下可執行指令碼

c.常用命令

  • 生成:gradle wrapper,由Wrapper Task生成
  • 配置引數:
    • gradle wrapper --gradle-version XXX用於指定使用的Gradle版本
    • gradle wrapper --distribution-url XXX用於指定下載Gradle發行版的url地址
  • 自定義:task wrapper(type:Wrapper){ //配置資訊 }

6.Gradle日誌

a.日誌級別

要點提煉| Gradle指南
b.日誌輸出程式碼

  • 使用print方法,屬於quiet級別日誌:println 'XX'X
  • 使用內建logger:
    要點提煉| Gradle指南
    c.日誌輸出控制
    要點提煉| Gradle指南
    例如,輸出QUIET級別及其之上的日誌資訊:gradle -q tasks

7.Gradle命令列

  • 檢視所有可執行tasks:./gradlew tasks
  • 強制重新整理依賴:./gradlew --refresh-dependencies assemble
  • 多工呼叫:./gradlew clean jar
  • 檢視幫助:./gradlew -?./gradlew -h./gradlew -help

二.Groovy基礎

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

1.特性:Groovy是個靈活的動態指令碼語言,語法和Java很相似,又相容Java,且在此基礎上增加了很多動態型別和靈活的特性,如支援閉包和DSL

2.語法

  • 分號不必需
  • 字串:單引號和雙引號均可定義一個字串常量,區別在於單引號不能對字串表示式做運算,而雙引號可以
task printStringVar << {
    def name = "張三”
    println '單引號的變數計算:${name}'
    println "雙引號的變數計算:${name}"
}
執行./gradlew printStringVar輸出結果:
單引號的變數計算:${name}
雙引號的變數計算:張三
複製程式碼
  • 集合:以List和Map為例,介紹如何定義集合和訪問集合元素
//List
task printList<<{
      def numList = [1,2,3,4,5,6];//定義一個List

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

複製程式碼
  • 方法:方法呼叫傳參的括號可省略;return不必需,無return時會將最後一行程式碼作為其返回值;允許將程式碼塊(閉包)作為引數傳遞
//以集合的each方法為例,接受的引數就是一個閉包
numList.each({println it})
//省略傳參的括號,並調整格式,有以下常見形式
numList.each{
    println it
}
複製程式碼
  • 不是一定要定義成員變數才能作為類屬性被訪問,用get/set方法也能當作類屬性
task helloJavaBean<<{
      Person p = new Person()
      p.name = "張三"
      println "名字是: ${p.name}"//輸出類屬性name,為張三
      println "年齡是: ${p.age}"//輸出類屬性age,為12
}
class Person{
      private String name
      public int getAge(){//省略return
          12
      }
}
複製程式碼
  • 閉包:當閉包有一個引數時,預設為it,多個引數時需要一一羅列
//單個引數
task helloClosure<<{
    customEach{
        println it
    }
}
def customEach(closure){
    for(int i in 1..10){
        closure(i)
    }
}
//多個引數
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構建指令碼基礎

1.Settings檔案

  • 作用:初始化、設定工程樹
  • 檔名settings.gradle,放在Project下
  • 常用方法:include方法指定能被Gradle識別的Module
//新增:app和:common這兩個module參與構建
include ':app'
project(':app').projectDir = new File('存放目錄')
include':common'
project(':common').projectDir = new File('存放目錄')
複製程式碼

2.Build檔案

  • Project的build.gradle:整個Project的共有屬性,包括配置版本、外掛、依賴庫等資訊
  • Module的build.gradle:各個module私有的配置檔案
    要點提煉| Gradle指南

3.Gradle任務

a.含義:指原子性操作

b.關係:一個Gradle可包含多個Project,一個 Project可包含多個Task,即每個Project是由多個Task組成的;Task是Project的屬性,屬性名就是任務名

c.建立

  • 以任務名建立:接受一個name引數
def task myTask = task(myTask)
myTask.doLast{
    println "第一種建立Task方法,原型為Task task(String name) throws InvalidUserDataException"
}
複製程式碼
  • 以任務名+Map建立:Map引數用於對建立的task進行配置,可用配置如下圖
    要點提煉| Gradle指南
def task myTask = task(myTask,group:BasePlugin.BUILD_GROUP)
myTask.doLast{
    println "第二種建立Task方法,原型為Task task(String name,Map<String,?> args) throws InvalidUserDataException"
}
複製程式碼
  • 以任務名+閉包建立:常見形式
task myTask{
    doLast{
        println "第三種建立Task方法,原型為Task task(String name,Closure configureClosure)"
    }
}
複製程式碼

以上建立方式實際上最終都會呼叫TaskContainter#create()方法,使用./gradlew myTask命令執行任務

d.訪問

  • 通過任務名訪問:名稱.方法
  • 通過TaskContainter訪問:tasks['名稱'].方法
  • 通過路徑訪問:引數可以為路徑或名稱
    • get方式:tasks.getByPath('路徑/名稱'),若不存在會丟擲UnknownTaskException異常
    • find方式:tasks.findByPath('路徑/名稱'),若不存在返回null
  • 通過名稱訪問:引數只能為名稱
    • get方式:tasks.getByName('名稱'),若不存在會丟擲UnknownTaskException異常
    • find方式:tasks.findByName('名稱'),若不存在返回null

可見任務名稱是唯一的,這是因為TaskContainer的父類 NamedDomainObjectCopllection是個具有唯一不變名字的域物件的集合

e.依賴:在建立任務時通過dependsOn指定其依賴的任務,可以控制任務的執行順序

task task1<<{
    println 'hello'
}
task task2<<{
    println 'world'
}
//依賴單個任務
task task3(dependsOn:task1){
    doLast{
        println 'one'
    }
}
//依賴多個任務
task task4{
    dependsOn task1,task2
    doLast{
        println 'two'
    }
}
複製程式碼

當執行task4時,會發現task1、task2會先執行,再執行task4

注:操作符<< 用在Task定義上相當於doLast

f.排序:除了通過強依賴來控制任務的執行順序,還可以通過 shouldRunAftermustRunAfter 實現

taskB.shouldRunAfter(taskA) //表示taskB應該在taskA執行之後執行,有可能不會按預設執行
taskB.mustRunAfter(taskA) //表示taskB必須在taskA執行之後執行
複製程式碼

g.分組& 描述:分組是對任務的分類,便於歸類整理;描述是說明任務的作用;建議兩個一起配置,便於快速瞭解任務的分類和用途

def task myTask = task(myTask)
myTask .group = BasePlugin.BUILD_GROUP
myTask .description = '這是一個構建的引導任務'
複製程式碼

h.啟用 & 禁用:enable屬性可以啟動和禁用任務,執行被禁用的任務輸出提示該任務被跳過

def task myTask = task(myTask)
myTask.enable = false //禁用任務
複製程式碼

i.執行分析:執行Task的時候實際上是執行其擁有的actions List,它是Task物件例項的成員變數;在建立任務時Gradle會解析其中被TaskAction註解的方法作為其Task執行的action,並新增到 actions List,其中doFirst和doList會被新增到action List第一位和最後一位

4.自定義屬性

Project、Task和SourceSet都允許使用者新增額外的自定義屬性、並對自定義屬性進行讀取和設定

  • 方式:通過ext屬性,新增多個通過ext程式碼塊
  • 優點:相比區域性變數有廣泛的作用域,可以跨Project、跨Task訪問,只要能訪問這些屬性所屬的物件即可
//給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.作用

  • 可以新增任務到專案,比如測試、編譯、打包等
  • 可以新增依賴配置到專案,幫助配置專案構建過程中需要的依賴,比如第三方庫等
  • 可以向專案中現有的物件型別新增新的擴充套件屬性和方法等,幫助配置和優化構建
  • 可以對專案進行一些約定,比如約定原始碼存放位置等

Gradle本身內建許多常用的外掛,如若需要還可以擴充套件現有外掛或者自定義外掛,如Android Gradle外掛就是基於內建的Java外掛實現的

2.擴充套件現有外掛

a.外掛種類

  • 二進位制外掛:實現org.gradle.api.Plugin介面的外掛,可以有plugin id
  • 指令碼外掛:嚴格上只是一個指令碼,可以來自本地或網路

b.應用外掛:通過Project#apply()方法,有三種用法

  • Map引數:void apply (Map<String, ?> options)
    • 二進位制外掛:
      • id:apply plugin:'java'
      • 型別:apply plugin:org.gradle.api.plugins.JavaPlugin
      • 簡寫:apply plugin:JavaPlugin
    • 指令碼外掛:apply from:'version.gradle'
    • 第三方釋出外掛:apply plugin:'com.android.application'

注意:應用第三方釋出的作為jar的二進位制外掛時,必須先在buildscript{}配置其classpath才能使用,否則會提示找不到該外掛

//buildscript:為專案進行前提準備和初始化相關配置依賴
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.自定義外掛:實現Plugin介面、重寫apply()方法


五.Java Gradle外掛

1.專案結構

使用Java外掛要先應用進來:

apply plugin:'java'
複製程式碼

此時會新增許多預設設定和約定,比如有以下預設專案結構:

|-example
|  |-build.gradle
|  |-src
|    |-main
|       |-java  原始碼存放目錄
|       |-resources  打包檔案存放目錄
|    |-test
|       |-java 單元測試用例存放目錄
|       |-resources 單元測試中使用的檔案
複製程式碼

2.源集(SourceSet)

  • 作用:用於描述和管理原始碼(java)及其資源(resources),如訪問原始碼目錄、設定源集屬性、更改Java原始碼目錄等
  • 方式:通過sourceSets屬性(是一個SourceSetsContainer)和sourceSets{}閉包
  • 常用屬性
    要點提煉| Gradle指南

比如,在上述Java外掛預設專案結構中的main和test就是內建的兩個源集,現在更改main源集的Java原始檔的存放目錄到src/java下:

apply plugin:'java'
sourceSets{
    main{
        java{
            srcDir 'src/java'
        }
    }
}
複製程式碼
  • 定義新源集:通過sourceSets{}閉包新增
apply plugin:'java'
sourceSets{
    vip{
    }
}
複製程式碼

此時會新建兩個目錄:src/vip/java和src/vip/resources

補充:除了SourceSet,Java外掛裡常用的其他屬性:

要點提煉| Gradle指南

3.配置第三方依賴

a.依賴方式

  • 外部依賴:依賴外部倉庫,如Maven、Ivy等
  • 專案依賴:依賴專案,依賴後可以使用該專案的Java類
  • 檔案依賴:如依賴Jar包,出於安全考慮不釋出到Maven而是放在專案的libs資料夾下

b.具體方法

  • 對於外部依賴,需要先在repositories{}閉包裡宣告依賴庫的位置
  • dependencies{}閉包新增依賴
    • 外部依賴:說明依賴庫的group:name:version
    • 專案依賴:project('專案名稱')
    • 檔案依賴:files('檔名稱'),多個檔案逗號分開,或者fileTree(dir:'檔名稱',include:'*.副檔名稱')依賴指定資料夾下指定副檔名檔案
  • 幾種依賴型別
    要點提煉| Gradle指南

舉例:

apply plugin:'java'
repositories {
    //外部依賴 依賴Maven中心庫
    maveCentral() 
}
dependencies {
    //外部依賴 完整寫法
    compile group:'com.squareup.okhttp3',name:'okhttp', version:'3.0.1'   
    //外部依賴 簡單寫法
    compile 'com.squareup.okhttp3:okhttp:3.0.1'    
    //外部依賴 指定main源集依賴
    mainCompile 'com.squareup.okhttp3:okhttp:3.0.1'   
    //專案依賴
    compile project(':example')    
    //檔案依賴 依賴libs下兩個Jar包
    compile files('libs/example01.jar', 'libs/example02.jar')   
    //檔案依賴 指定依賴libs下所有Jar包
    compile fileTree(dir: 'libs',include: '*.jar')
}
複製程式碼

4.內建任務

常用幾種任務:

  • build任務:構建專案
  • clean任務:刪除build目錄及構建生成的檔案
  • assemble任務:不執行單元測試,只編譯和打包
  • check任務:只執行單元測試
  • javadoc任務:生成Java格式的doc api文件

還有些通用任務、對源集適用的任務:

要點提煉| Gradle指南

5.多專案構建

  • 含義:多個Gradle專案一起構建
  • 方式:通過settings.gradle配置管理多專案;在每個專案都有一個build.gradle,採用專案依賴就能實現多專案協作
//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.釋出構件

  • 構件:Gradle構建的產物,如Jar包、Zip包等
  • 意義:釋出構建給其他工程使用,可以釋出到本地目錄、Maven、Ivy等
  • 方式:明確構件型別,並通過artifacts{}閉包配置需要釋出的構建,在uploadArchives{}上傳發布構件
//以釋出jar構件為例
apply plugin:'java '
task publishJar(type:Jar)
artifacts{
    archives publishJar
}
uploadArchives{
    repositories{
        //釋出到本地目錄
        flatDir{
            name 'libs'
            dirs "$projectDir/libs"
        }
        //釋出到本地Maven庫
        mavenLocal()
    }
}
複製程式碼

六.Android Gradle外掛

1.概述

Android Gradle外掛繼承於Java外掛,具有Java外掛的所有特性,也有自己的特性,看下官方介紹:

  • 可以很容易地重用程式碼和資源
  • 可以很容易地建立應用的衍生版本
  • 可以很容易地配置、擴充套件以及自定義構建過程
  • 和IDE無縫整合

2.外掛分類

  • App應用工程:生成可執行apk應用;id: com.android.application
  • Library庫工程:生成aar包給其他的App工程公用;id: com.android.library
  • Test測試工程:對App應用工程或Library庫工程進行單元測試;id: com.android.test

3.專案結構

|-example
|  |-build.gradle
|  |-example.iml
|  |-libs
|  |-proguard-rules.pro  混淆配置檔案
|  |-src
|    |-androidTest
|       |-java  Android單元測試程式碼
|    |-main
|       |-java  App主程式碼
|       |-res   資原始檔
|       |-AndroidManifest.xml  配置檔案
|    |-test
|       |-java 普通單元測試程式碼
複製程式碼

4.內建任務

  • Java外掛內建任務:如build、assemble、check等
  • Android特有的常用任務:
    • connectedCheck任務:在所有連線的裝置或者模擬器上執行check檢查
    • deviceCheck任務:通過API連線遠端裝置執行checks
    • lint任務:在所有ProductFlavor上執行lint檢查
    • installuninstall任務:在已連線的裝置上安裝或者解除安裝App
    • signingReport任務:列印App簽名
    • androidDependencies任務:列印Android 依賴

5.應用例項

//應用外掛,Android Gradle屬於Android釋出的第三方外掛
buildscript{
    repositories{
        jcenter()
    }
    dependencies{
        classpath 'com.android.tcols.build:gradle:1.5.0'
    }
}
apply plugin:'com.android.application'
//自定義配置入口,後續詳解
android{
    compileSdkVersion 23 //編譯Android工程的SDK版本
    buildToolsVersion "23.0.1" //構建Android工程所用的構建工具版本

    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'
        }
    }
}
//配置第三方依賴
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

  • 作用:用於定義所有的預設配置,是一個ProductFlavor,若ProductFlavor沒有被特殊定義,預設使用defaultConfig塊指定的配置
  • 常用配置
屬性名 含義
applicationId 指定App包名
minSdkVersion 指定App最低支援的Android SDK
targetSdkVersion 指定基於的Android SDK
versionCode 配置Android App的內部版本號
versionName 配置Android App的版本名稱
testApplicationId 配置測試App的包名,預設為applicationId + “.test”
testInstrumentationRunner 配置單元測試使用的Runner,預設為android.test.InstrumentationTestRunner
proguardFile 配置App ProGuard混淆所使用的ProGuard配置檔案
proguardFiles 同時配置多個ProGuard配置檔案
signingConfig 配置預設的簽名資訊,也是一個ProductFlavor,可直接配置

b.buildTypes

  • 作用:是構建型別,在Android Gradle中內建了debug和release兩個構建型別,差別在於能否在裝置上除錯和簽名不同
  • 每一個BuildType都會生成一個SourceSet以及相應的assemble<BuildTypeName>任務
  • 常用配置
屬性名 含義
applicationIdSuffix 配置基於預設applicationId的字尾
debuggable 是否生成一個可供除錯的Apk
jniDebuggable 是否生成一個可供除錯JNI程式碼的Apk
minifyEnabled 是否啟用Proguard混淆
multiDexEnabled 是否啟用自動拆分多個Dex的功能
zipAlignEnabled 是否開啟開啟zipalign優化,提高apk執行效率
shrinkResources 是否自動清理未使用的資源,預設為false
proguardFile 配置Proguard混淆使用的配置檔案
proguardFiles 同時配置多個ProGuard配置檔案
signingConfig 配置預設的簽名資訊,也是一個ProductFlavor,可直接配置

c.signingConfigs

  • 作用:配置簽名設定,標記App唯一性、保護App
  • 可以對不同構建型別採用不同簽名方式:debug模式用於開發除錯,可以直接使用Android SDK提供的預設debug簽名證照;release模式用於釋出,需要手動配置
  • 常用配置
屬性名 含義
storeFile 簽名證照檔案
storePassword 簽名證照檔案的密碼
storeType 簽名證照的型別
keyAlias 簽名證照中金鑰別名
keyPassword 簽名證照中該金鑰的密碼
android {
    signingConfigs {
        release{
            storeFile file('myFile.keystore')
            storePassword 'psw'
            keyAlias 'myKey'
            keyPassword 'psw'
        }
    }
}
複製程式碼

d.productFlavors

  • 作用:新增不同的渠道、並對其做不同的處理
  • 常用配置
屬性名 含義
applicationId 設定該渠道的包名
consumerProguardFiles 對aar包進行混淆
manifestPlaceholders
multiDexEnabled 啟用多個dex的配置,可突破65535方法問題
proguardFiles 混淆使用的檔案配置
signingConfig 簽名配置
testApplicationId 適配測試包的包名
testFunctionalTest 是否是功能測試
testHandleProfiling 是否啟用分析功能
testInstrumentationRunner 配置執行測試使用的Instrumentation Runner的類名
testInstrumentationRunnerArguments 配置Instrumentation Runner使用的引數
useJack 標記是否啟用Jack和Jill這個全新的、高效能的編譯器
dimension 維度,通過flavorDimensions方法宣告,宣告前後代表優先順序
//定義baidu和google兩個渠道,並宣告兩個維度,優先順序為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:欄位型別
    • name:欄位常量名
    • value:欄位常量值
android{
   buildTypes{
        debug{
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "URL", ' "http://www.ecjtu.jx.cn/" '
        }
    }
}
複製程式碼

6.多專案構建

和Java Grdle多專案構建一樣的,通過settings.gradle配置管理多專案;在每個專案都有一個build.gradle,採用專案依賴就能實現多專案協作。

專案直接依賴一般適用於關聯較緊密、不可複用的專案,如果想讓專案被其他專案所複用,比如公共元件庫、工具庫等,可以單獨釋出出去。

7.多渠道構建

a.基本原理

  • 構建變體(Build Variant)=構建型別(Build Type)+構建渠道(Product Flavor)

Build Type有release、debug兩種構建型別 Product Flavor有baidu、google兩種構建渠道 Build Variant有baiduRelease、baiduDebug、googleRelease、googleDebug四種構件產出

  • 構建渠道(Product Flavor)還可以通過dimension進一步細化分組

  • assemble開頭的負責生成構件產物(Apk)

assembleBaidu:執行後會生成baidu渠道的release和debug包 assembleRelease:執行後會生成所有渠道的release包 assembleBaiduRelease:執行後只會生成baidu的release包

b.構建方式:通過佔位符manifestPlaceholders實現:

//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")
       }
}
複製程式碼
//改進:通過productFlavors批量修改
android{
    productFlavors{
        google{
        }
       baidu{
       }
       ProductFlavors.all{ flavor->
           manifestPlaceholders.put("UMENG_ CHANEL", name) 
       }        
}
複製程式碼

8.高階應用

a. 使用共享庫

  • android sdk庫:系統會自動連結
  • 共享庫:獨立庫,不會被系統自動連結,使用時需要在AndroidManifest通過<uses-library>指定
//宣告需要使用maps共享庫,true表示如果手機系統不滿足將不能安裝該應用
<uses-library
    android:name="com.google.android.maps"
    android:required="true" 
/>
複製程式碼
  • add-ons庫:存於add-ons目錄下,大部分由第三方廠商或公司開發,會被自動解析新增到classpath
  • optional可選庫:位於platforms/android-xx/optional目錄下,通常為了相容舊版本的API,使用時需要手動新增到classpath

b. 批量修改生成的apk檔名

  • 型別:
    • applicationVariants :僅僅適用於Android應用Gradle外掛
    • libraryVariants :僅僅適用於Android庫Gradle外掛
    • testVariants :以上兩種Gradle外掛都使用
  • 示例:
    要點提煉| Gradle指南

applicationVariants是一個DomainObjectCollection集合,通過all方法遍歷每一個ApplicationVariant,這裡有googleRelease和googleDebug兩個變體;然後判斷名字是否以.apk結尾,如果是就修改其檔名。示例中共有。

c.動態生成版本資訊

  • 原始方式:由defaultConfig中的versionName指定
  • 分模組方式:把版本號等配置抽出放在單獨的檔案裡,並用ext{}括起來,通過apply from將其引入到build.gradle,版本資訊就被當作擴充套件屬性直接使用了
  • 從git的tag中獲取
  • 從屬性檔案中動態獲取和遞增

d.隱藏簽名檔案資訊

  • 必要性:為保證簽名資訊保安,最好直接放在專案中,而是放在伺服器上
  • 一種思路
    • 伺服器:配置好環境變數,打包時直接使用
    • 本地:直接使用android提供的debug簽名
    • 在signingConfigs加入以下判斷
signingConfigs {
    if (System.env.KEYSTORE_PATH != null) {
        //打包伺服器走這個邏輯
        storeFile file(System.env.KEYSTORE_PATH)
        keyAlias System.env.ALIAS
        keyPassword System.env.KEYPASS
        storePassword System.env.STOREPASS
    } else {
        //當不能從環境變數取到簽名資訊時,使用本地debug簽名
        storeFile file('debug.keystore')
        storePassword 'android'
        keyAlias 'androiddebugkey'
        keyPassword 'android'
    }
}
複製程式碼

e.動態新增自定義的資源

  • 針對res/values中的資源,除了使用xml定義,還可以通過Android Gradle定義
  • 方法:resValue(String type, String name, String value)
    • type:資源型別,如有string、id、bool
    • name:資源名稱,以便在工程中引用
    • value:資源值
productFlavors{
   google{
       resValue 'string', 'channel_tips', 'google渠道歡迎你'
   }
}
複製程式碼

以google為例,在debug模式下,資原始檔儲存目錄:build/generated/res/resValues/google/debug/values/generated.xml

f.Java編譯選項

通過compileOptions{}閉包進行編譯配置,可配置項:

  • encoding:配置原始檔的編碼
  • sourceCompatibility:配置Java原始碼的編譯級別
  • targetCompatibility:配置生成Java位元組碼的版本
 android{
      compileOptions{
         encoding = 'utf-8'
         sourceCompatibility = JavaVersion.VERSI0N_ 1_ 6
         targetCompatibility = JavaVersion.VERSION_ 1_ 6
     }
}
複製程式碼

g. adb選項配置

通過adbOptions{}閉包進行adb配置,可配置項:

  • timeOutInMs:設定執行adb命令的超時時間,單位毫秒
  • installOptions:設定adb install安裝設定項
    • -l:鎖定該應用程式
    • -r:替換已存在的應用程式,即強制安裝
    • -t:允許測試包
    • -s:把應用程式安裝到SD卡上
    • -d:允許進行降級安裝,即安裝版本比手機自帶的低
    • -g:為該應用授予所有執行時的許可權
android{
    adbOptions{
        timeOutInMs = 5*1000
        installOptions '-r', '-s'
    }
}
複製程式碼

h.DEX選項配置

通過dexOptions {}閉包進行dex配置,可配置項:

  • incremental:配置是否啟用dx的增量模式,預設值為false
  • javaMaxHeapSize:配置執行dx命令時為其分配的最大堆記憶體
  • jumboMode:配置是否開啟jumbo模式
  • preDexLibraries:配置是否預dex Libraries庫工程,預設值為true,開啟後會提高增量構建的速度
  • threadCount:配置Android Gradle執行dx命令時使用的執行緒數量

PS:這周沒有周記,期待明天開始的團建活動~

相關文章