Gradle脚本基础全攻略

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流php

1 背景

在开始Gradle以前请务必保证本身已经初步了解了Groovy脚本,特别是闭包规则,若是还不了解Groovy则能够先看《Groovy脚本基础全攻略》这一篇博客速成一下Groovy基础,而后再看此文便可。关于Gradle速成干货基础详情也请参考Geadle官方网站,很差意思我太Low了。css

这里写图片描述

Gradle核心是基于Groovy的领域特定语言(DSL,具体概念参见《Groovy脚本基础全攻略》),具备很是好的扩展性,因此无论是简单的独立项目仍是大型的多项目构建它都能高效的提升构建任务,尤为对多项目支持是很是牛逼的;Gradle还提供了局部构建功能,譬如构建一个单独子项目时它会构建这个子项目依赖的全部子项目;固然了他对远程仓库和本地库的支持也很到位;哎呀,总以后面你就明白他的牛逼之处了。html

既然Gradle核心是Groovy,Groovy本质又是Java,因此很明显能够发现Gradle环境必须依赖JDK与Groovy库,具体以下:java

  • JDK版本必须是JDK6以上;git

  • 由于Gradle自带Groovy库, 因此已安装的Groovy会被Gradle忽略;github

具体Gradle环境配置好了之后以下图:web

这里写图片描述

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流正则表达式

这里写图片描述

2 Gradle DSL基础

Gradle的实质是配置脚本,执行一种类型的配置脚本时就会建立一个关联的对象,譬如执行Build script脚本就会建立一个Project对象,这个对象其实就是Gradle的代理对象。下面给出来各类类型Gradle对应的对象类型:spring

脚本类型 关联对象类型
Build script Project
Init script Gradle
Settings script Settings


Gradle的三种主要对象解释以下:编程

  • Project对象:每一个build.gradle会转换成一个Project对象。

  • Gradle对象:构建初始化时建立,整个构建执行过程当中只有这么一个对象,通常不多去修改这个默认配置脚本。

  • Settings对象:每一个settings.gradle会转换成一个Settings对象。

能够看见,当咱们编写指定类型Gradle脚本时咱们能够直接使用关联对象的属性和方法;固然了,每一个脚本也都实现了Script接口,也就是说咱们也能够直接使用Script接口的属性与方法。

2-1 构建脚本Build script(Project)

在Gradle中每一个待编译的工程都是一个Project(每一个工程的build.gradle对应一个Project对象),每一个Project在构建的时候都包含一系列Task,这些Task中不少又是Gradle的插件默认支持的。

PS:所谓的咱们编写Gradle脚本,实质大多数时候都是在编写构建脚本Build script,因此说Project和Script对象的属性和方法等API很是重要。

每个Project对象和build.gradle一一对应,一个项目在构建时都具有以下流程:

  1. 为当前项目建立一个Settings类型的实例。

  2. 若是当前项目存在settings.gradle文件,则经过该文件配置刚才建立的Settings实例。

  3. 经过Settings实例的配置建立项目层级结构的Project对象实例。

  4. 最后经过上面建立的项目层级结构Project对象实例去执行每一个Project对应的build.gradle脚本。

2-2 初始化脚本Init script(Gradle)和设置脚本Settings script(Settings)

Gradle对象:

初始化脚本Init script(Gradle)相似于Gradle的其余类型脚本,这种脚本在构建开始以前运行,主要的用途是为接下来的Build script作一些准备工做。咱们若是须要编写初始化脚本Init script,则能够把它按规则放置在USER_HOME/.gradle/相关目录下。譬如:

这里写图片描述

初始化脚本的Gradle对象表明了Gradle的调运,咱们能够经过调用Project对象的getGradle()方法得到Gradle实例对象。

Settings对象:

在对工程进行配置(譬如多项目树构建)时Settings实例与settings.gradle文件一一对应,它用来进行一些项目设置的配置。这个文件通常放置在工程的根目录。譬如:

这里写图片描述

2-3 Build生命周期

Gradle的构建脚本生命周期具有三大步,以下:

这里写图片描述

能够看见,生命周期其实和上面构建脚本Build script的执行流程是能够关联上的。有了这个流程图咱们接下里详细看下每一个过程。

settings.gradle文件:

