Gradle是一款非常优秀的构建系统工具,它的DSL是基于Groovy实现。可以方便通过代码控制这些DSL达到构建目的,Gradle构建大部分功能是通过插件方式来实现。
1.Gradle入门及Gradle Wrapper:
Wrappe是对Gradle的一层包装,便于团队在开发过程中统一Gradle构建版本,避免因为Gradle构建版本不同意带来的不必要麻烦。
- gradlew和gradlew.bat分别是Linux和window下的可执行脚本,用法跟Gradle原生命令一样;
- gradle-wrapper.jar是具体业务逻辑实现的jar包,gradlew最终还是使用Java执行这个jar包来执行相关Gradle操作;
- gradle-wrapper.properties是配置文件,用于配置使用哪个版本的Gradle等。
distributionBase=GRADLE_USER_HOME //下载Gradle压缩包解压后存储的主目录
distributionPath=wrapper/dists //相对于distributionBase解压后Gradle压缩包路径
zipStoreBase=GRADLE_USER_HOME //同distributionBase,只不过存放zip压缩包
zipStorePath=wrapper/dists //同distributionPath,只不过存放zip压缩包
//Gradle发行版压缩包的下载地址
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
gradle-wrapper.properties是由Wrapper Task生成的,可以自定义配置Wrapper Task来达到配置gradle-wrapper.properties。在build.gradle构建文件中录入脚本:
task Wrapper(type: Wrapper){
gradleVersion = '5.4.2'
distributionBase='GRADLE_USER_HOME'
distributionPath= 'wrapper/dists'
zipStoreBase= 'GRADLE_USER_HOME'
zipStorePath= 'wrapper/dists'
distributionUrl= 'https://services.gradle.org/distributions/gradle-5.4.1-all.zip'
}
- 也可以在Gradle脚本中加入日志信息:logger.info()等日志级别信息用于调试。
2.Groovy基础:
Groovy是基于JVM虚拟机的一种动态语言,它的语法与Java非常相似,由Java入门Groovy基本没有任何障碍。Groovy完全兼容Java,又在此基础上增加了很多动态类型和灵活特性,比如闭包,支持DSL,是一门非常灵活的动态脚本语言。
- 字符串:单引号和双引号都可以定义字符串,其中单引号标记是纯粹的字符串常量,而双引号是可以表示表达式中进行运算;
task printStringClass << {
def str1 = '单引号字符串'
def str2 = "双引号字符串"
}
- 集合:与Java中的相比更加简洁
task printList << {
def numList = [1,2,3,4]
println numList.getClass().getName()
println numList[2] //访问第三个元素
println numList[-1] //访问最后一个元素
numList.each {
println it //遍历访问
}
}
task printMap << {
def map1 = ['width':1920,'height':1080]
println map1.getClass().getName()
println map1['width']
map1.each {
println("key:${it.key},value:${it.value}")
}
}
- 方法:Groovy的调用方法时()可以省略,return可以省略当没有return时就会用最后一句代码作为返回值,代码块可以作为参数传递;
task invokeMethod << {
method1 1,2
method2(3,4)
}
def method1(int a,int b) {
println(a+b)
}
def method2(int a,int b) {
if (a > b) {
a
}else {
b
}
}
- JavaBean:在Java中访问和修改JavaBean的属性,要重复生成getter/setter方法。而Groovy不用;
- 闭包概念:是一段代码块;
task helloClosure << {
//使用自定义的闭包
customEeach {
print it
}
}
def customEeach(closure) {
for (int i = 0; i < 10; i++) {
closure(i)
}
}
- 向闭包传递参数:当参数为多个时需要一一列举出来;
task helloClosure << {
//使用自定义的闭包
eachMap {
// -> 用于把参数和主体区分开来
k,v ->
println("${k} is ${v}")
}
}
def eachMap(closure) {
def map1 = ["name":"王麻子","age":"18"]
map1.each {
closure(it.key,it.value)
}
}
- 闭包委托:Groovy的闭包有thisObject/owner/delegate三个属性,当在闭包内调用方法时,由它们来确定使用哪个对象来处理。默认delegate和owner时相等的,但delegate是可以被修改的;
task helloClosure << {
new Delegate().test {
println("thisObject:${thisObject.getClass()}")
}
}
class Delegate {
def test(Closure<Delegate> closure){
closure(this)
}
}
- DSL(Domain Specific Language):领域特定语言,专门专注特定领域的语言,它在于专,而不是全。Java是一种通用全面语言。
3.Gradle构建脚本基础:
- Settings文件:用于初始化以及工程树的配置,设置文件默认文件名为setting.gradle,放在根目录的工程下;
设置的大多的作用都是为了配置子工程,在Gradle中多个工程是通过工程树表示的。相当于Android Studio看到Project和Module概念一样。根目录相当于Android Studio的Project,一个根目录可以有很多子工程,也就是有很多Module。
- Build文件:每个Project都会有一个Build文件,该文件是该Project构建入口,可以在这里针对该Project进行配置,如配置版本/依赖库/添加入插件等;可在主Build文件设置所有子模块的配置信息。
subprojects {
apply plugin:'java'
repositories{
jcenter()
}
}
- Project以及Tasks:
在Gradle中可以有很多Project,可以定义创建一个Project用于生成jar/也可以定义另外一个Project生成war包等;一个Project就是在业务范围内,被抽象出来的一个个独立模块可以根据项目情况抽象归类,最后一个个Project组成整个Gradle;
一个Project中又包含很多Tasks,Tasks就是一个操作,一个原子性的操作。
- 创建Tasks:Tasks是Project对象的一个函数。原型为 create(String name,Closure configureClosure),第二个参数是一个闭包;
task helloClosure{
}
- 任务依赖:任务之间是可以有依赖关系的,可以控制任务先于哪个任务执行或后于哪个任务执行;在任务创建的时候,可以通过dependsOn指定其依赖的任务;
task helloClosure <<{
new Delegate().test {
println("thisObject:${thisObject.getClass()}")
}
}
task sayHello(dependsOn:helloClosure){
}
- 任务间通过API控制/交互:
创建一个任务和定义一个变量是一样的,变量名就是定义的任务名,可以使用任务名通过Tasks中API访问方法/属性/或对任务重新配置。
- 自定义属性:Project和Tasks都允许添加自定义属性,要添加自定义属性通过对应的ext属性即可实现;相比于局部变量自定义属性作用域是整个Project;
//自定义一个project的属性
ext age = 18
//自定义一个project的代码块属性
ext {
name = '王麻子'
age = 18
}
4.Gradle任务:
- 多种方式创建任务:
第一种直接以任务名创建任务的方式:
def Task taskOne = task(taskOne)
第二种以任务名字+一个该任务配置的Map对象来创建任务:
def Task taskTwo = task(taskTwo,group: BasePlugin.BUILD_GROUP)
Task参数中Map的可配置项:
配置项 | 描述 | 默认值 |
type | 基于存在的Task来创建,和继承类似 | DefultTask |
overwrite | 是否替换存在的Task,和type配合用 | false |
dependOn | 用于配置任务的依赖 | [] |
action | 添加到任务的一个action或闭包 | null |
decription | 用配置任务的描述 | null |
group | 用于配置任务的分组 | null |
第三种方式以任务名字+闭包配置的方式:
- 多种方式访问任务:
第一种直接通过任务名称访问和操作该任务;
第二种通过访问集合的方式访问创建的任务;
task["taskOne"].properties{
}
第三种通过名称访问,有get和find两种方式:
tasks.findByName("taskOne")
- 任务的分组和描述:
def Task taskOne = task(taskOne)
taskOne.group = BasePlugin.BUILD_GROUP
taskOne.description = "任务的描述"
- << 操作符号:在Gradle的Task是doLast()方法的短标记形式;
- 任务的执行分析:当执行任务时,其实就是执行其拥有的actions列表,这个列表保存在Task对象实例中的action成员变量中,类型为List,一个任务执行方法有doFrist/doSelf/doLast;
- 任务的排序:通过任务的shouldRunAfter和mustRunAfter两个方法控制一个任务应该或者必须在另一个任务之后执行;
- 任务的启动和禁用:通过enable属性来设置启动和禁用,默认为true;
- 任务的onlyIf的断言:是一个表达式,有onlyIf方法接受一个闭包作为参数,如该闭包返回为true该任务执行否则跳过;
5.Gradle插件:
- 插件作用:插件会扩展项目的功能,在项目的构建过程中做很多事
可以添加任务到项目中,帮忙完成一些事,如测试/编译/打包等;
可以添加依赖配置到项目中,如依赖的第三方库;
可以向项目中现有的对象类型添加新的扩展属性/方法等,有助于配置/优化构建;
可以对项目进行一些约定。
- 应用插件:
应用二进制插件,二进制插件就是实现了org.gradle.api.Plugin的插件:
apply plugin: 'org.gradle.api.plugins.JavaPlugin'
- 应用脚本插件:
apply form: 'version.gradle'
- apply方法的其他用法:
void apply(Closure closure);
void apply(Action<? super ObjectConfigurationAction> action);
void apply(Map<String, ?> options);
apply {
plugin 'java'
}
- 应用第三方发布的插件,buildscript{}是在构建项目之前,为项目进行前期准备和初始化相关配置依赖地方,配置好所需的依赖就可以应用插件了:
buildscript {
repositories {
google()
jcenter() //构建脚本引入jcenter
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
- 使用plugin DSL应用插件;
- 自定义插件:自定义插件必须实现Plugin接口,这个接口只有一个apply方法,该方法在插件被应用时被执行。
class mySelfPlugin implements Plugin<Project> {
@Override
void apply(Project target) {
}
}
6.Java Gradle插件:
- Java插件的运用:
apply plugin:'java'
通过以上脚本的应用之后,Java插件会为工程添加很多有用的默认设置和约定,如源代码的位置/单元测试代码的位置/资源文件的位置等。一般情况下最好遵循它的默认设置。
- Java插件约定的项目结构:
默认情况下,Java插件约定src/main/java为我们项目源代码存放目录;src/main/resources为要打包的文件存放目录如一些Properties配置文件和图片等;src/test/java为我们单元测试存放目录;src/test/resources为存放单元测试中使用的文件。
也可以新建一个源集,目录用于存放其他结构的代码资源,如下:
sourceSets {
vip{
}
}
- 配置第三方依赖:
repositories {
//配置仓库
mavenCentral()
maven {
url'http://www.mavenurl.com/'
}
}
//配置依赖
dependencies {
compile 'com.squareup.okhttp3:okhttp:3.0.1'
}
Gradle提供的配置依赖:
名称 | 继承于 | 被哪个任务使用 | 意义 |
compile | _ | compileJava | 编译时依赖 |
runtime | compile | _ | 运行时依赖 |
testCompile | compile | compileTestJava | 编译测试用例时依赖 |
testRuntime | runtime testCompile | test | 仅在测试用例运行时依赖 |
archive | —— | uploadArchive | 该项目发布构建(jar包等)依赖 |
default | runtime | _ | 默认依赖配置 |
Java插件可以为不同源集在编译时和运行时指定不同的依赖。
dependencies {
mainCompile 'com.squareup.okhttp3:okhttp:3.0.1'
VIPCompile 'com.squareup.okhttp3:okhttp:2.5.1'
}
依赖通用使用格式:
名称 | 继承于 | 被哪个任务使用 | 意义 |
sourceSetCompile | _ | sourceSetCompileJava | 为指定源集提供编译时依赖 |
sourceSetRuntime | sourceSetCompile | _ | 为指定源集提供运行时依赖 |
项目依赖:
dependencies {
compile project('项目名称') //项目名在同一目录下
compile files('lib/项目名称') //项目名在同一下lib目录下
compile fileTree(dir:'libs',include:'*.jar') //包含所有libs,后缀为.jar文件
}
- 源码集合(sourceSet)概念:是Java插件用来描述和管理代码及资源的一个抽象概念,是一个Java源代码文件和资源文件的集合。通过源集,可以方便地访问源代码目录,设置源集属性,更改源集的Java目录或者资源目录等;有了源集可以针对不同的业务和应用对源代码进行分组。
Java插件在Project下为我们提供了一个sourceSet属性以及一个sourceSet{}闭包来访问和配置源集。
常用源集属性:
属性名 | 类型 | 描述 |
name | String | 它是只读的,如main |
output.classesDir | File | 该源集编译后的class文件目录 |
output.resourcesDir | File | 编译后生成的资源目录 |
compileClasspath | FileCollection | 编译该源集时所需的classpath |
java | SourceDirectorySet | 该源集的Java源文件 |
java.srcDir | Set | 该源集Java源文件所在目录 |
resources | SourceDirectorySet | 该源集的资源文件 |
resources.srcDir | Set | 该源集的资源文件所在目录 |
- Java插件添加的任务:
Java插件添加的通用任务:
任务名称 | 类型 | 描述 |
compileJava | JavaCompile | 使用javac编译Java源文件 |
processResources | Copy | 把资源文件拷贝到生产的资源目录里 |
classes | Task | 组装生产的类和资源文件目录 |
compileTestJava | JavaCompile | 使用javac测试Java源文件 |
processTestResources | Copy | 把测试资源文件拷贝到生产的资源目录里 |
testClasses | Task | 组装生产的测试类和相关资源文件目录 |
jar | Jar | 组装Jar文件 |
test | Test | 使用JUnit或TestNG运行单元测试 |
uploadArchives | Upload | 上传包含jar的构建,使用archive{}闭包配置 |
clean | Delete | 清除构建生成的目录文件 |
cleanTaskName | Delete | 删除指定任务生成的文件, |
javacdoc | Jar | 使用javacdoc生成Java API文档 |
源集任务:
任务名称 | 类型 | 描述 |
compileSourcesJava | JavaCompile | 使用javac编译指定源集的Java源代码 |
processSourcesSetResources | Copy | 把指定源集的资源文件复制到生产文件下的资源目录中 |
sourceSetClasses | Task | 组装给定源集的类和资源文件目录 |
- Java插件添加的属性:
Java插件添加了很多常用的属性,这些属性都被添加到Project中,可以直接使用;
Java插件添加属性的源集属性:
属性名 | 类型 | 描述 |
sourcesSet | SourcesSetContainer | 该Java项目的源集,可以访问和配置源集 |
sourcesCompatibility | JavaVersion | 编译Java源文件使用的Java版本 |
targetCompatibility | JavaVersion | 编译生成的类的Java版本 |
archiveBaseName | String | 打包jar或zip文件的名称 |
manifest | Manifest | 用于访问或配置的manifest清单文件 |
libDir | File | 存放生成的类库目录 |
distsDir | File | 存放生成的发布的文件的目录 |
- 多项目构建:
多项目构建,其实就是多个Gradle项目一起构建,一起通过Settings.gradle配置管理。每个项目下都有一个build文件对该项目进行配置,然后采用项目依赖就可以实现多个项目协作。
- 发布构件:Gradle构建的产物,称之为构件;一个构件就是一个jar,也可以是一个zip包或war包;发布构件是通过artifacts{}闭包配置的;uploadArchives是一个Upload Task,用上传发布构件。
apply plugin: 'java'
task publishJar(type: Jar)
artifacts {
archives publishJar
}
uploadArchives{
repositories{
flatDir{
name 'libs'
dir '$projectDir/libs'
}
mavenCentral()
}
}