上一篇對groovy語法與核心api做了簡單總結,為gradle具體業(yè)務功能實現(xiàn)做了語言鋪墊,那么接下來進入到gradle api的學習。
一、gradle生命周期
gradle生命周期分為三個階段:
Initialization初始化階段: 各工程初始化,解析settings.gradle,構建所有project對應的project對象。
Configuration配置階段: 執(zhí)行所有工程中build.gradle的配置代碼,解析所有project對象中的task,構建task的拓撲圖。Task的執(zhí)行順序在配置階段就確定好了。
Execution執(zhí)行階段: 執(zhí)行task及其依賴task。
gradle部分生命周期監(jiān)聽回調
//配置階段開始前的監(jiān)聽回調
this.beforeEvaluate {
}
//配置階段完成以后的回調
this.afterEvaluate {
}
//當前project build完成
this.gradle.buildFinished {
}
//project構建之前
this.gradle.beforeProject {
}
//project構建之后
this.gradle.afterProject {
}
//其他監(jiān)聽
this.gradle.addBuildListener(new BuildListener() {
@Override
void buildStarted(Gradle gradle) {
}
@Override
void settingsEvaluated(Settings settings) {
}
@Override
void projectsLoaded(Gradle gradle) {
}
@Override
void projectsEvaluated(Gradle gradle) {
}
@Override
void buildFinished(BuildResult result) {
}
})
二、 project
gradle-5.4.1/src/core-api/org/gradle/api/Project.java
gradle中根工程和各module對應一個project,它是腳本入口。
project相關api
this.getProject() or this.project//獲取project
this.getRootProject() or this.rootProject//獲取根project
this.getSubprojects() or this.subprojects//獲取所有子project 根project獲取的子project即各個module
this.getParent() or this.parent//獲取父project
在build.gradle中方法的定義及調用
this.helloGradle()
def helloGradle() {
def allprojects = this.getAllprojects()
allprojects.each { project ->
println 'project name :' + project.name
}
}
//對app project 進行配置
project('app') { Project project ->
apply plugin: ‘...'
group ‘...'
version ‘...'
dependencies {...}
android {…}
...
}
屬性相關api
Project自帶屬性
public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
/**
* The default project build file name.
*/
String DEFAULT_BUILD_FILE = "build.gradle";
/**
* The hierarchy separator for project and task path names.
*/
String PATH_SEPARATOR = ":";
/**
* The default build directory name.
*/
String DEFAULT_BUILD_DIR_NAME = "build";
String GRADLE_PROPERTIES = "gradle.properties";
String SYSTEM_PROP_PREFIX = "systemProp";
String DEFAULT_VERSION = "unspecified";
String DEFAULT_STATUS = "release";
}
//使用ext閉包拓展屬性
ext {
compileSdkVersion = 29
}
//這里修改compileSdkVersion為例
Android{
compileSdkVersion [this.project.compileSdkVersion](http://this.project.compilesdkversion/)
}
//在gradle中引入文件
apply from :this.file('common.gradle’)
//在gradle中引入插件
apply plugin:'gradle-plugin’
//property基本操作
getProperty(‘')
setProperty('')
hasProperty(‘')
另外還可以在gradle.properties中配置 key - value形式的全局屬性
#key-value
isLoadTest=true
# 這里可以以key-value的形式定義全局的屬性,使用的時候需要用toBoolean() toInteger()等轉換
# 另外屬性命名不能與已有方法重名,這樣容易找不到屬性
//三方庫引入方式對比
2.X
compile: 編譯運行期都參與。
provided: 編譯期參與,運行時不參與
3.0之后:
compile 延伸出api 和 implementation。
api : 與compile效果一樣。
implementation : implementation依賴的庫只能自己庫本身訪問,例如:A依賴B,B依賴C,如果B依賴C是使用的implementation依賴,那么在A中是訪問不到C 中的方法的,如果需要訪問,請使用api依賴。其他與compile一致。
compileOnly: 與provided效果一樣。
其他:
runtimeOnly: 和apk效果一樣,打包時有效,不參與編譯。
testImplementation:和testCompile效果一樣,在單元測試和打包測試apk的時候有效。
debugImplementation:和debugCompile效果相同, 在debug模式下有效。
releaseImplementation:和releaseCompile效果相同,只在release模式和打包release包情況下有效。
文件相關api
路徑:
//工程根目錄
getRootDir().absolutePath //or this.rootDir
//工程目錄/build
getBuildDir().absolutePath //or this.buildDir
//module目錄
getProjectDir().absolutePath //or this.projectDir
//獲取文件
getFile('build.gradle')
def getFile(String path) {
try {
//new file要傳入絕對路徑,file()傳入相對路徑,相對于當前project開始查找
def file = file(path)//project的file方法獲取文件,files方法定位多個符合條件文件
return file.text
} catch (GradleException e) {
println 'file not found'
}
return null
}
//文件拷貝 from into
copy {
from file('build/outputs/apk/')
into getRootProject().getBuildDir().path + '/apk/'
//附加功能
exclude {} //包含
rename {} //重命名
}
//對文件樹進行遍歷
fileTree('build/outputs/apk/') { FileTree filetree ->
filetree.visit { FileTreeElement element ->
println 'the file name is:' + element.file.name
copy {
from element.file
into getRootProject().getBuildDir().path + 'test'
}
}
}
其他
buildscript { ScriptHandler scriptHandler ->
//gradle本身配置工程的倉庫地址
scriptHandler.repositories {}
//gradle本身配置工程的三方庫依賴地址
scriptHandler.dependencies {}
//對應project中的dependencies,是配置應用程序三方庫的依賴
}
三、task
gradle-5.4.1/src/core-api/org/gradle/api/Task.java
一個Task表示構建的單個原子動作。構建工作就是由各種Task構成的。
新建task兩種寫法:
//用task函數(shù)創(chuàng)建
task myTask {
println 'hello task'
}
//使用taskContainer容器創(chuàng)建
this.tasks.create(name: 'myTask') {
println 'hello task'
}
task所有可配置信息
public interface Task extends Comparable<Task>, ExtensionAware {
String TASK_NAME = "name";
String TASK_DESCRIPTION = "description";
String TASK_GROUP = "group";
String TASK_TYPE = "type";
String TASK_DEPENDS_ON = "dependsOn";
String TASK_OVERWRITE = "overwrite";
String TASK_ACTION = "action";
...
}
task在執(zhí)行階段的兩個回調:
doFirst{}//在已有的task之前去添加邏輯
doLast{}//在已有的task之后去添加邏輯
調用方式:
task myTask {
doLast{ //內部調用
}
}
//or
myTask.doLast{ //外部調用
}
小實例:計算prebuild到build的總時長
def startTime, endTime
//配置階段執(zhí)行完以后
this.afterEvaluate { Project project ->
//保證要找的task配置完成
def preBuildTask = project.tasks.getByName('preBuild')
preBuildTask.doFirst {
startTime = System.currentTimeMillis()
}
def buildTask = project.tasks.getByName('build')
buildTask.doLast {
endTime = System.currentTimeMillis()
println "the build time is ${endTime - startTime}"
}
}
gradle在配置階段會構建task的拓撲圖,這個過程組織好task的執(zhí)行順序
task依賴
dependsOn配置依賴
task taskX {
doLast {
println 'taskX'
}
}
靜態(tài)配置
//taskY在taskX之后執(zhí)行
task taskY(dependsOn:taskX) {
doLast {
println 'taskY'
}
}
//or
task taskY {
dependsOn taskX
doLast {
println 'taskY'
}
}
//or
taskY.dependsOn taskX
指定依賴之后,執(zhí)行taskY,會先執(zhí)行它依賴的taskX ,然后執(zhí)行它自己。
動態(tài)配置
task taskZ() {
dependsOn this.tasks.findAll { task ->
return task.name.startsWith('lib')//動態(tài)依賴lib開頭的task
}
doLast {
println 'taskZ'
}
}
task執(zhí)行順序
mustRunAfter()、shouldRunAfter()
只指定順序執(zhí)行,沒有依賴關系。
task taskZ {
mustRunAfter taskX //強制task在指定的task之后執(zhí)行
shouldRunAfter taskX //不強制性的
doLast {
println 'taskZ'
}
}
如果單獨執(zhí)行taskZ,那么就只會執(zhí)行taskZ,跟taskX和taskY無關,只有taskX、taskY、taskZ都執(zhí)行的時候,這個條件能約束執(zhí)行順序。
finalizedBy
taskX.finalizedBy taskY //執(zhí)行完taskX之后會拉起執(zhí)行taskY
總結:dependsOn指定依賴關系,先執(zhí)行依賴的task再執(zhí)行自己;finalizedBy是當前task執(zhí)行完成拉起讓自己結束的task;而mustRunAfter是多個執(zhí)行的task之前約束一個執(zhí)行順序,默認情況下無依賴關系的task執(zhí)行順序是隨機的。
task輸入輸出
TaskInputs、TaskOutputs
輸入輸出在Gradle中用于增量構建,執(zhí)行一個任務,如果在編譯時,gradle判斷在從上一次編譯中,該task的輸入輸出沒有任何改變,那么gradle就會跳過該task,前提是這個task至少有一個輸入或輸出。
支持的輸入輸出類型參考TaskInputs接口
inputs.file/files/property
outputs.file/files
四、Settings
在gradle中,通過執(zhí)行Settings類來完成構建的初始化階段。
最重要的是inlcude方法
include ':app', ':lib_network’ //配置工程子project
rootProject.name = ‘GradleDemo'
這里可以做條件判斷是否引入子project
if (hasProperty('isLoadTest') ? isLoadTest.toBoolean() : false) {
include ':Test'
}
對應兩個監(jiān)聽
gradle.settingsEvaluated {
println “Settings.gradle 初始化執(zhí)行結束"
}
gradle.projectsLoaded {Gradle gradle ->
println “Settings.gradle所有在 settings 中 include 的 Project 對象都創(chuàng)建完成了"
}
五、SourceSet
//5.4.1版本配置方法
android {
sourceSets {
// sourceSets的main對象,該對象屬于默認對象。
main {
resources {
srcDirs 'src/main/res', 'src/main/res-ad', 'src/main/res-player'
}
}
}
}
//3.0版本配置方法
// 配置源碼路徑。這個sourceSets是java插件引入的
sourceSets {
// 還可以根據(jù)productFlavors中的其他渠道配置對應的sourceSets對象。編譯時,會首先加載對應productFlavors中的資源,沒有則加載main中默認資源。
main {
manifest.srcFile 'AndroidManifest.xml'// 這是一個函數(shù)
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
groovy和gradle文章寫下來,基本是代碼的形式,可能閱讀并不是那么直觀,但是這個比較符合我的習慣。方便查詢吧。