除了构建脚本文件,Gradle还定义了一个约定名称的设置文件(默认为settings.gradle)。该文件在初始化阶段被执行,对于多项目构建必须保证在根目录下有settings.gradle文件,对于单项目构建设置文件是可选的,不过建议仍是写上。

以下是单项目构建的一个例子:

//settings.gradle
println 'This is executed during the initialization phase.'
//build.gradle
println 'This is executed during the configuration phase.'

task configured {
    println 'This is also executed during the configuration phase.'
}

task test << {
    println 'This is executed during the execution phase.'
}

task testBoth {
    doFirst {
      println 'This is executed first during the execution phase.'
    }
    doLast {
      println 'This is executed last during the execution phase.'
    }
    println 'This is executed during the configuration phase as well.'
}

运行构建结果:

> gradle test testBoth
This is executed during the initialization phase.
This is executed during the configuration phase.
This is also executed during the configuration phase.
This is executed during the configuration phase as well.
:test
This is executed during the execution phase.
:testBoth
This is executed first during the execution phase.
This is executed last during the execution phase.

BUILD SUCCESSFUL

Total time: 1 secs

Gradle多项目构建:

多项目构建老是须要指定一个树根,树中的每个节点表明一个项目,每个Project对象都指定有一个表示在树中位置的路径;在设置文件中咱们还可使用一套方法来自定义构建项目树。

//分层布局的多项目构建settings.gradle文件
include 'project1', 'project2:child', 'project3:child1'

上面例子中把project的路径做为了include方法的参数,譬如上面的’project3:child1’参数就指定了物理路径的project3/child1(project3/child1是相对于多项目根路径的相对路径),这也同时意味着会建立’project3’和’project3:child1’两个project。

//平面布局的多项目构建settings.gradle文件
includeFlat 'project3', 'project4'

上面例子中includeFlat方法接受目录名做为参数,可是特别注意,这些项目目录必须是根目录的兄弟目录。

固然了,设置文件中建立的多项目树实际上是由项目描述符来描述的,咱们能够在设置文件中随时修改这些描述符。以下:

//settings.gradle
rootProject.name = 'main'
project(':projectA').projectDir = new File(settingsDir, '../my-project-a')
project(':projectA').buildFileName = 'projectA.gradle'

能够看见,如上例子经过描述符更更名称和项目目录,而且创建了一个项目的文件。

Gradle构建初始化Initialization:

在初始化阶段若是咱们在根路径下直接指明settings.gradle文件和相关配置则构建初始化就会直接按照咱们的设置去构建项目,若是咱们没指明settings.gradle文件则Gradle会以必定的规则去寻找settings.gradle文件,而后依据寻找结果的不一样去决定如何构建项目。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

3 Gradle构建基础

经过上一章能够知道,每个Gradle构建都是由一个或多个project构成,每个project都是由一个或多个tasks构成,每一个task的实质实际上是一些更加细化的构建(譬如编译class、建立jar文件等)。

任务task基础:

以下例子咱们先来直观感觉一下task的概念,具体细节后面会探讨:

//建立一个名为build.gradle的文件
task hello {
    doLast {
        println 'Hello world!'
    }
}

//这是快捷写法,用<<替换doLast,后面解释
task hl << {
    println 'Hello world!'
}

//建立upper的task,使用Groovy语言编写
task upper << {
    String someString = 'mY_nAmE'
    println "Original: " + someString
    println "Upper case: " + someString.toUpperCase()
}

经过以下命令运行构建上面名为hello的task,具体以下:

xxx@XXX:~/$ gradle hello
:hello
Hello world!

BUILD SUCCESSFUL

Total time: 1.037 secs

能够看见,gradle命令会在当前目录中查找一个叫build.gradle的构建脚本文件,这个构建脚本定义了一个叫作hello的独立task,而且添加了一个action,咱们执行了这个task就获得了想要的结果。

在这里再多嘴一句,咱们看下task有无action的区别,以下:

//有Action的task
task actionTask << {  
    println 'I am actionTask'  
}  
//无Action的task
task noActionTask {  
    println 'I am noActionTask'  
}

必定要记住,在上面这个例子中若是task没有加<<则这个任务在脚本初始化initialization阶段(即不管执行啥task都被执行,具体参见上一章的第一个例子)被执行,若是加了<<则在gradle actionTask后才执行。由于没有加<<则闭包在task函数返回前会执行,而加了<<则变成调用actionTask.doLast(),因此会等到gradle actionTask时执行。

