在使用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
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-wrapper.jar
:具體業務邏輯實現的jar包gradle-wrapper.properties
:配置檔案,包含篇配置資訊如下圖: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.日誌級別:
b.日誌輸出程式碼:- 使用print方法,屬於quiet級別日誌:
println 'XX'X
- 使用內建logger:
c.日誌輸出控制:
例如,輸出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)
}
}
複製程式碼
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私有的配置檔案
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進行配置,可用配置如下圖
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方式:
- 通過名稱訪問:引數只能為名稱
- get方式:
tasks.getByName('名稱')
,若不存在會丟擲UnknownTaskException異常 - find方式:
tasks.findByName('名稱')
,若不存在返回null
- get方式:
可見任務名稱是唯一的,這是因為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.排序:除了通過強依賴來控制任務的執行順序,還可以通過 shouldRunAfter
和 mustRunAfter
實現
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
- id:
- 指令碼外掛:
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()方法
1.專案結構
使用Java外掛要先應用進來:
apply plugin:'java'
複製程式碼
此時會新增許多預設設定和約定,比如有以下預設專案結構:
|-example
| |-build.gradle
| |-src
| |-main
| |-java 原始碼存放目錄
| |-resources 打包檔案存放目錄
| |-test
| |-java 單元測試用例存放目錄
| |-resources 單元測試中使用的檔案
複製程式碼
2.源集(SourceSet)
- 作用:用於描述和管理原始碼(java)及其資源(resources),如訪問原始碼目錄、設定源集屬性、更改Java原始碼目錄等
- 方式:通過
sourceSets
屬性(是一個SourceSetsContainer)和sourceSets{}
閉包 - 常用屬性:
比如,在上述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外掛裡常用的其他屬性:
3.配置第三方依賴
a.依賴方式
- 外部依賴:依賴外部倉庫,如Maven、Ivy等
- 專案依賴:依賴專案,依賴後可以使用該專案的Java類
- 檔案依賴:如依賴Jar包,出於安全考慮不釋出到Maven而是放在專案的libs資料夾下
b.具體方法
- 對於外部依賴,需要先在
repositories{}
閉包裡宣告依賴庫的位置 - 在
dependencies{}
閉包新增依賴- 外部依賴:說明依賴庫的
group:name:version
- 專案依賴:
project('專案名稱')
- 檔案依賴:
files('檔名稱')
,多個檔案逗號分開,或者fileTree(dir:'檔名稱',include:'*.副檔名稱')
依賴指定資料夾下指定副檔名檔案
- 外部依賴:說明依賴庫的
- 幾種依賴型別
舉例:
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文件
還有些通用任務、對源集適用的任務:
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()
}
}
複製程式碼
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連線遠端裝置執行checkslint
任務:在所有ProductFlavor上執行lint檢查install
、uninstall
任務:在已連線的裝置上安裝或者解除安裝AppsigningReport
任務:列印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外掛都使用
- 示例:
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命令時使用的執行緒數量