文章大纲

  • 引言
  • 一、Gradle 自定义扩展属性
    • 1、使用 def 变量名定义局部变量
    • 2、使用ext {}代码块声明全局变量
    • 3、使用android.ext. 或者dependencies.ext .等关键字定义局部变量
    • 4、在gradle.properties中定义全局变量
  • 二、Gradle 任务task
    • 1、通过task 名称形式定义任务
    • 2、task 的生命周期
    • 3、创建任务的执行顺序
      • 1、通过dependsOn 指定执行顺序
      • 2、通过mustRunAfter 、shouldRunAfter 、finalizedBy指定执行顺序
    • 4、继承AbstractTask 创建自定义的任务
      • 4.1、继承AbstractTask 并使用@TaskAction 注解run方法
      • 4.2、把自定义任务添加到Gradle 构造系统
      • 4.3、使用@Input为自定义任务标注输入和@OutputFile 标注输出
      • 4.4、设置Gradle 构建的方式
      • 4.5、通过系统提供的api 创建增强型任务
      • 4.6、通过tasks.getByName("name")获取系统任务
  • 三、Gradle构建生命周期

引言

前面的四篇文章中总结讲解了如何去利用Gradle 提供的属性和方法去灵活完成具体项目的构建,理论上来说对于大部分项目都已经足够了,但是并不意味着Gradle 仅仅支持这些功能,Gradle 作为高度灵活的构建系统,还支持扩展属性、自定义任务等一些高级功能。

  • Android 进阶——Android Studio 项目结构详细述及Gradle脚本语法完全解析(一)
  • Android 进阶——Android Studio 项目结构详细述及Gradle脚本语法android子节点buildTypes、productFlavors、variantFilt完全解析(二)
  • Android 进阶——Android Studio 项目结构详细述及Gradle脚本语法android剩余子节点配置完全解析(三)
  • Android 进阶——Android Studio 项目结构详细述及Gradle脚本语法dependencies节点和依赖管理完全解析(四)

一、Gradle 自定义扩展属性

所谓Gradle 自定义扩展属性本质就是自定义Groovy 中的变量,与其他语言一样,在Gradle脚本中我们可以通过很多种方式在build.gradle脚本(Project 或者Module目录下的)或者gradle.properties中定义属性(变量)

1、使用 def 变量名定义局部变量

使用关键字 def 可以只在声明变量的Gradle脚本文件中生效的局部变量,作用域仅在当前Gradle脚本。

//定义局部变量def loaclParam="crazy.mo"

2、使用ext {}代码块声明全局变量

使用ext{}代码块声明的变量为全局变量,作用域对所有子项目可见。

//在Project 下的build.gradle脚本下通过ext代码块定义一个所有子项目可见的全局变量ext {    globalParam="对所有子项目可见的变量"}

3、使用android.ext. 或者dependencies.ext .等关键字定义局部变量

在Project 类中任何对象都可以设置ext 也可以通过

//定义局部变量def loaclParam="crazy.mo"dependencies.ext.localParam2="局部变量2"android.ext.localParam3="局部变量3"ext.localParam4="局部变量4"//showLocal.ext.localParam5="局部变量5" 不能再这里定义,因为代码是从上往下开始执行的,此时showLocal对象还未生成task showLocal << {    println("局部变量2:" + loaclParam)    println("局部变量3:" + dependencies.ext.localParam2)    println("局部变量:" + android.ext.localParam3)    //println("局部变量:" + ext.localParam4)//这会报错不能这样访问,因为这样直接写相当于是去访问task下的ext.    println("局部变量4:" + localParam4)    println("局部变量4:" + project.ext.localParam4)//project 代表当前module下的,而rootProject则代表父Project下的    println("局部变量5:" + ext.localParam5)    println("ext:" + ext)    println("project.ext:" + project.ext)    println("showLocal.ext:" + showLocal.ext)}showLocal.ext.localParam5="局部变量5"

4、在gradle.properties中定义全局变量

二、Gradle 任务task

Gradle 完成构建操作本质上是通过一个个任务去完成的,如下图所示可以看到个任务的分组情况和依赖情况,所谓依赖就是执行某个任务的时候会自动去触发相依赖的任务,这也是为啥有时候我我们执行执行了assembleRelease任务,前面还会先去执行其他一系列的任务。

可以通过gradlew task --all 查看所有任务
也可以通过gradlew taskname 执行指定任务,甚至还可以通过驼峰缩写形式执行指定任务
(windows 环境下使用gradlew ,类Unix 使用./gradlew)

1、通过task 名称形式定义任务

通过关键字task 创建了一个任务时同时也创建了一个变量名称为task名的对象,如果不需要参数可以省略掉小括号,以下两种形式等价。