任务task依赖:

咱们经过上面task基础感觉的例子能够发现,一个build.gradle文件中定义多个task互相没有关系,决定执行的是咱们gradle命令后面跟的task名字;那咱们要是让他们之间有依赖关系咋办呢?以下:

task taskX(dependsOn: 'taskY') << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}

运行结果以下:

xxx@XXX:~/$ gradle taskX
:taskY
taskY
:taskX
taskX

BUILD SUCCESSFUL

Total time: 1.039 secs

动态任务task:

咱们还能够在Gradle中使用Groovy来建立动态task,以下:

4.times { counter ->
    task "task$counter" << {
        println "I'm task number $counter"
    }
}

运行结果以下:

xxx@XXX:~/$ gradle task1
:task1
I'm task number 1 BUILD SUCCESSFUL Total time: 1.397 secs

使用已存在任务task:

咱们除过在上面定义任务task时指明依赖之外还能够经过API为任务加入一个依赖,以下:

4.times { counter ->
    task "task$counter" << {
        println "I'm task number $counter"
    }
}
task0.dependsOn task2, task3

运行结果以下:

xxx@XXX:~/$ gradle task0
:task0
I'm task number 2 I'm task number 3
I'm task number 0 BUILD SUCCESSFUL Total time: 1.397 secs

或者咱们还能够经过API为任务加入一些新行为,以下:

task hello << { println 'Hello Earth' }
hello.doFirst { println 'Hello Venus' }
hello.doLast { println 'Hello Mars' }
hello << { println 'Hello Jupiter' }

运行结果以下:

xxx@XXX:~/$ gradle hello
:hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter

BUILD SUCCESSFUL

Total time: 1.397 secs

能够发现,doFirst和doLast能够被执行屡次,<<操做符实质就是doLast。

任务task短标记:

咱们能够经过美圆符将一个task做为另外一个task的属性,以下:

task hello << {
    println 'Hello world!'
}
hello.doLast {
    println "Greetings from the $hello.name task."
}

执行结果以下:

xxx@XXX:~/$ gradle hello
:hello
Hello world!
Greetings from the hello task.

BUILD SUCCESSFUL

Total time: 1.397 secs

能够看见,上面脚本中使用的name实际上是任务的默认属性, 表明当前任务的名称。

自定义任务task属性:

咱们还能够给任务task加入自定义的属性,以下例子:

task myTask {
    ext.myProperty = "myValue"
}

task printTaskProperties << {
    println myTask.myProperty
}

执行结果以下:

xxx@XXX:~/$ gradle printTaskProperties
:printTaskProperties
myValue

BUILD SUCCESSFUL

Total time: 1.397 secs

定义默认任务task:

Gradle容许在脚本中定义一个或多个默认任务,以下:

defaultTasks 'clean', 'run'

task clean << {
    println 'Default Cleaning!'
}

task run << {
    println 'Default Running!'
}

task other << {
    println "I'm not a default task!"
}

执行结果以下:

xxx@XXX:~/$ gradle
:clean,run
Default Cleaning!
Default Running!

BUILD SUCCESSFUL

Total time: 1.397 secs

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

4 Gradle依赖管理基础

大多数项目都不是彻底独立的,它们须要依赖其余项目进行编译等,Gradle容许你告诉它你项目的依赖关系,以便找到这些依赖关系,并在你的构建中维护这些依赖关系,依赖关系可能须要从远程的Maven等仓库中下载,也多是在本地文件系统中,或者是经过多项目构建另外一个构建,咱们称这个过程为依赖解析。

Gradle依赖声明:

关于依赖声明不解释,直接给个例子,以下:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
    testCompile group: 'junit', name: 'junit', version: '4.+'
}

Gradle依赖配置:

在Gradle中依赖能够组合成configurations(配置),一个配置简单地说就是一系列的依赖,通俗说也就是依赖配置;咱们可使用它们声明项目的外部依赖,也能够被用来声明项目的发布。下面咱们给出几种Java插件中常见的配置,以下:

  • compile
    用来编译项目源代码的依赖;

  • runtime
    在运行时被生成的类须要的依赖,默认项,包含编译时的依赖;

  • testCompile

    编译测试代码依赖,默认项,包含生成的类运行所需的依赖和编译源代码的依赖;

  • testRuntime

    运行测试所须要的依赖,默认项,包含上面三个依赖;

