Gradle 基础

Gradle 构建生命周期

  • 初始化阶段:解析整个工程中所有 Project,构建所有 Project 对应的 Project 对象

  • 配置阶段:解析所有 Project 对象中的 Task,构建 Task 拓扑图

  • 执行阶段:执行具体的 Task 以及依赖的 Task

监听 Gradle 构建生命周期

监听生命周期常用 API: beforeEvaluate {}:完成初始化阶段之后,配置阶段开始之前 afterEvaluate {}:完成配置阶段之后,执行阶段开始之前 gradle.buildFinished {}:Gradle 构建执行完成之后 gradle.beforeProject {}:作用等同于 beforeEvaluate gradle.afterProject {}:作用等同于 afterEvaluate

自定义监听: gradle.addListener() gradle.addBuildListener() gradle.addProjectEvaluationListener()

Project

Project 基础

每一个 Project 都对应一个 build.gradle 文件; 类似 Groovy Script 文件,每一个 Groovy Script 文件,都会被编译器编译成 Script 类; 同样,每一个 build.gradle 文件,都会被 Gradle 编译成 Project 类; 所以,build.gradle 中所有的代码,本质上是写在一个 Project 类内部,并最终被执行;

Project 相关 API

build.gradle 中所有的代码,都是在配置阶段执行; 在 Task 中的代码,才会在执行阶段执行;

// 获取所有项目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 属性相关 API

Project 重要属性:

// 默认 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";复制代码

扩展属性使用方式 1: 除了上述常用的重要属性,gradle 也支持自定义扩展属性; 扩展属性可以定义在本身 Project 中,也可以定义在 rootProject 中; subProject 中会继承 rootProject 中的所有属性,subProject 因此能直接使用定义在 rootProject 中的属性;

// rootProject 定义扩展属性ext {    sdkVersion = 28    constraintlayout = 'androidx.constraintlayout:constraintlayout:1.1.3'}//  subProject 中使用compileSdkVersion sdkVersionimplementation constraintlayout复制代码

扩展属性使用方式 2: 也可以单独将所有扩展属性,写到一个专门保存扩展属性的 gradle 文件中; 比如如下 myext.gradle 文件

// myext.gradle 文件ext {    android = [            sdkVersion: 28    ]    constraintlayout = 'androidx.constraintlayout:constraintlayout:1.1.3'}复制代码

使用时,在 rootProject 中引入 myext.gradle,然后在 subProject 中使用;

// rootProject 引入 myext.gradleapply from:this.file('myext.gradle')// subProject 中使用compileSdkVersion rootProject.ext.android.sdkVersionimplementation constraintlayout复制代码

扩展属性使用方式 3: 扩展属性也可以定义在 gradle.properties 文件中,然后所有 Project 都可以使用;

// gradle.properties 文件中定义myCompileSdkVersion = 28// Project 中使用compileSdkVersion myCompileSdkVersion.toInteger()复制代码

Project 文件相关 API

路径获取

// 根项目的路径getRootDir()// 当前项目的build路径getBuildDir()// 当前项目的路径getProjectDir()复制代码

文件操作

// 相对路径获取文件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 依赖相关 API

Project 中的 buildscript

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'    }}复制代码

Project 中的 dependencies

// 项目代码中所需的依赖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 外部命令执行 API

exec 执行外部命令

// 执行外部命令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

Task 的定义

// 通过Task函数创建Tasktask myTask {    // 配置阶段执行    println 'myTask do something'    // 执行阶段执行:task 操作列表的开头执行    doFirst {        println 'myTask doFirst'    }    // 执行阶段执行:task 操作列表的结尾执行    doLast {        println 'myTask doLast'    }}myTask.doFirst {    // 先执行外部 doFirst,再执行内部 doFirst    println 'myTask doFirst2'}// 通过TaskContainer创建Tasktasks.create('myTask2') {    println 'myTask2 do something'}复制代码

Task 的属性配置

// 配置Task相关属性task myTask3(group: 'demo', description: 'myTask3') {    println 'myTask3 do something'}task myTask4 {    setGroup('demo')    setDescription('myTask4')    println 'myTask4 do something'}复制代码

Task 的依赖与执行顺序

dependsOn 简单使用

// taskDemo2依赖于taskDemo1执行task taskDemo1 {    doLast {        println 'doLast taskDemo1'    }}task taskDemo2 {    dependsOn(taskDemo1)    doLast {        println 'doLast taskDemo2'    }}复制代码

