gradle

Android Gradle(三)- gradle

2020-04-10  本文已影响0人  Stan_Z

上一篇对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文章写下来,基本是代码的形式,可能阅读并不是那么直观,但是这个比较符合我的习惯。方便查询吧。

上一篇下一篇

猜你喜欢

热点阅读