各类各样的插件支持许多标准的配置,咱们还能够定义本身的配置。

Gradle外部依赖:

咱们能够用Gradle声明许多种依赖,其中有一种是外部依赖(external dependency),它是在当前构建以外的一种依赖,通常存放在远程(譬如Maven)或本地的仓库里。以下是一个外部依赖的例子:

dependencies {
    compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
}

能够看见,引用一个外部依赖须要用到group、name、version属性。上面的写法还有一种简写,以下规则:

group:name:version

这是一个简写的例子:

dependencies { compile 'org.hibernate:hibernate-core:3.6.7.Final' }

Gradle仓库:

有了上面的外部依赖,你指定会想Gradle是咋找到那些外部依赖文件的。其实Gradle会在一个仓库(repository)里找这些依赖文件,仓库其实就是不少依赖文件的集合服务器, 他们经过group、name、version进行归类存储,好在Gradle能够解析好几种不一样的仓库形式(譬如Maven等),可是Gradle默认不提早定义任何仓库,咱们必须手动在使用外部依赖以前定义本身的仓库。

下面是一个使用MavenCentral仓库的例子:

repositories { mavenCentral() }

这是一个使用远程Maven仓库的例子:

repositories {
    maven {
        url "http://repo.mycompany.com/maven2"
    }
}

这是一个使用本地文件系统里库的例子:

repositories {
    ivy {
        // URL can refer to a local directory
        url "../local-repo"
    }
}

固然了,一个项目能够有好几个库,Gradle会根据依赖定义的顺序在各个库里寻找它们,在第一个库里找到了就不会再在第二个库里找它了,不然在第二个库找。

Gradle发布artifacts:

依赖配置也能够用来发布文件,咱们能够经过在uploadArchives任务里加入仓库来完成。下面是一个发布到Maven 库的例子,Gradle将生成和上传pom.xml,以下:

apply plugin: 'maven'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
        }
    }
}

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

5 Gradle命令

多任务调用命令:

gradle task1 task2 [...]

排除任务命令:

gradle -x task1 task2 [...]

失败后继续执行构建命令:

只要有任务调用失败Gradle默认就会中断执行,咱们可使用–continue选项在一次调用中不中断执行,而后发现全部失败缘由。

简化任务名命令:

当咱们调用某个任务时若是名字太长咱们能够采用简化操做,可是必须保证能够惟一区分出该任务的字符,譬如:

//简写
gradle -x t1
//替换
gradle -x task1

选择执行构建命令:

调用gradle命令默认会构建当前目录下的build.gradle文件,咱们可使用-b参数选择其余目录的构建文件且当使用此参数时settings.gradle将不会生效。以下:

//选择文件构建subdir/myproject.gradle
task hello << {
    println "using build file '$buildFile.name' in '$buildFile.parentFile.name'."
}

执行过程:

xxx@XXX:~/$ gradle -b subdir/myproject.gradle hello
:hello
using build file 'myproject.gradle' in 'subdir'.

BUILD SUCCESSFUL

Total time: 1.397 secs

此外咱们还可使用-p参数来指定构建的目录,譬如在多项目构建中能够用-p替代-b参数。以下执行过程:

xxx@XXX:~/$ gradle -p subdir hello
:hello
using build file 'build.gradle' in 'subdir'.

BUILD SUCCESSFUL

Total time: 1.397 secs

获取构建信息:

  • gradle projects命令:列出子项目名称列表。
  • gradle tasks命令:列出项目中全部任务。
  • gradle help –task someTask命令:能够显示指定任务的详细信息。
  • gradle dependencies命令:列出项目的依赖列表,全部依赖会根据任务区分,以树型结构展现。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

6 编写Gradle脚本

Gradle是以Groovy语言为基础,基于DSL语法的自动化构建工具,一个构建脚本可以包含任何Groovy语言元素,每一个脚本都是UTF-8编码的文件。

6-1 Project对象API

前面咱们说过,Gradle在构建脚本中定义了一个project,对于构建脚本中每一个project其实Gradle都建立了一个 Project类型的对象来关联,当构建脚本执行时它会去配置所关联的Project对象;构建脚本中每一个被调用的方法和属性都委托给了当前Project对象。

