Android Gradle(三)- gradle
上一篇对groovy语法与核心api做了简单总结,为gradle具体业务功能实现做了语言铺垫,那么接下来进入到gradle api的学习。
一、gradle生命周期
gradle生命周期分为三个阶段:
Initialization初始化阶段
: 各工程初始化,解析settings.gradle,构建所有project对应的project对象。
Configuration配置阶段
: 执行所有工程中build.gradle的配置代码,解析所有project对象中的task,构建task的拓扑图。Task的执行顺序在配置阶段就确定好了。
Execution执行阶段
: 执行task及其依赖task。
gradle部分生命周期监听回调
//配置阶段开始前的监听回调
this.beforeEvaluate {
}
//配置阶段完成以后的回调
this.afterEvaluate {
}
//当前project build完成
this.gradle.buildFinished {
}
//project构建之前
this.gradle.beforeProject {
}
//project构建之后
this.gradle.afterProject {
}
//其他监听
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函数创建
task myTask {
println 'hello task'
}
//使用taskContainer容器创建
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在执行阶段的两个回调:
doFirst{}//在已有的task之前去添加逻辑
doLast{}//在已有的task之后去添加逻辑
调用方式:
task myTask {
doLast{ //内部调用
}
}
//or
myTask.doLast{ //外部调用
}
小实例:计算prebuild到build的总时长
def startTime, endTime
//配置阶段执行完以后
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的执行顺序
task依赖
dependsOn配置依赖
task taskX {
doLast {
println 'taskX'
}
}
静态配置
//taskY在taskX之后执行
task taskY(dependsOn:taskX) {
doLast {
println 'taskY'
}
}
//or
task taskY {
dependsOn taskX
doLast {
println 'taskY'
}
}
//or
taskY.dependsOn taskX
指定依赖之后,执行taskY,会先执行它依赖的taskX ,然后执行它自己。
动态配置
task taskZ() {
dependsOn this.tasks.findAll { task ->
return task.name.startsWith('lib')//动态依赖lib开头的task
}
doLast {
println 'taskZ'
}
}
task执行顺序
mustRunAfter()、shouldRunAfter()
只指定顺序执行,没有依赖关系。
task taskZ {
mustRunAfter taskX //强制task在指定的task之后执行
shouldRunAfter taskX //不强制性的
doLast {
println 'taskZ'
}
}
如果单独执行taskZ,那么就只会执行taskZ,跟taskX和taskY无关,只有taskX、taskY、taskZ都执行的时候,这个条件能约束执行顺序。
finalizedBy
taskX.finalizedBy taskY //执行完taskX之后会拉起执行taskY
总结:dependsOn指定依赖关系,先执行依赖的task再执行自己;finalizedBy是当前task执行完成拉起让自己结束的task;而mustRunAfter是多个执行的task之前约束一个执行顺序,默认情况下无依赖关系的task执行顺序是随机的。
task输入输出
TaskInputs、TaskOutputs
输入输出在Gradle中用于增量构建,执行一个任务,如果在编译时,gradle判断在从上一次编译中,该task的输入输出没有任何改变,那么gradle就会跳过该task,前提是这个task至少有一个输入或输出。
支持的输入输出类型参考TaskInputs接口
inputs.file/files/property
outputs.file/files
四、Settings
在gradle中,通过执行Settings类来完成构建的初始化阶段。
最重要的是inlcude方法
include ':app', ':lib_network’ //配置工程子project
rootProject.name = ‘GradleDemo'
这里可以做条件判断是否引入子project
if (hasProperty('isLoadTest') ? isLoadTest.toBoolean() : false) {
include ':Test'
}
对应两个监听
gradle.settingsEvaluated {
println “Settings.gradle 初始化执行结束"
}
gradle.projectsLoaded {Gradle gradle ->
println “Settings.gradle所有在 settings 中 include 的 Project 对象都创建完成了"
}
五、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 {
// 还可以根据productFlavors中的其他渠道配置对应的sourceSets对象。编译时,会首先加载对应productFlavors中的资源,没有则加载main中默认资源。
main {
manifest.srcFile 'AndroidManifest.xml'// 这是一个函数
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
groovy和gradle文章写下来,基本是代码的形式,可能阅读并不是那么直观,但是这个比较符合我的习惯。方便查询吧。