一、瞭解gradle
1.概述
1.1 gradle是什麼
gradle是一款基於JVM的專注於靈活性和性能的開源構建工具。
gradle用的是一種基於 Groovy 的領域特定語言(DSL,Demain Specific Language)來聲明項目設置,摒棄了 XML(如 ANT 和 Maven)的各種繁瑣配置。
1.2 作用
1.3 爲什麼用gradle?
附上:Gradle官網:https://gradle.org
2.Android gradle plugin
Android gradle plugin是Gradle插件,也就是AndroidStudio用於開發Android項目的gradle插件。
gradle是構建工具,可以構建java應用,web應用。而gradle plugin只是google用來構建android應用的一個android studio插件。
3.gradle wrapper
每個基於gradle構建的工程都有一個gradle本地代理,叫做 gradle wrappe。在 /gradle/wrapper/gralde-wrapper.properties 目錄中聲明瞭指向目錄和版本。
每一個Wrapper都會綁定到一個特定版本的Gradle,當用戶第一次執行如下的命令時,Wrapper會自動地下載並安裝對應版本的Gradle,方便用戶構建項目。
二、Groovy基本語法
1、基礎語法
1、語句可以不以分號結尾
2、函數調用可以不需要參數括號
println 'hello world'
3、動態類型
Groovy 定義變量的方式和 Java 是類似的,區別在於 Groovy 提供了def關鍵字供使用,它可以省略變量類型的定義,根據變量的值進行類型推導。
如:
def a = 123
def b = 'b'
def c = true
boolean d = false
int e = 123
4、函數寫法
Groovy 方法的默認訪問修飾符是public,方法的返回類型可以不需要聲明,但需添加def關鍵字。有返回值的方法return可以被省略,默認返回最後一行代碼的運行結果,如果使用了return關鍵字則返回指定的返回值。
例:
String method1() {
return 'hello'
}
assert method1() == 'hello';
def method2() {
return 'hello'
}
assert method2() == 'hello';
def method3() {
'hello'
}
assert method3() == 'hello';
Groovy 方法的參數類型可以被省略,默認爲Object類型。
例:
def add(int a, int b) {
return a + b
}
//與上面的等價
def add(a, b) {
a + b
}
Groovy 方法的其他特性與Java一樣,比如支持重載、不定長參數(…)等。
5、不需要main函數
在Java中要輸出“hello world”需要像下面這樣,創建一個類,然後創建一個main方法。
public class Hello {
public static void main(String[] args) {
System.out.println("hello world");
}
}
在Groovy中,這些都可以省略,實例如下:
例:在文本中寫如下groovy語句
println 'Groovy world!'
上面我們寫的groovy文件編譯後的class其實是Java類,該類從Script類派生而來(查閱API);可以發現,每個腳本都會生成一個static main方法,我們執行groovy腳本的實質其實是執行的這個Java類的main方法,腳本源碼裏所有代碼都被放到了run方法中,腳本中定義的方法(該例暫無)都會被定義在Main類中。如下:
import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
def run() {
println 'Groovy world!'
}
static void main(String[] args) {
InvokerHelper.runScript(Main, args)
}
}
6、Groovy快速入門博客
https://www.jianshu.com/p/e8dec95c4326
2、閉包
閉包其實就是一段代碼塊。在gradle中,我們主要是把閉包當參數來使用
例如1:
//定義一個閉包
def b1 = {
println “hello b1”
}
//定義一個方法,方法裏面需要閉包類型參數
def method1 (Closure closure) {
closure()
}
//調用方法
method1(b1)
結果:輸出hello b1
例如2:
//定義一個閉包,帶參數
def b2 = {
v->
println "hello ${v}"
}
//定義一個方法,方法裏面需要閉包類型參數
def method2 (Closure closure) {
closure("xiaoma")
}
//調用方法
method2(b2)
結果:輸出hello xiaoma
例如3:
//多個參數以逗號分隔,參數類型和方法一樣可以顯式聲明也可省略。
def closure = { String x, int y ->
println "hey {y}"
}
3、元編程
groovy運行時類方法調用流程:
在java中,如果對象調用了一個類中沒有定義過的方法時,連編譯都編譯不過,但是在groovy中,情況則不同(可以編譯通過),根據圖中流程可以知道,運行期間,當對象調用了一個類中沒有的方法時,會依次調用metaClass中的同名方法,類中的methodMissing(String name, Object args)方法,類中的invokeMethod(String name, Object args)方法,執行到其中一個便停止後續方法查找調用。
三、Gradle項目編譯
1.Android Gradle項目結構
含有兩個子模塊(app和remoteDiagnosisLibrary)的項目結構如下:
1.1gradle.properties
可以在 gradle.properties 文件中配置一些變量,這些變量在這個工程下的所有module的build.gradle文件裏都可以使用。這樣就可以把一些共用的變量放到這裏,這樣後面修改的時候就可以只修改這個變量,不用各個模塊都要修改了。
上圖項目結構中的gradle.properties如下:
1.2settings.gradle
Gradle試圖找到一個設置(settings.gradle)。爲此,運行時將目錄樹的層次結構遍歷到根目錄。一旦找到設置文件,算法就停止搜索。
總是添加一個設置到構建的根目錄,以避免初始性能影響。
上圖項目結構中的settings.gradle如下:
1.3build.gradle
配置腳本文件名默認是不變的build.gradle,每一個project(模塊)對應一個build.gradle。
2.編譯執行流程
一次Gradle的工作流分爲3大部分:
第一:初始化。
Gradle支持單個和多個項目的構建。在初始化階段,Gradle確定哪些項目將參與構建,併爲每個項目創建一個項目實例。
第二:配置。
在此階段,將配置項目對象。作爲構建的一部分的所有項目的構建腳本都被執行。
第三:執行。
Gradle確定在配置階段創建和配置的要執行的任務的子集。子集由傳遞給gradle命令和當前目錄的任務名參數決定。然後Gradle執行每一個選擇的任務。
實例1:創建task
task haha{
println("hahaha")
doLast{
println("ccccc")
}
doFirst{
println("aaaaa")
}
doLast{
println("bbbbbb")
}
println("endendend")
}
注:
doFirst:將給定添加Action到此任務的操作列表的開頭。
doLast:將給定添加Action到此任務的操作列表的最後。
執行haha task,結果如下
Configure project:打印表明是第二階段:配置階段
Task:haha打印表明是第三階段:執行階段這個地方特別理解一下:
1、dolast方法創建的任務,在配置階段只是創建執行的任務,真正執行是在執行階段。所以hahaha打印在configure階段,cccccc打印在task階段
2、執行階段task的順序
沒有順序之前是按照字母順序排列,可以通過依賴方法(dependsOn)、doFirst、doLast調整順序
3.模塊Project
1、每個項目都會有自己的gradle領域,配置腳本文件名默認是不變的build.gradle
2、Project之間如果出現父子關係,只有根Project纔會有setting.gradle配置文件,該配置文件的作用是聲明其包含的子項目。
3、Project代表一個項目,在jvm中的一個實例。Build.gradle中無主的方法都可以在project中找到
4.任務Task介紹
1.概述
task,如其名:任務,gradle就是由一個一個任務來完成的。他其實也是一個類,有自己的屬性,也可以"繼承",甚至他還有自己的生命週期。Task是構建中的最小執行單元。
task的基類是DefaultTask ,我們也可以自定義一個task,必須繼承DefaultTask,如下:
class MyTask extends DefaultTask {
String message = 'This is MyTask'
// @TaskAction 表示該Task要執行的動作,即在調用該Task時,hello()方法將被執行
@TaskAction
def hello(){
println "Hello gradle. $message"
}
}
2.默認Task
Gradle 允許在腳本中定義一個或多個默認任務.
2.1 添加默認任務的方法
在build.gradle中調用defaultTasks方法,將要設置成默認的task方法傳入進去。
2.2 實例
build.gradle
defaultTasks 'clean', 'run'
task clean << {
println 'Default Cleaning!'
}
task run << {
println 'Default Running!'
}
task other << {
println "I'm not a default task!"
}
gradle -q 命令的輸出:
gradle -q
Default Cleaning!
Default Running!
結果等價於執行編譯命令gradle clean run。
在一個多項目構建中, 每一個子項目都可以有它特別的默認任務. 如果一個子項目沒有特別的默認任務, 父項目的默認任務將會被執行.
3.自定義Task
如下:vpsclient項目的gradle.build中創建了一個clean任務。
4.Gradle、Settings、Project、Task之間關係
Gradle
表示對Gradle的調用。
Settings
聲明實例化和配置Project要參與構建的實例的層次結構所需的配置。
對應的文件是setting.gradle。
Project
Project代表一個項目,在jvm中的一個實例。該接口是用於與構建文件中的Gradle交互的主要API。從中Project,您可以通過編程方式訪問Gradle的所有功能。
Project和build.gradle 文件之間存在一對一的關係。
Task
Task代表構建的一項基本工作,例如編譯類或生成javadoc。
四者之間的聯繫:
1、執行gradle命令時,會創建一個gradle對象。
2、在構建初始化過程中,Gradle爲每個要參與構建的項目裝配一個項目對象,具體如下:
爲構建創建Settings實例。
Settings。gradle腳本,如果存在,針對設置對象來配置它。
使用已配置的Settings對象創建Project實例的層次結構。
最後,Project通過build.gradle針對項目執行其文件(如果存在)來評估每個文件。這些項目以廣度順序進行評估,因此在其子項目之前先對其進行評估。可以通過調用Project.evaluationDependsOnChildren()或添加使用的顯式評估依賴項來覆蓋此順序Project.evaluationDependsOn(java.lang.String)。
3、Project本質上是Task對象的集合。每個Task都屬於一個Project。
四、Gradle配置
1、Build.gradle配置文件Demo
重要的屬性:
android屬性
設置編譯android項目的參數,構建android項目的所有配置都寫在這裏。
實例說明:
android {
// 編譯SDK的版本
compileSdkVersion 22
// build tools的版本
buildToolsVersion "23.0.1"
//aapt配置
aaptOptions {
//不用壓縮的文件
noCompress 'pak', 'dat', 'bin', 'notice'
//打包時候要忽略的文件
ignoreAssetsPattern "!.svn:!.git"
//分包
multiDexEnabled true
//--extra-packages是爲資源文件設置別名:意思是通過該應用包名+R,com.android.test1.R和com.android.test2.R都可以訪問到資源
additionalParameters '--extra-packages', 'com.android.test1','--extra-packages','com.android.test2'
}
//默認配置
defaultConfig {
//應用的包名
applicationId "com.example.heqiang.androiddemo"
minSdkVersion 21
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
//編譯配置
compileOptions {
// java版本
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
//源文件目錄設置
sourceSets {
main {
//jni lib的位置
jniLibs.srcDirs = jniLibs.srcDirs << 'src/jniLibs'
//定義多個資源文件夾,這種情況下,兩個資源文件夾具有相同優先級,即如果一個資源在兩個文件夾都聲明瞭,合併會報錯。
res.srcDirs = ['src/main/res', 'src/main/res2']
//指定多個源文件目錄
java.srcDirs = ['src/main/java', 'src/main/aidl']
}
}
//簽名配置
signingConfigs {
debug {
keyAlias 'androiddebugkey'
keyPassword 'android'
storeFile file('keystore/debug.keystore')
storePassword 'android'
}
}
buildTypes {
//release版本配置
release {
debuggable false
// 是否進行混淆
minifyEnabled true
//去除沒有用到的資源文件,要求minifyEnabled爲true才生效
shrinkResources true
// 混淆文件的位置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.debug
//ndk的一些相關配置,也可以放到defaultConfig裏面。
//指定要ndk需要兼容的架構(這樣其他依賴包裏mips,x86,arm-v8之類的so會被過濾掉)
ndk {
abiFilter "armeabi"
}
}
//debug版本配置
debug {
debuggable true
// 是否進行混淆
minifyEnabled false
//去除沒有用到的資源文件,要求minifyEnabled爲true才生效
shrinkResources true
// 混淆文件的位置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.debug
//ndk的一些相關配置,也可以放到defaultConfig裏面。
//指定要ndk需要兼容的架構(這樣其他依賴包裏mips,x86,arm-v8之類的so會被過濾掉)
ndk {
abiFilter "armeabi"
}
}
}
// lint配置
lintOptions {
//移除lint檢查的error
abortOnError false
//禁止掉某些lint檢查
disable 'NewApi'
}
}
除了上面寫的,在android{}塊中可以包含以下直接配置項:
productFlavors{ } 產品風格配置,ProductFlavor類型
testOptions{ } 測試配置,TestOptions類型
dexOptions{ } dex配置,DexOptions類型
packagingOptions{ } PackagingOptions類型
jacoco{ } JacocoExtension類型。用於設定 jacoco版本
splits{ } Splits類型。
dependencies屬性
gradle中所有的jar包的座標都放在這個屬性內,每個jar包都包含三個基本元素(group,name,version)。
2、Gradle構建語言幫助文檔地址
Gradle配置Build.gradle腳本語言幫助文檔地址:
https://docs.gradle.org/current/dsl/
3、修改成國內源(阿里源)
在 project 的 build.gradle中修改如下:
allprojects {
repositories {
//jcenter()
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
}
}
然後點擊 gradle rync 即可。
4、自定義gradle插件
4.1 二進制插件
apply plugin: 'xxx' //聲明引用插件的類型
如騰訊shadow中buildScripts/gradle/maven.gradle:
4.2 應用腳本插件
apply from:'xxx' //表示引用其他的配置文件
如騰訊shadow中gradle.build:
就是引用了buildScripts/gradle/下面的兩個配置文件
五、Gradle自定義構建
1、構建的變體
1.1 概述
構建變體是構建版本和生產版本的結合體。當你創建了一個構建版本或者生產版本,同樣的,新的變體也會被創建。
像下圖便有這麼多的變體:
1.2 創建構建變體
flavorDimensions "channel","money"
android {
productFlavors {
vivo {
dimension "channel"
applicationId "vivo"
versionCode 1
minSdkVersion 15
}
oppo {
dimension "channel"
applicationId "oppo"
versionCode 2
minSdkVersion 15
}
free {
dimension "money"
resValue "color", "colorfree", "#ff8888"
}
vip {
dimension "money"
resValue "color", "colorfree", "#ff0000"
}
}
}
2、自定義構建流程
2.1在某任務之前執行
Task diyTask = project.task('diyTask') {
doLast {
Utils.println("diy task run")
}
}
project.tasks.whenTaskAdded { Task theTask ->
if (theTask.name == 'assembleDebug') {
theTask.dependsOn(diyTask)
theTask.mustRunAfter(diyTask) // diyTask在assembleRelease之前執行
}
}
2.1在某任務之後執行
Task diyTask = project.task('diyTask') {
doLast {
Utils.println("diy task run")
}
}
project.tasks.whenTaskAdded { Task theTask ->
if (theTask.name == 'assembleRelease') {
theTask.dependsOn(diyTask) // diyTask在assembleRelease之後執行
}
}
六、Gradle命令
1、任務查詢和運行命令
查看任務
./gradlew tasks
查看所有任務 包括緩存任務等
./gradlew tasks --all
對某個module [moduleName] 的某個任務[TaskName] 運行
./gradlew :moduleName:taskName
2、快速構建命令
查看構建版本
./gradlew -v
清除build文件夾
./gradlew clean
檢查依賴並編譯打包
./gradlew build
編譯並安裝debug包
./gradlew installDebug
編譯並打印日誌
./gradlew build --info
譯並輸出性能報告,性能報告一般在 構建工程根目錄 build/reports/profile
./gradlew build --profile
調試模式構建並打印堆棧日誌
./gradlew build --info --debug --stacktrace
強制更新最新依賴,清除構建並構建
./gradlew clean build --refresh-dependencies
3、指定構建目標命令
編譯並打Debug包
./gradlew assembleDebug
這個是簡寫 assembleDebug
./gradlew aD
編譯並打Release的包
./gradlew assembleRelease
這個是簡寫 assembleRelease
./gradlew aR