以下咱们看一个使用Project属性的例子:

println name
println project.name

上面两个println语句的输出是同样的;因为name属性没有在当前脚本中定义,因此能够像第一个那样使用自动委托 ,一般咱们使用第二中写法。

Project对象提供了一些标准的属性,咱们能够在构建脚本中很方便的使用他们,以下:

Name Type Default Value
project Project Project实例对象
name String 项目目录的名称
path String 项目的绝对路径
description String 项目描述
projectDir File 包含构建脚本的目录
build File projectDir/build
group Object 未具体说明
version Object 未具体说明
ant AntBuilder Ant实例对象

具体关于Project的方法详情参阅Project的API文档。这里咱们给出Project的apply方法的一个例子,以下:

//加载一个gradle文件
apply from: rootProject.getRootDir().getAbsolutePath() + "/common.gradle"

6-2 Script对象API

当Gradle执行一个脚本时它会将这个脚本编译为实现了Script的类(在上篇博客《Groovy脚本基础全攻略》Groovy的本质编译class代码那块有介绍),也就是说全部的属性和方法都是在Script的接口中声明。

6-3 Gradle对象API

关于Gradle对象的详细属性和API介绍点我便可。这里直接给出一个使用Gradle对象的例子,以下:

这里写图片描述

6-4 Gradle变量声明

在Gradle脚本中有两种类型的变量能够声明,以下:

  • 局部变量
  • 扩展变量

局部变量使用关键字def声明,它只在声明的地方可见,以下:

def dest = "dest"

    task copy(type: Copy) {
          form "source"
          into dest

    }

在Gradle中全部被加强的对象能够拥有自定义属性(譬如projects、tasks、source sets等),使用ext扩展块能够一次添加多个属性。以下:

apply plugin: "java"

ext {
    springVersion = "3.1.0.RELEASE"
    emailNotification = "build@master.org"
}

sourceSets.all { ext.purpose = null }

sourceSets {
    main {
        purpose = "production"
    }
    test {
        purpose = "test"
        }
    plugin {
        purpose = "production"
    }
}

task printProperties << {
    println springVersion
    println emailNotification
    sourceSets.matching { it.purpose == "production" }.each { println it.name}
}

上面咱们用一个ext扩展块向Project对象添加两个扩展属性,当这些扩展属性被添加后,它们就像预约义的属性同样能够被读写。

6-5 Gradle中Groovy使用

这个没啥说的,具体能够参考《Groovy脚本基础全攻略》这篇博客,里面有详细介绍。咱们这里粗略总结回忆一下便可:

  • Groovy会自动将一个属性的引用转换为相应的getter/setter方法。

  • Groovy调用方法时圆括号无关紧要。

  • Groovy为List和Map集合提供了一些操做捷径,譬如apply plugin:’java’中的plugin:’java’其实就是Groovy中的Map,apply是一个方法,省略了括弧而已。

哎呀,详细的仍是去看前一篇博客吧。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

7 Gradle文件操做基础

实际使用Gradle过程当中大多数时候须要操做文件,好在Gradle给咱们提供了一些API来快捷处理。

定位文件:

咱们可使用Project.file()方法来定位一个文件获取File对象(详情参考Project的API),以下:

//相对路径
File configFile = file('src/config.xml')
//绝对路径
File configFile = file(configFile.absolutePath)
//项目路径的文件对象 
File configFile = file(new File('src/config.xml'))

能够从Project的API发现file()方法可以接收任何形式的对象参数,它会将参数值转换为一个绝对文件对象,一般咱们能够传一个String或File实例;若是传的路径是绝对路径,则会被直接构造为一个文件实例,不然会被构造为项目目录加上传递目录的文件对象;固然了,file()方法还能识别URL(譬如file:/some/path.xml等)。

文件集合:

文件集合实际上是一组文件,Gradle使用FileCollection接口表示文件集合,Gradle API中许多类都实现了这个接口,譬如dependency configurations等。获取FileCollection实例的一种方法是Project.files(),咱们能够传递任何数量的对象参数。以下:

FileCollection collection = files('src/file1.txt',
                                  new File('src/file2.txt'),
                                  ['src/file3.txt', 'src/file4.txt'])