2、task 的生命周期

默认新建的task 对应的就是AbstractTask对象,而AbstractTask定义了几个周期方法,分别在task 任务配置期间doFirst执行任务前doLast 执行任务后去自动触发。

task customTask{    println("在任务配置期间执行")    doLast (new Action<Task>() {        @Override        void execute(Task task) {            println("任务开始执行后3...")        }    })    doLast (new Action<Task>() {        @Override        void execute(Task task) {            println("任务开始执行后...")        }    })    doFirst(new Action<Task>() {        @Override        void execute(Task task) {            println("任务开始执行前...")        }    })    doFirst(new Action<Task>() {        @Override        void execute(Task task) {            println("任务开始执行前2...")        }    })    doLast (new Action<Task>() {        @Override        void execute(Task task) {            println("任务开始执行后2...")        }    })}customTask.doLast(new Action<Task>() {    @Override    void execute(Task task) {        println("任务开始执行后 finaly...")    }})


另外在doLast 还有一种简洁的写法:

3、创建任务的执行顺序

1、通过dependsOn 指定执行顺序

通过dependsOn 指定taskThird在taskFirst和taskSecond 之后执行且taskSecond 在taskFirst之后执行。

task taskFirst <<{    println('第一个任务被执行')}task taskSecond <<{    println('第二个任务被执行')}//如果不指定taskFirst dependsOn taskSecond,即使把taskSecond写在前面taskSecond也不会先执行task taskThird(dependsOn:[taskSecond,taskFirst]) <<{    println('第三个任务被执行')}taskSecond dependsOn taskFirst 

2、通过mustRunAfter 、shouldRunAfter 、finalizedBy指定执行顺序

这些方法在AbstractTask中被实现。

//taskSecond dependsOn taskFirst//必须在taskSecond之后执行taskFirst.mustRunAfter taskSecond//并行编译,可能在其后面也可能在之前taskFirst.shouldRunAfter taskSecond//假如说这个任务用于释放资源,清理缓存task realseSrc <<{}//指定 realseSrc在taskThird 执行完毕之后运行taskThird.finalizedBy realseSrc

4、继承AbstractTask 创建自定义的任务

4.1、继承AbstractTask 并使用@TaskAction 注解run方法

要定义自定义任务,必须需要使用@TaskAction 标注核心方法(比如下例中run方法为这个自定义任务的核心逻辑),然后可以根据需要自定义构造方法或增加属性。

//定义一个Task 任务class CustomTask extends DefaultTask{       CustomTask() {        //[非必须]若不指定分组无论是通过集成还是task定义的任务都是默认存放于other分组中的,如果指定了group则会存放到定义的分组中        group 'Custom分组'        description '自定义任务的描述信息'    }    @TaskAction    void run(){        println("CustomTask 里真正处理的核心逻辑")    }}

4.2、把自定义任务添加到Gradle 构造系统

自定义任务添加到Gradle 构造系统后就可以通过gradlew 命令像执行系统的task 一样去执行自定义任务。

  • 通过 关键字tasks.create (String name, Class< T > type)
//添加到Gradle 构建系统 就可以通过gradlew mycustom 执行tasks.create("mycustom",CustomTask)
  • 通过使用关键字task 创建任务时传入type值
//添加到Gradle 构建系统 就可以通过gradlew mycustom 执行就会自动去调用run方法task mycustom(type:CustomTask){}

4.3、使用@Input为自定义任务标注输入和@OutputFile 标注输出

每一个任务都是可以包含输出和输出的,通常第一次执行的时候会耗时较长,而之后则会比较快,这正是因为增量执行的缘故,而增量判定的依据就是两个用于标注的输入输出是否一致,如果一致则跳过任务的核心逻辑(跳过时就会显示UPDATE-TO-DATE)。