dependsOn 进阶使用

task lib1 {    doLast {        println 'doLast lib1'    }}task lib2 {    doLast {        println 'doLast lib2'    }}task nolib {    doLast {        println 'doLast nolib'    }}// myDemo2 任务依赖 lib Tasktask myDemo2 {    // lib Task 必须要在 myDemo2 之前声明    dependsOn this.tasks.findAll { Task task ->        return task.name.startsWith('lib')    }    doLast {        println 'doLast myDemo2'    }}复制代码

mustRunAfter 使用

task taskSort1{    doLast {        println 'doLast taskSort1'    }}task taskSort2{    // 在指定任务之后才执行    mustRunAfter taskSort1    doLast {        println 'doLast taskSort2'    }}task taskSort3{    mustRunAfter taskSort2    doLast {        println 'doLast taskSort3'    }}复制代码

Task 挂接到生命周期

挂接到 build 生命周期

// 通过 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 的类型

Task 常用类型

// 删除任务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'}复制代码

其他模块

Settings

gradle 初始化中的 Settings 类:org.gradle.api.initialization.Settings Settings 重要属性:String DEFAULT_SETTINGS_FILE = "settings.gradle"; 该属性使得 settings.gradle 文件中的操作,最终会对应到 Settings 类 常用方法:include 决定哪些项目要加入构建

SourceSet

Android 中的 AndroidSourceSet 类:com.android.build.gradle.api.AndroidSourceSet SourceSets 中默认必须拥有 main/test 两个 SourceSet,因此会在 SourceSets 中配置 main 闭包;

sourceSets.getByName('main') {}sourceSets.main {}sourceSets { main {} }复制代码

上面都是对 main 这个 SourceSet 进行配置,其代码是等效的;

// 指定源代码文件被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']        }}复制代码

sourceSets 的属性详解:

java 属性:设置 java 代码的存放位置

main {    java {        // 存在的java代码路径        srcDirs = [                'src/main/java',                'src/main/myDemo/exclude'        ]        // 针对我们设置的 “srcDirs” 文件夹路径,设置将哪些类不进行编译打包        excludes = ['myDemo/*.java']        // 针对我们设置的 “srcDirs” 文件夹路径,设置将哪些类进行编译打包;默认情况下该属性的值为**/*.java        includes = ["com/myDemo/MainActivity.java"]    }}复制代码

assets 属性:设置 assets 的存放位置

assets.srcDirs 'src/main/assets', 'src/main/myAssets'复制代码

aidl 属性:设置 aidl 的存放位置

aidl.srcDirs 'src/main/aidl', 'src/main/myAidl'复制代码

jni 属性:设置 jni 的存放位置

jni.srcDirs 'src/main/jni','src/main/myJni'复制代码

jniLibs 属性:设置 jniLibs 的存放位置

jniLibs.srcDirs 'libs','mylibs'复制代码

manifest 属性:设置 manifest 的存放位置

manifest.srcFile 'src/main/MyManifest.xml'复制代码

res 属性:设置 res 的存放位置

res.srcDirs 'src/main/res', 'src/main/res-debug'复制代码

setRoot 方法:设置了 setRoot ,则 gradle 会在我们设置的同级目录下找资源

main {    // 如果我们的代码都在同一个目录下,可以用setRoot进行设置,    // 设置了 setRoot 之后,gradle的编译只会在同级目录下找资源,    // 例如:只会在 src/mypath/java 找java代码    // 会忽略 java.srcDirs 设置的路径    setRoot 'src/mypath'    // 这个会忽略    java.srcDirs 'src/main/java'}复制代码

Plugin

Plugin 本质上是对 Task 的封装,将所需要执行的 Task 编写成一个插件,然后通过插件来执行插件中包含的任务; 这里以本地创建 buildSrc 文件夹的方式来自定义插件;

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 参考资料: blog.csdn.net/u010982507/… juejin.im/post/684490…

Android Gradle 插件

参考资料: blog.csdn.net/lyz_zyx/art… www.jianshu.com/p/c11862136…

参考资料 慕课网 《Gradle3.0 自动化项目构建技术精讲 实战》

作者:xinychan_juejin
链接:https://juejin.cn/post/6858423839970459655
来源:掘金
著作权归作者所有。非商业转载请注明出处。

来源:https://www.icode9.com/content-4-833951.html

(0)

相关推荐