gradle构建
百度百科
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。主要用于Java语言。
Groovy对自己的定义就是:Groovy是在 java平台上的、 具有像Python, Ruby 和 Smalltalk 语言特性的灵活动态语言, Groovy保证了这些特性像 Java语法一样被 Java开发者使用。Groovy 是一门JVM 语言,也就是,Groovy 的代码最终也会被编译成JVM 字节码,交给虚拟机去执行。
Groovy 基本语法
变量
在groovy 中,没有固定的类型,变量可以通过def
关键字引用,比如:
def name = 'Andy'
我们通过单引号引用一串字符串的时候这个字符串只是单纯的字符串,但是如果使用双引号引用,在字符串里面还支持插值操作,
def name = 'Andy'
def greeting = "Hello, $name!"
方法
类似 python 一样,通过def
关键字定义一个方法。方法如果不指定返回值,默认返回最后一行代码的值。
def square(def num) {
num * num
}
square 4
类
Groovy 也是通过Groovy 定义一个类:
class MyGroovyClass {
String greeting
String getGreeting() {
return 'Hello!'
}
}
-
在Groovy 中,默认所有的类和方法都是pulic的,所有类的字段都是private的;
-
和java一样,我们通过new关键字得到类的实例,使用def接受对象的引用:def instance = new MyGroovyClass()
-
而且在类中声明的字段都默认会生成对应的setter,getter方法。所以上面的代码我们可以直接调用instance.setGreeting 'Hello, Groovy!',注意,groovy 的方法调用是可以没有括号的,而且也不需要分号结尾。除此之外,我们甚至也可以直接调用;
-
我们可以直接通过instance.greeting这样的方式拿到字段值,但其实这也会通过其get方法,而且不是直接拿到这个值。
闭包
在Groovy 中有一个闭包的概念。闭包可以理解为就是 Java 中的匿名内部类。闭包支持类似lamda形式的语法调用。如下:
def square = { num ->
num * num
}
square 8
如果只有一个参数,我们甚至可以省略这个参数,默认使用it作为参数,最后代码是这样的:
Closure square = {
it * it
}
square 16
安装
下载官网的压缩包,下载地址https://guides.gradle.org
解压,
配置本地的环境变量
image.png验证
image.png第一次输入gradle -v会在本地用户文件夹生成.gradle的文件夹,是Gradle的本地仓库
Eclipse安装Gradle
现在新版本的Eclipse/oxygen已经集成了Geadle
创建一个新项目,观察是否有Gradle,若有就注明,已经集成,不需要下载插件了。
若无,需要下载Buildship插件
help---》 Eclipse Markeplace....
image.png安装完成后重启Eclipse,观察是否出现Gradle项目。
Eclipse创建Gradle项目
image.png image.png image.png image.png image.png image.pngGradle的编译周期
在解析 Gradle 的编译过程之前我们需要理解在 Gradle 中非常重要的两个对象。Project和Task。
每个项目的编译至少有一个 Project,一个 build.gradle
就代表一个project
,每个project里面包含了多个task,task 里面又包含很多action,action是一个代码块,里面包含了需要被执行的代码。
在编译过程中, Gradle 会根据 build 相关文件,聚合所有的project和task,执行task 中的 action。因为 build.gradle文件中的task非常多,先执行哪个后执行那个需要一种逻辑来保证。这种逻辑就是依赖逻辑,几乎所有的Task 都需要依赖其他 task 来执行,没有被依赖的task 会首先被执行。所以到最后所有的 Task 会构成一个 有向无环图(DAG Directed Acyclic Graph)的数据结构。
编译过程分为三个阶段:
-
初始化阶段:创建 Project 对象,如果有多个build.gradle,也会创建多个project.
-
配置阶段:在这个阶段,会执行所有的编译脚本,同时还会创建project的所有的task,为后一个阶段做准备。
-
执行阶段:在这个阶段,gradle 会根据传入的参数决定如何执行这些task,真正action的执行代码就在这里.
Gradle的目录
image.pngsrc文件夹
src/main/java
和src/test/java
是和一般的Java项目一样,存放源码配置的位置,方便调试,和``·src```是一样的。
gradle文件夹
存放gradle的版本里面有一个 wrapper文件夹
gradlw wrapper 包含一些脚本文件和针对不同系统下面的运行文件。wrapper 有版本区分,但是并不需要手动去下载,当运行脚本的时候,如果本地没有会自动下载对应版本文件。
image.png image.pngbuild.gradle
配置整个projeck的项目的构建的依赖
apply plugin: 'java-library' 声明:我们构建的是一个java的library
image.pngsetting.gradle
这个 setting 文件定义了哪些module 应该被加入到编译过程,对于单个module 的项目可以不用需要这个文件,但是对于 multimodule 的项目就需要这个文件,否则gradle 不知道要加载哪些项目。这个文件的代码在初始化阶段就会被执行。
image.pnggradlew和gradlew.bat
gradkew的配置和运行文件
image.pngGradle 的 Task
Task的介绍
一个Task代表一个构建工作的原子操作,例如编译calsses或者生成javadoc。
Gradle中,每一个待编译的工程都叫一个Project。每一个Project在构建的时候都包含一系列的Task。比如一个Android APK的编译可能包含:Java源码编译Task、资源编译Task、JNI编译Task、lint检查Task、打包生成APK的Task、签名Task等。插件本身就是包含了若干Task的。
- 一个Task包含若干Action。所以,Task有doFirst和doLast两个函数,用于添加需要最先执行的Action和需要和需要最后执行的Action。
Action就是一个闭包。闭包,英文叫Closure,是Groovy中非常重要的一个数据类型或者说一种概念。
- Task创建的时候可以通过 type: SomeType 指定Type,Type其实就是告诉Gradle,这个新建的Task对象会从哪个基类Task派生。比如,Gradle本身提供了一些通用的Task,最常见的有Copy 任务。Copy是Gradle中的一个类。当我们:task myTask(type:Copy)的时候,创建的Task就是一个Copy Task。
- 当我们使用 taskmyTask{ xxx}的时候,花括号就是一个closure。
- 当我们使用taskmyTask << {xxx}的时候,我们创建了一个Task对象,同时把closure做为一个action加到这个Task的action队列中,并且告诉它“最后才执行这个closure”
task myTask
task myTask { configure closure } // closure是一个闭包
task myType << { task action } // <<符号是doLast的缩写
task myTask(type: SomeType) // SomeType可以指定任务类型,Gradle本身提供有Copy、Delete、Sync等
task myTask(type: SomeType) { configure closure }
Task的API文档:
https://docs.gradle.org/current/dsl/org.gradle.api.Task.html
自定义Task
在Gradle中,我们有3种方法可以自定义Task。
(1)在build.gradle文件中定义
Gradle使用的是Groovy代码,所以在build.gradle文件中,我们便可以定义Task类。
// 需要继承自DefaultTask
class HelloWorldTask extends DefaultTask {
// @Optional 表示在配置该Task时,message是可选的。
@Optional
String message = 'I am kaku'
// @TaskAction 表示该Task要执行的动作,即在调用该Task时,hello()方法将被执行
@TaskAction
def hello(){
println "hello world $message"
}
}
// hello使用了默认的message值
task hello(type:HelloWorldTask)
// 重新设置了message的值
task helloOne(type:HelloWorldTask){
message ="I am a android developer"
}
(2)在当前工程中定义
当项目中自定义Task类型比较多时,可以将自定义Task写在buildSrc项目中。
具体做法为:在项目的根目录下新建一个名为buildSrc文件夹,然后依次新建子目录src/main/groovy,然后可以建自己的包名,这里以demo.gradle.task为例,依次新建子目录demo/gradle/task,然后在buildSrc根目录下新建build.gradle文件,里面写入:
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
接着在demo.gradle.task包下,创建HelloWorldTask.groovy文件,将(1)中的HelloWorldTask部分代码粘贴过来
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
class HelloWorldTask extends DefaultTask {
@Optional
String message = 'I am kaku'
@TaskAction
def hello() {
println "hello world $message"
}
}
最终目录结构如下:
image.png(3)在单独的项目中定义
当自定义的Task需要能够提供给其他项目中使用时,可以通过声明依赖的方式引入Task。
具体做法为: 创建一个项目,将(2)中的buildSrc目录下的内容copy到新建项目中,然后将该项目生成的jar文件上传到repository中。
build.gradle如下:
apply plugin: 'groovy'
apply plugin: 'maven'
version = '1.0'
group = 'skr'
archivesBaseName = 'hellotask'
repositories.mavenCentral()
dependencies {
compile gradleApi()
compile localGroovy()
}
uploadArchives {
repositories.mavenDeployer {
repository(url: 'file:../lib')
}
}
执行 gradlew uploadArchives ,所生成的jar文件将被上传到上级目录的lib(../lib)文件夹中
在使用该HelloWorldTask时,客户端的build.gradle文件需要做以下配置:
buildscript {
repositories {
maven {
url 'file:../lib'
}
}
dependencies {
classpath group: 'skr', name: 'hellotask', version: '1.0'
}
}
task hello(type: HelloWorldTask)
自定义Plugin
与自定义Task相似,也是3种定义方式,只是代码不一样:
apply plugin: DateAndTimePlugin
dateAndTime {
timeFormat = 'HH:mm:ss.SSS'
dateFormat = 'MM/dd/yyyy'
}
// 每一个自定义的Plugin都需要实现Plugin<T>接口
class DateAndTimePlugin implements Plugin<Project> {
//该接口定义了一个apply()方法,在该方法中,我们可以操作Project,
//比如向其中加入Task,定义额外的Property等。
void apply(Project project) {
project.extensions.create("dateAndTime", DateAndTimePluginExtension)
//每个Gradle的Project都维护了一个ExtenionContainer,
//我们可以通过project.extentions进行访问
//比如读取额外的Property和定义额外的Property等。
project.task('showTime') << {
println "Current time is " + new Date().format(project.dateAndTime.timeFormat)
}
project.tasks.create('showDate') << {
println "Current date is " + new Date().format(project.dateAndTime.dateFormat)
}
}
}
//向Project中定义了一个名为dateAndTime的extension
//并向其中加入了2个Property,分别为timeFormat和dateFormat
class DateAndTimePluginExtension {
String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"
String dateFormat = "yyyy-MM-dd"
}