使用迭代操做还能将其转换为其余的一些类型,同时咱们还可使用+操做将两个文件集合合并,使用-操做对一个文件集合作减法。以下例子:

// 对文件集合进行迭代
collection.each {File file ->
    println file.name
}
 // 转换文件集合为其余类型
Set set = collection.files
Set set2 = collection as Set
List list = collection as List
String path = collection.asPath
File file = collection.singleFile
File file2 = collection as File
 // 增长和减小文件集合
def union = collection + files('src/file3.txt')
def different = collection - files('src/file3.txt')

咱们也能够向files()方法传递闭包或者可回调的实例参数,当查询集合的内容时就会调用它,而后将返回值转换为一些文件实例,返回值能够是files()方法支持的任何类型的对象。以下例子:

task list << {
    File srcDir

    // 使用闭合建立一个文件集合
    collection = files { srcDir.listFiles() }

    srcDir = file('src')
    println "Contents of $srcDir.name"
    collection.collect { relativePath(it) }.sort().each { println it }

    srcDir = file('src2')
    println "Contents of $srcDir.name"
    collection.collect { relativePath(it) }.sort().each { println it }
}

文件树:

文件树能够表明一个目录树结构或一个ZIP压缩文件的内容,FileTree继承自FileCollection,因此咱们能够像处理文件集合同样处理文件树,使用Project.fileTree()方法能够获得FileTree实例,它会建立一个基于基准目录的对象。以下:

/以一个基准目录建立一个文件树
FileTree tree = fileTree(dir: 'src/main')
 // 添加包含和排除规则
tree.include '**/*.java'
tree.exclude '**/Abstract*'
 // 使用路径建立一个树
tree = fileTree('src').include('**/*.java')
 // 使用闭合建立一个数
tree = fileTree('src') {
    include '**/*.java'
}
 // 使用map建立一个树
tree = fileTree(dir: 'src', include: '**/*.java')
tree = fileTree(dir: 'src', includes: ['**/*.java', '**/*.xml'])
tree = fileTree(dir: 'src', include: '**/*.java', exclude: '**/*test*/**')
 // 遍历文件树
tree.each {File file ->
    println file
}
 // 过滤文件树
FileTree filtered = tree.matching {
    include 'org/gradle/api/**'
}
 // 合并文件树A
FileTree sum = tree + fileTree(dir: 'src/test')
 // 访问文件数的元素
tree.visit {element ->
    println "$element.relativePath => $element.file"
}

咱们还可使用ZIP或TAR等压缩文件的内容做为文件树,Project.zipTree()和Project.tarTree()方法能够返回一个FileTree实例。以下:

// 使用路径建立一个ZIP文件
FileTree zip = zipTree('someFile.zip')

// 使用路径建立一个TAR文件
FileTree tar = tarTree('someFile.tar')

//TarTree能够根据文件扩展名获得压缩方式,若是咱们想明确的指定压缩方式则能够以下操做
FileTree someTar = tarTree(resources.gzip('someTar.ext'))

指定输入文件:

Gradle中有些对象的属性能够接收一组输入文件,譬如JavaComplile任务的source属性(定义编译的源文件)。以下:

//使用一个File对象设置源目录
compile {
    source = file('src/main/java')
}

//使用一个字符路径设置源目录
compile {
    source = 'src/main/java'
}

//使用一个集合设置多个源目录
compile {
    source = ['src/main/java', '../shared/java']
}

//使用FileCollection或者FileTree设置源目录
compile {
    source = fileTree(dir: 'src/main/java').matching {include 'org/gradle/api/**'}
}

//使用闭包设置源目录
compile {
    source = {
        // Use the contents of each zip file in the src dir
        file('src').listFiles().findAll {it.name.endsWith('.zip')}.collect { zipTree(it) }
    }
}

compile {
    //使用字符路径添加源目录
    source 'src/main/java', 'src/main/groovy'
    //使用File对象添加源目录
    source file('../shared/java')
    //使用闭包添加源目录
    source { file('src/test/').listFiles() }
}

复制文件:

咱们可使用复制任务(Copy)进行文件复制操做,复制任务扩展性很强,它能够过滤复制文件的内容,使用复制任务要提供想要复制的源文件和一个目标目录,若是要指定文件被复制时的转换方式则可使用复制规则,复制规则是一个CopySpec接口的实现,咱们使用CopySpec.from()方法指定源文件,CopySpec.into()方法指定目标目录便可。以下:

