Gradle基础学习
简介
- gradle 是一个自动化构建工具
- gradle 脚本使用了 groovy 或者 kotlin DSL
- gradle 基于 groovy 编写,而 groovy 是基于 jvm 语言
settings.gradle
settings.gradle 是负责配置项目的脚本 对应 Settings 类,gradle 构建过程中,会根据 settings.gradle 生成 Settings 的对象。对应的可调用的方法在文档里可以查找
rootproject/build.gradle
build.gradle 负责整体项目的一些配置,对应的是 Project 类
gradle 构建的时候,会根据 build.gradle 生成 Project 对象,所以在 build.gradle 里写的 dsl,其实都是 Project 接口的一些方法,Project 其实是一个接口,真正的实现类是 DefaultProject
build.gradle 里可以调用的方法在 Project 可以查到
其中几个主要方法有:
- buildscript // 配置脚本的 classpath
- allprojects // 配置项目及其子项目
- respositories // 配置仓库地址,后面的依赖都会去这里配置的地址查找
- dependencies // 配置项目的依赖
module/build.gradle
build.gradle 是子项目的配置,对应的也是 Project 类
子项目和根项目的配置是差不多的,不过在子项目里可以看到有一个明显的区别,就是引用了一个插件 apply plugin “com.android.application”,后面的 android dsl 就是 application 插件的 extension,关于 android plugin dsl 可以看 android-gradle-dsl
其中几个主要方法有:
- compileSdkVersion // 指定编译需要的 sdk 版本
- defaultConfig // 指定默认的属性,会运用到所有的 variants 上
- buildTypes // 一些编译属性可以在这里配置,可配置的所有属性在 这里
- productFlavor // 配置项目的 flavor
依赖
在 gradle 3.4 里引入了新的依赖配置,如下:
新配置 弃用配置 行为 作用
implementation compile 依赖项在编译时对模块可用,并且仅在运行时对模块的消费者可用。 对于大型多项目构建,使用 implementation 而不是 api/compile 可以显著缩短构建时间,因为它可以减少构建系统需要重新编译的项目量。 大多数应用和测试模块都应使用此配置。 api 只会暴露给直接依赖的模块,使用此配置,在模块修改以后,只会重新编译直接依赖的模块,间接依赖的模块不需要改动
api compile 依赖项在编译时对模块可用,并且在编译时和运行时还对模块的消费者可用。 此配置的行为类似于 compile(现在已弃用),一般情况下,您应当仅在库模块中使用它。 应用模块应使用 implementation,除非您想要将其 API 公开给单独的测试模块。 api 会暴露给间接依赖的模块,使用此配置,在模块修改以后,模块的直接依赖和间接依赖的模块都需要重新编译
compileOnly provided 依赖项仅在编译时对模块可用,并且在编译或运行时对其消费者不可用。 此配置的行为类似于 provided(现在已弃用)。 只在编译期间依赖模块,打包以后运行时不会依赖,可以用来解决一些库冲突的问题
runtimeOnly apk 依赖项仅在运行时对模块及其消费者可用。 此配置的行为类似于 apk(现在已弃用)。 只在运行时依赖模块,编译时不依赖
flavor
flavor,dimension,variant在 android gradle plugin 3.x 之后,每个 flavor 必须对应一个 dimension,可以理解为 flavor 的分组,然后不同 dimension 里的 flavor 两两组合形成一个 variant。
flavorDimensions "size", "color"
productFlavors {
big {
dimension "size"
}
small {
dimension "size"
}
blue {
dimension "color"
}
red {
dimension "color"
}
}
那么生成的 variant 对应的就是 bigBlue,bigRed,smallBlue,smallRed 每个 variant 可以对应的使用 variantImplementation 来引入特定的依赖,比如:bigBlueImplementation,只有在 编译 bigBlue variant的时候才会引入。
gradle wrapper
gradlew / gradlew.bat
这个文件用来下载特定版本的 gradle 然后执行的,就不需要开发者在本地再安装 gradle 了。这样做有什么好处呢?开发者在本地安装 gradle,会碰到的问题是不同项目使用不同版本的 gradle 怎么处理,用 wrapper 就很好的解决了这个问题,可以在不同项目里使用不同的 gradle 版本。gradle wrapper 一般下载在 GRADLE_CACHE/wrapper/dists 目录下
gradle/wrapper/gradle-wrapper.properties
是一些 gradlewrapper 的配置,其中用的比较多的就是 distributionUrl,可以执行 gradle 的下载地址和版本。
gradle/wrapper/gradle-wrapper.jar
是 gradlewrapper 运行需要的依赖包。
gradle init.gradle
在 gradle 里,有一种 init.gradle 比较特殊,这种脚本会在每个项目 build 之前先被调用,可以在其中做一些整体的初始化操作,比如配置 log 输出等等 使用 init.gradle 的方法:
-
通过 –init-script 指定 init.gradle 位置 eg: gradlew –init-script initdir/init.gradle
-
init.gradle 文件放在 USER_HOME/.gradle/ 目录下
-
gradle 脚本放在 USER_HOME/.gradle/init.d/ 目录下
-
gradle 脚本放在 GRDALE_HOME/init.d/ 目录下
gradle 生命周期及回调
gradle 构建分为三个阶段
- 初始化阶段
初始化阶段主要做的事情是有哪些项目需要被构建,然后为对应的项目创建 Project 对象 - 配置阶段
配置阶段主要做的事情是对上一步创建的项目进行配置,这时候会执行 build.gradle 脚本,并且会生成要执行的 task - 执行阶段
执行阶段主要做的事情就是执行 task,进行主要的构建工作 gradle 在构建过程中,会提供一些列回调接口,方便在不同的阶段做一些事情,主要的接口有下面几个
gradle.addBuildListener(new BuildListener() {
@Override
void buildStarted(Gradle gradle) {
println('构建开始')
// 这个回调一般不会调用,因为我们注册的时机太晚,注册的时候构建已经开始了,是 gradle 内部使用的
}
@Override
void settingsEvaluated(Settings settings) {
println('settings 文件解析完成')
}
@Override
void projectsLoaded(Gradle gradle) {
println('项目加载完成')
gradle.rootProject.subprojects.each { pro ->
pro.beforeEvaluate {
println("${pro.name} 项目配置之前调用")
}
pro.afterEvaluate{
println("${pro.name} 项目配置之后调用")
}
}
}
@Override
void projectsEvaluated(Gradle gradle) {
println('项目解析完成')
}
@Override
void buildFinished(BuildResult result) {
println('构建完成')
}
})
gradle.taskGraph.whenReady {
println("task 图构建完成")
}
gradle.taskGraph.beforeTask {
println("每个 task 执行前会调这个接口")
}
gradle.taskGraph.afterTask {
println("每个 task 执行完成会调这个接口")
}
自定义 task
task myTask {
println 'myTask in configuration'
doLast {
println 'myTask in run'
}
}
class MyTask extends DefaultTask {
@Input Boolean myInputs
@Output
@TaskAction
void start() {
}
}
tasks.create("mytask").doLast {
}
Android transform
android gradle plugin 提供了 transform api 用来在 .class to dex 过程中对 class 进行处理,可以理解为一种特殊的 Task,因为 transform 最终也会转化为 Task 去执行 要实现 transform 需要继承 com.android.build.api.transform.Transform 并实现其方法,实现了 Transform 以后,要想应用,就调用 project.android.registerTransform()