Gradle理论与实践三:Gradle构建脚本基础

814 阅读2分钟

本文已同步发表于我的微信公众号,微信搜索 代码说 即可关注,欢迎与我沟通交流。

Gradle系列相关文章: 1、Gradle理论与实践一:Gradle入门
2、Gradle理论与实践二:Groovy介绍
3、Gradle理论与实践三:Gradle构建脚本基础
4、Gradle理论与实践四:自定义Gradle插件
5、Gradle配置subprojects和allprojects的区别:subprojects和allprojects的区别

Gradle构建脚本基础

  • Project: 根据业务抽取出来的一个个独立的模块
  • Task:一个操作,一个原子性操作。比如上传一个jarmaven中心库等
  • Setting.gradle文件:初始化及整个工程的配置入口
  • build.gradle文件: 每个Project都会有个build.gradle的文件,是Project构建的入口。Root Project也有一个build.gradle文件,可以获取到所有的Child Project, 并且可以对所有的Child Project进行统一配置:如应用的三方插件、三方依赖库等。如,我们可以在Root Projectbuild.gradle文件里配置:
allprojects {
      repositories {
       jcenter()
      }
}

这样项目中所有依赖的三方库都可以在jcenter中下载了,省去了对每个Project去配置的情况。

上面用到的是allprojects,还可以配置subprojects,他们的区别在于:allprojects是对所有project的配置,包括Root Project。而subprojects是对所有Child Project的配置。更详细的请移步:https://blog.csdn.net/u013700502/article/details/85231687

1、创建一个task

Task的创建方式,可以是:

task hello {
     doFirst {
       print 'hello:doFirst\n'
     }
     doLast {
       print 'hello:doLast\n'
     }
}

也可以是:

tasks.create("hello") {
     doFirst {
       print 'hello:doFirst'
     }
     doLast {
       print 'hello:doLast'
     }
}

他们执行的结果都是一样的:

bogon:test_gradle mq$ gradle -q hello
hello:doFirst
hello:doLast

task是Project对象的一个函数,原型为Task create(String name, Closure configureClosure),最后一个参数是闭包的时候,可以放到括号外面,并且括号可以省略,task中的doFirstdoLast分别在任务前后执行。

2、创建Task的几种方式

  • 1、调用Project对象的task(String name)方法,如:
def Task hello = task(hello);

hello << {
    print 'hello\n'
}

输出:

bogon:test_gradle mq$ gradle -q hello
hello
  • 2、任务名字+闭包方式,如:
task hello {
    description '任务描述'
    doLast {
        print "方法原型: Task task(String name, Closure configureClosure)\n"
        print "任务描述: ${description}"
    }
}

输出结果:

bogon:test_gradle mq$ gradle -q hello
方法原型: Task task(String name, Closure configureClosure)
任务描述: 任务描述
  • 3、TaskContainer方式创建:
tasks.create('hello') {
    description '任务描述'
    doLast {
        print "方法原型: Task create(String name, Closure configureClosure)\n"
        print "任务描述: ${description}"
    }
}

输出结果:

方法原型: Task create(String name, Closure configureClosure)
任务描述: 任务描述

tasks是Project的属性,其类型是TaskContainer。其中1和2的创建最终也是调用TaskContainer方式创建的。

3、Task内部执行顺序

当我们执行Task的时候,就是执行其拥有的actions列表,是一个List。把Task执行之前、Task本身执行、Task之后执行分别称为doFirst、doSelf、doLast,先来看个例子:

def Task hello = task myTask(type: CustomTask);

hello.doFirst {
    print 'Task执行之前 do-First\n'
}

hello.doLast {
    print 'Task执行之后 do-Last\n'
}

class CustomTask extends DefaultTask {

    @TaskAction
    def doself() {
        print 'Task执行自身 do-self\n'
    }
}

输出:

bogon:test_gradle mq$ gradle -q hello
Task执行之前 do-First
Task执行自身 do-self
Task执行之后 do-Last

通过结果发现确实是按照我们想要的顺序执行的。Gradle在执行hello这个任务的时候,Gradle会解析其带有@TaskAction注解的方法作为其Task执行的Action,并且把其加入到actionList中。而doFirst、doLast分别会在actionList的最前面和最后面加入,所以之后就达到了按顺序执行。

4、Task任务依赖

任务之间是可以有依赖关系的,使用dependsOn执行当前task依赖的任务,如:

task hello << {
   print 'hello '
}

task world(dependsOn: hello) {
   doLast {
       print 'world'
   }
  }

此时执行gradle -q world,结果如下:

bogon:test_gradle mq$ gradle -q world
hello world

因为world任务是依赖hello的,所以当执行world后,先去执行了hello任务,再执行world任务。dependsOn是Task类的一个方法,可以接受多个依赖的任务作为参数。 修改以下程序:

task hello << {
   print 'hello\n'
}

task world(dependsOn: hello) {
   doLast {
       print 'world\n'
   }
}

world.doFirst {
   print 'doFirst\n'
}

world.doLast {
   print 'doLast2\n'
}

结果:

bogon:test_gradle mq$ gradle -q world
hello
doFirst
world
doLast2

通过结果可以看出,doFirst和doLast可以使用多次,并且按顺序执行doLast可以用 << 操作符替代。

5、自定义属性

ProjectTask允许添加额外自定义属性,通过对应的ext属性即可,如

//自定义一个Project的属性
ext.buildTime = '2018'

//自定义多个属性
ext {
   buildTime = '2018'
   month = '12'
}

task time {
     doLast {
       print "构建时间${buildTime} 年${month}月 \n"
     }
}

执行gradle -q time,执行结果:

bogon:test_gradle mq$ gradle -q time
构建时间201812

可见我们自定义的属性正确地取到了,自定义属性的作用域很广,只要能得到对应的Project,就能获取到定义的属性值。在Android中我们通常使用自定义属性值来定义我们的版本号、版本名称等,把这些放到一个单独的gradle文件中,因为他们在发版前就会变动,放到单独的gradle文件中便于管理,在AS根目录下新建config.gradle如下:

//config.gradle
ext {
      android = [
            compileSdkVersion: 26,
            buildToolsVersion: "25.0.0",
            versionName      : "6.2.1",
            versionCode      : 6210,
            minSdkVersion    : 16,
            targetSdkVersion : 23
      ]
    }

APP对应的build.gradle中取值:

//build.gradle
apply from: rootProject.getRootDir().getAbsolutePath() + '/config.gradle'

compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.android.buildToolsVersion

就可以获取到自定义的属性值。

上例中,除了能获取到config.gradle中的属性值,还可以在build.gradle中调用config.gradle中的方法,具体实现:

//config.gradle
ext {
    .......其他.........
    //注意方法和属性写法的区别
    copyApk = this.&copyApk
}

def copyApk() {

}

build.gradle调用:

//build.gradle
apply from: rootProject.getRootDir().getAbsolutePath() + '/config.gradle'

copyApk()

这样就实现了在build.gradle中调用config.gradle中的copyApk()方法了。

欢迎扫描下方二维码或搜索微信公众号 代码说, 关注我的微信公众号查看最新文章~