task copyTask(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'
}

task anotherCopyTask(type: Copy) {
    //复制src/main/webapp目录下的全部文件
    from 'src/main/webapp'
    //复制一个单独文件
    from 'src/staging/index.html'
    //复制一个任务输出的文件
    from copyTask
    //显式使用任务的outputs属性复制任务的输出文件
    from copyTaskWithPatterns.outputs
    //复制一个ZIP压缩文件的内容
    from zipTree('src/main/assets.zip')
    //指定目标目录
    into { getDestDir() }
}

task copyTaskWithPatterns(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'
    include '**/*.html'
    include '**/*.jsp'
    exclude { details -> details.file.name.endsWith('.html') &&
                         details.file.text.contains('staging') }
}

task copyMethod << {
    copy {
        from 'src/main/webapp'
        into 'build/explodedWar'
        include '**/*.html'
        include '**/*.jsp'
    }
}
 //在复制时重命名文件
task rename(type: Copy) {
    from 'src/main/webapp'
    into 'build/explodedWar'
    //使用闭包映射文件名
    rename { String fileName ->
        fileName.replace('-staging-', '')
    }
    // 使用正则表达式映射文件名
    rename '(.+)-staging-(.+)', '$1$2'
    rename(/(.+)-staging-(.+)/, '$1$2')
}

文件同步任务:

同步任务(Sync)继承自复制任务(Copy),当执行时会复制源文件到目标目录,而后从目标目录删除全部非复制文件。以下:

task libs(type: Sync) {
    from configurations.runtime
    into "$buildDir/libs"
}

建立归档文件:

使用归档任务能够建立Zip、Tar、Jar、War、Ear等归档文件,以下:

apply plugin: 'java'

task zip(type: Zip) {
    from 'src/dist'
    into('libs') {
        from configurations.runtime
    }
}

关于文件操做的其余请参考API文档。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

8 Gradle插件

8-1 Gradle插件概述

插件基础:

关于Gradle支持的插件能够点我搜索。其实Gradle的核心只是一个空空的框架,所谓的Gradle构建便捷脚本其实都是由插件提供支持的,插件添加了新的任务。在Gradle中通常有两种类型的插件,以下:

  • 脚本插件
    是额外的构建脚本,它会进一步配置构建,一般会在构建内部使用。脚本插件能够从本地文件系统或远程获取,若是从文件系统获取则是相对于项目目录,若是是远程获取则是由HTTP URL指定。

  • 二进制插件
    是实现了Plugin接口的类,而且采用编程的方式来操纵构建。

插件须要经过Project.apply()方法完成声明应用,相同的插件能够应用屡次。以下例子:

//脚本插件
apply from: 'other.gradle'

//二进制插件
apply plugin: 'java'

插件还可使用插件ID,插件的id做为给定插件的惟一标识符,咱们能够给插件注册一个缩写字符的id。譬以下面例子:

//经过Java插件的id进行引用
apply plugin: JavaPlugin

使用构建脚本块应用插件:

咱们能够向构建脚本中加入插件的类路径而后再应用插件和使用插件的任务,以下:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1"
    }
}

apply plugin: "com.jfrog.bintray"

Gradle插件拓展:

能够看见,Gradle实际上是依托于各类插件壮大的,譬如Java插件用来构建Java工程,Android插件用来构建打包Android工程,咱们只须要选择合适的插件便可,插件会为咱们提供丰富的任务用来快捷处理构建,具体详情参考各插件API便可。

8-2 Gradle的Java插件构建实例

上面说了,插件是Gradle的扩展,它会经过某种方式配置咱们的项目(譬如加入一些task);Gradle自带许多插件,咱们也能够编写本身的插件而后开源.,Java 插件就是这样的一个插件,该插件已经给项目定义了默认的参数(譬如Java源文件位置),因此一般咱们不须要在脚本中加入太多东西。

单个基础Java项目构建:

//把Java插件加入到项目中,也就是许多预约制的任务被自动加入到了项目里
apply plugin: 'java'

加入上面插件之后Gradle默认但愿能在src/main/java路径下找到源代码,在 src/test/java路径下找到测试代码,任何src/main/resources路径的文件都会被包含在JAR文件里,任何src/test/resources路径的文件都会被加入到classpath中以运行测试代码,全部的输出文件将会被建立在构建目录里,JAR文件存放在 build/libs文件夹里。

