一、gradle 是什么
官方解釋是:
Gradle is an open-source build automation tool focused on flexibility and performance. Gradle build scripts are written using a Groovy or Kotlin DSL.
可以從三個角度來理解
1. gradle 是一個自動化構(gòu)建工具?
gradle 是通過組織一系列 task 來最終完成自動化構(gòu)建的墙歪,所以 task 是 gradle 里最重要的概念
我們以生成一個可用的 apk 為例铐然,整個過程要經(jīng)過 資源的處理忘衍,javac 編譯漓库,dex 打包愿伴,apk 打包踊赠,簽名等等步驟呵扛,每個步驟就對應(yīng)到 gradle 里的一個 task
gradle 可以類比做一條流水線,task 可以比作流水線上的機器人筐带,每個機器人負責不同的事情今穿,最終生成完整的構(gòu)建產(chǎn)物
2. gradle 腳本使用了 groovy 或者 kotlin DSL?
gradle 使用 groovy 或者 kotlin 編寫,不過目前還是 groovy 居多
那什么是 DSL 呢伦籍?DSL 也就是 Domain Specific Language 的簡稱蓝晒,是為了解決某一類任務(wù)專門設(shè)計的計算機語言
DSL 相對應(yīng)的是 GPL (General-Purpose Language)腮出,比如 java
與 GPL 相比起來,DSL 使用簡單芝薇,定義比較簡潔胚嘲,比起配置文件,DSL 又可以實現(xiàn)語言邏輯
對 gradle 腳本來說洛二,他實現(xiàn)了簡潔的定義馋劈,又有充分的語言邏輯,以 android {} 為例晾嘶,這本身是一個函數(shù)調(diào)用妓雾,參數(shù)是一個閉包,但是這種定義方式明顯要簡潔很多
3. gradle 基于 groovy 編寫垒迂,而 groovy 是基于 jvm 語言?
gradle 使用 groovy 編寫械姻,groovy 是基于 jvm 的語言,所以本質(zhì)上是面向?qū)ο蟮恼Z言机断,面向?qū)ο笳Z言的特點就是一切皆對象楷拳,所以,在 gradle 里毫缆,.gradle 腳本的本質(zhì)就是類的定義唯竹,一些配置項的本質(zhì)都是方法調(diào)用,參數(shù)是后面的 {} 閉包
比如 build.gradle 對應(yīng) Project 類苦丁,buildScript 對應(yīng) Project.buildScript 方法
二浸颓、gradle 項目分析
關(guān)于 gradle 的項目層次,我們新建一個項目看一下
2.1 settings.gradle
settings.gradle 是負責配置項目的腳本對應(yīng)Settings?類旺拉,gradle 構(gòu)建過程中产上,會根據(jù) settings.gradle 生成 Settings 的對象
對應(yīng)的可調(diào)用的方法在文檔里可以查找其中幾個主要的方法有:
include(projectPaths)
includeFlat(projectNames)
project(projectDir)
一般在項目里見到的引用子模塊的方法,就是使用 include蛾狗,這樣引用晋涣,子模塊位于根項目的下一級
include ':app'
如果想指定子模塊的位置,可以使用 project 方法獲取 Project 對象沉桌,設(shè)置其 projectDir 參數(shù)
include ':app'
project(':app').projectDir = new File('./app')
2.2 rootproject/build.gradle
build.gradle 負責整體項目的一些配置谢鹊,對應(yīng)的是?Project?類gradle 構(gòu)建的時候,會根據(jù) build.gradle 生成 Project 對象留凭,所以在 build.gradle 里寫的 dsl佃扼,其實都是 Project 接口的一些方法,Project 其實是一個接口蔼夜,真正的實現(xiàn)類是 DefaultProject?
build.gradle 里可以調(diào)用的方法在Project?可以查到其中幾個主要方法有:
buildscript // 配置腳本的 classpath
allprojects // 配置項目及其子項目
respositories // 配置倉庫地址兼耀,后面的依賴都會去這里配置的地址查找
dependencies // 配置項目的依賴
以 EasyGradle 項目來看
buildscript { // 配置項目的 classpath
? ? repositories {? // 項目的倉庫地址,會按順序依次查找
? ? ? ? google()
? ? ? ? jcenter()
? ? ? ? mavenLocal()
? ? }
? ? dependencies { // 項目的依賴
? ? ? ? classpath 'com.android.tools.build:gradle:3.0.1'
? ? ? ? classpath 'com.zy.plugin:myplugin:0.0.1'
? ? }
}
allprojects { // 子項目的配置
? ? repositories {
? ? ? ? google()
? ? ? ? jcenter()
? ? ? ? mavenLocal()
? ? }
}
2.3 module/build.gradle
build.gradle 是子項目的配置,對應(yīng)的也是 Project 類
子項目和根項目的配置是差不多的瘤运,不過在子項目里可以看到有一個明顯的區(qū)別窍霞,就是引用了一個插件 apply plugin "com.android.application",后面的 android dsl 就是 application 插件的 extension拯坟,關(guān)于 android plugin dsl 可以看
?android-gradle-dsl?
其中幾個主要方法有:
compileSdkVersion // 指定編譯需要的 sdk 版本
defaultConfig // 指定默認的屬性但金,會運用到所有的 variants 上
buildTypes // 一些編譯屬性可以在這里配置,可配置的所有屬性在?這里
productFlavor // 配置項目的 flavor
以 app 模塊的 build.gradle 來看
apply plugin: 'com.android.application' // 引入 android gradle 插件
android { // 配置 android gradle plugin 需要的內(nèi)容
? ? compileSdkVersion 26
? ? defaultConfig { // 版本郁季,applicationId 等配置
? ? ? ? applicationId "com.zy.easygradle"
? ? ? ? minSdkVersion 19
? ? ? ? targetSdkVersion 26
? ? ? ? versionCode 1
? ? ? ? versionName "1.0"
? ? }
? ? buildTypes {
? ? ? ? release {
? ? ? ? ? ? minifyEnabled false
? ? ? ? ? ? proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
? ? ? ? }
? ? }
? ? compileOptions { // 指定 java 版本
? ? ? ? sourceCompatibility 1.8
? ? ? ? targetCompatibility 1.8
? ? }
? ? // flavor 相關(guān)配置
? ? flavorDimensions "size", "color"
? ? productFlavors {
? ? ? ? big {
? ? ? ? ? ? dimension "size"
? ? ? ? }
? ? ? ? small {
? ? ? ? ? ? dimension "size"
? ? ? ? }
? ? ? ? blue {
? ? ? ? ? ? dimension "color"
? ? ? ? }
? ? ? ? red {
? ? ? ? ? ? dimension "color"
? ? ? ? }
? ? }
}
// 項目需要的依賴
dependencies {
? ? implementation fileTree(dir: 'libs', include: ['*.jar']) // jar 包依賴
? ? implementation 'com.android.support:appcompat-v7:26.1.0' // 遠程倉庫依賴
? ? implementation 'com.android.support.constraint:constraint-layout:1.1.3'
? ? implementation project(':module1') // 項目依賴
}
2.4 依賴
在 gradle 3.4 里引入了新的依賴配置傲绣,如下:
還是以 EasyGradle 為例,看一下各個依賴的不同:
項目里有三個模塊:app巩踏,module1, module2
模塊 app 中有一個類 ModuleApi
模塊 module1 中有一個類 Module1Api
模塊 module2 中有一個類 Module2Api
其依賴關(guān)系如下:
implementation 依賴?
當 module1 使用 implementation 依賴 module2 時续搀,在 app 模塊中無法引用到 Module2Api 類
api 依賴?
當 module1 使用 api 依賴 module2 時塞琼,在 app 模塊中可以正常引用到 Module2Api 類,如下圖
compileOnly 依賴?
當 module1 使用 compileOnly 依賴 module2 時禁舷,在編譯階段 app 模塊無法引用到 Module2Api 類彪杉,module1 中正常引用,但是在運行時會報錯
反編譯打包好的 apk牵咙,可以看到 Module2Api 是沒有被打包到 apk 里的
runtimeOnly 依賴?
當 module1 使用 runtimeOnly 依賴 module2 時派近,在編譯階段,module1 也無法引用到 Module2Api
2.5 flavor
在介紹下面的流程之前洁桌,先明確幾個概念渴丸,flavor,dimension另凌,variant
在 android gradle plugin 3.x 之后谱轨,每個 flavor 必須對應(yīng)一個 dimension,可以理解為 flavor 的分組吠谢,然后不同 dimension 里的 flavor 兩兩組合形成一個 variant
舉個例子
如下配置:
flavorDimensions "size", "color"
productFlavors {
? ? big {
? ? ? ? dimension "size"
? ? }
? ? small {
? ? ? ? dimension "size"
? ? }
? ? blue {
? ? ? ? dimension "color"
? ? }
? ? red {
? ? ? ? dimension "color"
? ? }
}
那么生成的 variant 對應(yīng)的就是 bigBlue土童,bigRed,smallBlue工坊,smallRed
每個 variant 可以對應(yīng)的使用 variantImplementation 來引入特定的依賴献汗,比如:bigBlueImplementation,只有在 編譯 bigBlue variant的時候才會引入