Gradle basics
Gradle build life cycle
- Initialization stage: Parse all Projects in the entire project and construct Project objects corresponding to all Projects
- Configuration phase: Parse tasks in all Project objects and build Task topology diagram
- Execution phase: execute specific tasks and dependent tasks
Monitor the Gradle build life cycle
Common APIs for monitoring life cycle: beforeEvaluate {}: After completing the initialization phase, before the configuration phase starts afterEvaluate {}: After completing the configuration phase, before the execution phase starts gradle.buildFinished {}: After the Gradle build execution is completed gradle.beforeProject {}: Function Same as beforeEvaluate gradle.afterProject {}: the same as afterEvaluate
自定义监听: gradle.addListener() gradle.addBuildListener() gradle.addProjectEvaluationListener()
Project
Project basics
Each Project corresponds to a build.gradle file; similar to Groovy Script files, every Groovy Script file will be compiled into a Script class by the compiler; Similarly, every build.gradle file will be compiled into a Project class by Gradle; therefore, All the code in build.gradle is essentially written in a Project class and is finally executed;
Project related API
All the code in build.gradle is executed in the configuration phase; the code in Task will be executed in the execution phase;
// 获取所有项目
getAllprojects()
// 获取所有子项目
getSubprojects()
// 获取根项目
getRootProject()
// 获取父项目
getParent()
// 对指定名称的 Project 进行操作,相当于在 app 项目的 build.gradle 文件中写代码
project('app') { Project project ->
group 'com.demo'
version '0.0.1.1'
println '---app---'
println project.group
println project.version
}
// 为所有project添加配置,包括根project本身
allprojects {
group 'com.demo'
version '0.0.1.1'
}
// 为所有子project添加配置
subprojects {
group 'com.demo'
version '0.0.1.1'
}
复制代码
Project attribute related API
Project important attributes:
// 默认 build 文件名称;正因为该属性,所以所有的 Project 都用 build.gradle 文件来进行构建
String DEFAULT_BUILD_FILE = "build.gradle";
// Project 和 Task 路径名的层次结构分隔符
String PATH_SEPARATOR = ":";
// 默认 build 文件保存路径
String DEFAULT_BUILD_DIR_NAME = "build";
//gradle 的 properties 文件
String GRADLE_PROPERTIES = "gradle.properties";
复制代码
Extended attribute usage method 1: In addition to the above-mentioned commonly used important attributes, gradle also supports custom extended attributes; extended attributes can be defined in its own Project or in rootProject; subProject will inherit all attributes in rootProject, so subProject can Directly use the attributes defined in rootProject;
// rootProject 定义扩展属性
ext {
sdkVersion = 28
constraintlayout = 'androidx.constraintlayout:constraintlayout:1.1.3'
}
// subProject 中使用
compileSdkVersion sdkVersion
implementation constraintlayout
复制代码
Extended attribute usage 2: You can also write all extended attributes individually to a gradle file that saves extended attributes; for example, the following myext.gradle file
// myext.gradle 文件
ext {
android = [
sdkVersion: 28
]
constraintlayout = 'androidx.constraintlayout:constraintlayout:1.1.3'
}
复制代码
When using, import myext.gradle in rootProject, and then use it in subProject;
// rootProject 引入 myext.gradle
apply from:this.file('myext.gradle')
// subProject 中使用
compileSdkVersion rootProject.ext.android.sdkVersion
implementation constraintlayout
复制代码
Extended properties usage 3: Extended properties can also be defined in the gradle.properties file, and then all projects can be used;
// gradle.properties 文件中定义
myCompileSdkVersion = 28
// Project 中使用
compileSdkVersion myCompileSdkVersion.toInteger()
复制代码
Project file related API
Path acquisition
// 根项目的路径
getRootDir()
// 当前项目的build路径
getBuildDir()
// 当前项目的路径
getProjectDir()
复制代码
File operations
// 相对路径获取文件
this.getContent('myext.gradle')
def getContent(String path) {
try {
// 传入当前project文件夹的相对路径
def file = file(path)
def files = files(path)
println file.text
} catch (GradleException e) {
println 'file path error'
}
}
// 复制文件
copy {
from file('myext.gradle')
into project('app').getProjectDir()
}
copy {
from file('build/outputs/apk/')
into getRootProject().getBuildDir().path + '/apk/'
exclude {
// 排除不需要copy的文件
}
rename {
// 对文件进行重命名
}
}
// 文件树进行遍历
fileTree('build/outputs/apk/') { FileTree fileTree ->
fileTree.visit { FileTreeElement element ->
println 'element file name:' + element.file.name
}
}
复制代码
Project depends on related API
Buildscript in Project
buildscript {
// 配置工程的仓库地址
repositories {
jcenter()
mavenCentral()
// 本地maven仓库
mavenLocal()
// 私有maven仓库
maven {
name 'mavendemo'
url 'http://mavendemo.com'
credentials {
username = 'joe'
password = 'secret'
}
}
}
// 配置 build.gradle 本身所需的依赖
// 与 Project.dependencies 不同,buildscript 中的 dependencies 依赖使用关键字 classpath
dependencies {
classpath 'com.android.tools.build:gradle:3.6.0'
}
}
复制代码
Dependencies in Project
// 项目代码中所需的依赖
dependencies {
// 配置本地 fileTree/file/files 依赖
implementation fileTree(dir: 'libs', include: ['*.jar'])
// 配置远程依赖
implementation 'androidx.appcompat:appcompat:1.1.0'
// 配置本地项目依赖
implementation project('app') {
// 排除指定 module 依赖
exclude module: 'support-v4'
// 排除指定 group 依赖
exclude group: 'com.android.support'
// 是否允许传递依赖
transitive false
}
}
复制代码
Project external command execution API
exec executes external commands
// 执行外部命令
task(name: 'apkcopy') {
doLast { // 执行阶段时执行
def srcPath = this.getBuildDir().path + '/outputs/apk/'
def desPath = 'Users/Administrator/Downloads'
def command = "mv -f ${srcPath} ${desPath}"
exec {
executable 'bash'
args '-c',command
}
}
}
复制代码
Task
Definition of Task
// 通过Task函数创建Task
task myTask {
// 配置阶段执行
println 'myTask do something'
// 执行阶段执行:task 操作列表的开头执行
doFirst {
println 'myTask doFirst'
}
// 执行阶段执行:task 操作列表的结尾执行
doLast {
println 'myTask doLast'
}
}
myTask.doFirst {
// 先执行外部 doFirst,再执行内部 doFirst
println 'myTask doFirst2'
}
// 通过TaskContainer创建Task
tasks.create('myTask2') {
println 'myTask2 do something'
}
复制代码
Task property configuration
// 配置Task相关属性
task myTask3(group: 'demo', description: 'myTask3') {
println 'myTask3 do something'
}
task myTask4 {
setGroup('demo')
setDescription('myTask4')
println 'myTask4 do something'
}
复制代码
Task dependency and execution order
dependsOn simple to use
// taskDemo2依赖于taskDemo1执行
task taskDemo1 {
doLast {
println 'doLast taskDemo1'
}
}
task taskDemo2 {
dependsOn(taskDemo1)
doLast {
println 'doLast taskDemo2'
}
}
复制代码
dependsOn advanced use
task lib1 {
doLast {
println 'doLast lib1'
}
}
task lib2 {
doLast {
println 'doLast lib2'
}
}
task nolib {
doLast {
println 'doLast nolib'
}
}
// myDemo2 任务依赖 lib Task
task myDemo2 {
// lib Task 必须要在 myDemo2 之前声明
dependsOn this.tasks.findAll { Task task ->
return task.name.startsWith('lib')
}
doLast {
println 'doLast myDemo2'
}
}
复制代码
mustRunAfter use
task taskSort1{
doLast {
println 'doLast taskSort1'
}
}
task taskSort2{
// 在指定任务之后才执行
mustRunAfter taskSort1
doLast {
println 'doLast taskSort2'
}
}
task taskSort3{
mustRunAfter taskSort2
doLast {
println 'doLast taskSort3'
}
}
复制代码
Task is attached to the life cycle
Attach to the build life cycle
// 通过 doLast 挂接到 build 方法之后
afterEvaluate {
def myBuild = getTasks().getByName('build')
if (myBuild == null) {
println 'myBuild null error'
return
}
myBuild.doLast {
println 'myBuild doLast'
}
}
// finalizedBy 的使用
task frontTask {
doLast {
println 'doLast frontTask'
}
}
task backTask {
// 在backTask任务执行之后执行frontTask
finalizedBy frontTask
doLast {
println 'doLast backTask'
}
}
// 通过 finalizedBy 挂接到 build 方法之后
task buildMyLog {
doLast {
println 'doLast buildMyLog'
}
}
afterEvaluate {
def myBuild = getTasks().getByName('build')
// 在myBuild任务执行之后执行buildMyLog
myBuild.finalizedBy buildMyLog
}
复制代码
Task type
Task common types
// 删除任务
task myDel(type: Delete) {
delete 'uglyFolder', 'uglyFile'
}
// 拷贝任务
task myCopy(type: Copy) {
from 'src/main/doc'
into 'build/target/doc'
}
// 执行任务
task myExec(type:Exec) {
workingDir '../tomcat/bin'
//on windows:
commandLine 'cmd', '/c', 'stop.bat'
//on linux
commandLine './stop.sh'
}
复制代码
Other modules
Settings
The Settings class in gradle initialization: org.gradle.api.initialization.Settings Settings Important property: String DEFAULT_SETTINGS_FILE = "settings.gradle"; This property makes the operations in the settings.gradle file ultimately correspond to the common methods of the Settings class: include Decide which projects to join the build
SourceSet
AndroidSourceSet class in Android: com.android.build.gradle.api.AndroidSourceSet SourceSets must have two SourceSets main/test by default, so the main closure will be configured in SourceSets;
sourceSets.getByName('main') {}
sourceSets.main {}
sourceSets { main {} }
复制代码
The above is to configure the SourceSet of main, and the code is equivalent;
// 指定源代码文件被Gradle编译的路径
android {
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
// 修改 res 资源目录;允许多个res文件夹
res.srcDirs = ['src/main/res',
'src/main/res-nfc',
'src/main/res-camera']
// 修改 assets 文件存放位置
assets.srcDirs = ['assets']
// 修改 so 库存放位置
jniLibs.srcDirs = ['libs']
}
}
复制代码
Detailed explanation of the properties of sourceSets:
java attribute: set the storage location of java code
main {
java {
// 存在的java代码路径
srcDirs = [
'src/main/java',
'src/main/myDemo/exclude'
]
// 针对我们设置的 “srcDirs” 文件夹路径,设置将哪些类不进行编译打包
excludes = ['myDemo/*.java']
// 针对我们设置的 “srcDirs” 文件夹路径,设置将哪些类进行编译打包;默认情况下该属性的值为**/*.java
includes = ["com/myDemo/MainActivity.java"]
}
}
复制代码
assets property: set the storage location of assets
assets.srcDirs 'src/main/assets', 'src/main/myAssets'
复制代码
aidl attribute: set the storage location of aidl
aidl.srcDirs 'src/main/aidl', 'src/main/myAidl'
复制代码
jni attribute: set the storage location of jni
jni.srcDirs 'src/main/jni','src/main/myJni'
复制代码
jniLibs attribute: set the storage location of jniLibs
jniLibs.srcDirs 'libs','mylibs'
复制代码
manifest attribute: set the storage location of the manifest
manifest.srcFile 'src/main/MyManifest.xml'
复制代码
res attribute: set the storage location of res
res.srcDirs 'src/main/res', 'src/main/res-debug'
复制代码
setRoot method: if setRoot is set, gradle will look for resources in the same level directory we set
main {
// 如果我们的代码都在同一个目录下,可以用setRoot进行设置,
// 设置了 setRoot 之后,gradle的编译只会在同级目录下找资源,
// 例如:只会在 src/mypath/java 找java代码
// 会忽略 java.srcDirs 设置的路径
setRoot 'src/mypath'
// 这个会忽略
java.srcDirs 'src/main/java'
}
复制代码
Plugin
Plugin is essentially an encapsulation of Task. The Task that needs to be executed is written into a plug-in, and then the tasks contained in the plug-in are executed through the plug-in; here, the plug-in is customized by creating the buildSrc folder locally;
1-在根 build.gradle 的同级目录下,创建 buildSrc 文件夹;
注:buildSrc 文件夹是 gradle 默认的自定义插件目录;如果有 buildSrc 文件夹存在,在 build 项目时,会优先构建 buildSrc 中的内容;
2-创建 buildSrc 文件夹后,rebuild 工程,会在 buildSrc 中自动创建内容;
3-在 buildSrc 文件夹中创建 build.gradle,通过 sourceSets 指定代码目录;
4-在 buildSrc 文件夹中创建 src/main/groovy 目录,在该目录中编写 Plugin/ProjectExtension/Task;
注:自定义 Plugin 可以直接通过 project.task('taskname')创建任务,也可以通过 project.task('taskname',type: MyTask)继承已经写好的任务;
5-在 buildSrc 文件夹中创建 src/main/resources 目录,在 resources 目录下创建目录 META-INF/gradle-plugins 目录,目录中创建 properties 文件,编写插件全类名;
6-在 project 中的 build.gradle 中使用插件 apply plugin: 'com.myplugin'
复制代码
Plugin reference material: blog.csdn.net/u010982507/... juejin.im/post/684490...
Android Gradle plugin
Reference material: blog.csdn.net/lyz_zyx/art... www.jianshu.com/p/c11862136...
Reference Materials "Gradle3.0 Automation Project Construction Technology Explained + Actual Combat"
Author: xinychan_juejin
link: https: //juejin.cn/post/6858423839970459655
Source: Nuggets
copyright reserved by the authors. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.