加入Java插件后咱们能够经过gradle tasks命令来列出项目的全部任务,这样就能够知道Java插件添加了哪些task。经常使用的task以下:

  • build task
    当运行gradle build命令时Gradle将会编译和测试你的代码,而且建立一个包含类和资源的JAR文件。

  • clean task
    当运行gradle clean命令时Gradle将会删除build生成的目录和全部生成的文件。

  • assemble task
    当运行gradle assemble命令时Gradle将会编译并打包代码,可是并不运行单元测试。

  • check task
    当运行gradle check命令时Gradle将会编译并测试你的代码,其余的插件会加入更多的检查步骤。

单个具备外部依赖的Java项目构建:

固然了,一个Java项目可能会有许多外部依赖(即调用第三方JAR),为了在项目里引用这些 JAR包,咱们须要告诉Gradle去哪里找他们,好在Gradle支持许多仓库,这些仓库能够被用来提取或者放置依赖,咱们能够很方便的从这些仓库中取得第三方Jar包。以下:

//加入Maven仓库
repositories {
    mavenCentral()
}

接着加入一些编译阶段来自于mavenCentral仓库的依赖,以下:

dependencies {
    //编译阶段
    compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
    //测试编译阶段
    testCompile group: 'junit', name: 'junit', version: '4.+'
}

定制构建项目:

Java插件给项目加入了一些属性,这些属性已经被赋予了默认的值且已经够咱们平常使用了,若是咱们以为这些默认属性很差也能够本身修改。以下:

//定制 MANIFEST.MF 文件
sourceCompatibility = 1.5
version = '1.0'
jar {
    manifest {
        attributes 'Implementation-Title': 'Gradle Quickstart', 'Implementation-Version': version
    }
}

默认Java插件加入的任务是常规性的任务,可是咱们能够定制任务,譬如咱们能够设置一个任务的属性、在任务中加入行为、改变任务的依赖、彻底重写一个任务等。以下:

//测试阶段加入一个系统属性
test {
    systemProperties 'property': 'value'
}

关于哪些属性是可用的问题,咱们可使用gradle properties命令列出项目的全部属性。

发布JAR文件:

一般JAR文件须要在某个地方发布,咱们能够经过Gradle方便的进行发布,譬以下面例子将发布到一个本地的目录,以下:

//uploadArchives task
uploadArchives {
    repositories {
       flatDir {
           dirs 'repos'
       }
    }
}

多Java项目构建:

在Gradle中为了定义一个多项目构建咱们须要建立一个设置文件(settings.gradle),设置文件放在源代码的根目录,它用来指定要包含哪一个项目且名字必须叫作settings.gradle。以下例子:

//多项目工程结构树:
multiproject/
  api/
  services/webservice/
  shared/
//多项目构建settings.gradle文件
include "shared", "api", "services:webservice", "services:shared"

对于大多数多项目构建有一些配置对全部项目都是通用的,因此咱们将在根项目里定义一个这样的通用配置(配置注入技术 configuration injection)。 根项目就像一个容器,subprojects方法遍历这个容器的全部元素而且注入指定的配置。以下:

//多项目构建通用配置
subprojects {
    apply plugin: 'java'
    apply plugin: 'eclipse-wtp'

    repositories {
       mavenCentral()
    }

    dependencies {
        testCompile 'junit:junit:4.11'
    }

    version = '1.0'

    jar {
        manifest.attributes provider: 'gradle'
    }
}

能够看见,上面通用配置把Java插件应用到了每个子项目中。

咱们还能够在同一个构建里加入项目之间的依赖,这样能够保证他们的前后关系。以下:

//api/build.gradle
dependencies {
    compile project(':shared')
}

至此基础的Java插件使用就OK了,深刻的请自行查看API。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

4 Gradle基础总结

到此Gradle的基础知识就彻底介绍完了,咱们对Gradle的框架也有了一个直观的认识。其实编写Gradle无非也就是对类的属性和方法进行调运操做,至于如何调运操做依据具体插件而异,核心的生命周期和几个对象实例搞明白基本上就能驾驭Gradle脚本了,其余的无非就是熟练度和API查找。

这里写图片描述