class CustomTask extends DefaultTask{//可以传入n个文件、属性、目录或者路径    @Input    @Optional    String inputPath;    @OutputFile    File output;    CustomTask() {        //若不指定分组无论是通过集成还是task定义的任务都是默认存放于other分组中的,如果指定了group则会存放到定义的分组中        group 'Custom分组'        description '自定义任务的描述信息'    }    @TaskAction    void run(){        println("CustomTask 里真正处理的核心逻辑")    }}

如果指定了输入输出且没有使用@Optional标注(表示可选)的话则必须在任务配置阶段传入才能执行,否则会执行失败。

task mycustom(type:CustomTask){    inputPath="xxx/xx/.xx"    output="xx/xx.xxx"}

4.4、设置Gradle 构建的方式

通过outputs.upToDateWhen{}改变Gradle的构建方式,默认为true,返回false时则每次都会全量执行,即关闭增量构建

class CustomTask extends DefaultTask{    @Input    String inputPath;    @OutputFile    File output;    CustomTask() {        //若不指定分组无论是通过集成还是task定义的任务都是默认存放于other分组中的,如果指定了group则会存放到定义的分组中        group 'Custom分组'        description '自定义任务的描述信息'        outputs.upToDateWhen {            //默认为true,返回false时则每次都会全量执行,即关闭增量构建            true        }    }    @TaskAction    void run(){        println("CustomTask 里真正处理的核心逻辑")        //通过inputs.files拿到所有输入        inputs.files.first()        //inputs.files.singleFile()    }}//mycustom 为CustomTask的增强任务,事实上无论是系统的自定义的使用这样的语法声明之后,就自动建立了映射 ,执行这个任务就相当于是执行了CustomTask中被 @TaskAction 标注的方法。task mycustom(type:CustomTask){    ///inputPath="xxx/xx/.xx" 传入输入    //另一种方式通过调用file方法传入输入,就可以在run方法中通过inputs.files拿到输入信息    inputs.file file("xxx/xx/.xx")    output=file("xx/xx.xxx")}

上例中mycustom 为CustomTask的增强任务,事实上无论是系统的自定义的使用这样的语法声明之后,就自动建立了映射 ,执行这个任务就相当于是执行了CustomTask中被 @TaskAction 标注的方法。

4.5、通过系统提供的api 创建增强型任务

Gradle自身就定义了很多任务,欲知更多请访问Gradle官网,接下来我们以使用系统知道的Zip压缩指定目录为例

//public class Zip extends AbstractArchiveTasktask myZip(type: Zip){    //输出文件名    archiveName "myzip.zip"    //输出目录    destinationDir file("${buildDir}/myzip")    //设置指定目录为压缩源    from "${buildDir}/ouputs/logs"}

简单来说通过创建增强型任务,我们就可以在灵活地借助系统提供的api完成我们要的功能,这在后面进行自定义控件时非常好用。

4.6、通过tasks.getByName(“name”)获取系统任务

通过gradlew zip执行这个增强任务,系统的packageDebug相关的一系列任务会被先执行,然后把packageDebug任务的输出作为zip的输入被执行,最终把所有输出压缩为all.zip文件。

//在分析完 gradle完成之后才执行这个方法afterEvaluateafterEvaluate {    task zip(type: Zip) {        archiveName 'my.zip'        destinationDir file("${buildDir}/zip")        println tasks.getByName('assembleDebug')        from tasks.getByName('packageDebug').outputs.files    }}

三、Gradle构建生命周期

Gradle构建生命周期默认为以下三个步骤:

  • 首先是分析构建脚本,生成对应的Settings和Project类
  • 分别进行初始化配置
  • 执行对应的任务

而我们可以通过hook 来对Gradle 构建生命周期进行干预,只需要调用Gradle 提供的方法即可实现Hook。

//在分析完成gradle 之后执行afterEvaluate {}//对于引入了android插件的工程无效//beforeEvaluate {////}//gradle.addProjectEvaluationListener(new ProjectEvaluationListener() {//    @Override//    void beforeEvaluate(Project project) {////    }////    @Override//    void afterEvaluate(Project project, ProjectState state) {////    }//})//gradle 任务执行图//gradle.addListener(new TaskExecutionGraphListener(){////    @Override//    void graphPopulated(TaskExecutionGraph graph) {//        println graph.allTasks//    }//})

未完待续…

更多相关文章

  1. [Android] ProcessBuilder与Runtime.getRuntime().exec分别创建
  2. Android中AsyncTask的入门使用学习指南
  3. Android之自定义各种控件
  4. 高德天气应用开发之三:android 自定义控件实现(ActionBar + PageI
  5. Android(安卓)Android自定义的下拉列表框控件
  6. android: Handler概念理解与运用
  7. DrawingView android上的一个自定义涂鸦控件
  8. Android(安卓)Binder入门指南之getService详解之请求的反馈
  9. Android(安卓)Gradle构建-理解DSL语言以及运行机制

随机推荐

  1. Android 的singleLine废弃解决
  2. Android:Thread & Handler 线程 消息循环
  3. android 下载管理器
  4. Android 安全:移除不必要的三方依赖权限
  5. Android百度地图——SDK版本v2.0.0初探
  6. Qt on Android:创建可伸缩界面
  7. Linux 下编译Android-VLC开源播放器详解(
  8. Android运行时ART加载OAT文件的过程分析
  9. [Android]SMS Backup+ – 将短信同步备份
  10. 开启本地服务器,利用二维码进行通信[Demo]