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

验证

image.png

第一次输入gradle -v会在本地用户文件夹生成.gradle的文件夹,是Gradle的本地仓库

Eclipse安装Gradle

现在新版本的Eclipse/oxygen已经集成了Geadle
创建一个新项目,观察是否有Gradle,若有就注明,已经集成,不需要下载插件了。

image.png

若无,需要下载Buildship插件

help---》 Eclipse Markeplace....

image.png

安装完成后重启Eclipse,观察是否出现Gradle项目。

Eclipse创建Gradle项目

image.png
image.png
image.png
image.png
image.png
image.png

Gradle的编译周期

在解析 Gradle 的编译过程之前我们需要理解在 Gradle 中非常重要的两个对象。ProjectTask

每个项目的编译至少有一个 Project,一个 build.gradle就代表一个project,每个project里面包含了多个task,task 里面又包含很多actionaction是一个代码块,里面包含了需要被执行的代码。

在编译过程中, Gradle 会根据 build 相关文件,聚合所有的projecttask,执行task 中的 action。因为 build.gradle文件中的task非常多,先执行哪个后执行那个需要一种逻辑来保证。这种逻辑就是依赖逻辑,几乎所有的Task 都需要依赖其他 task 来执行,没有被依赖的task 会首先被执行。所以到最后所有的 Task 会构成一个 有向无环图(DAG Directed Acyclic Graph)的数据结构。

编译过程分为三个阶段:

  • 初始化阶段:创建 Project 对象,如果有多个build.gradle,也会创建多个project.

  • 配置阶段:在这个阶段,会执行所有的编译脚本,同时还会创建project的所有的task,为后一个阶段做准备。

  • 执行阶段:在这个阶段,gradle 会根据传入的参数决定如何执行这些task,真正action的执行代码就在这里.

Gradle的目录

image.png

src文件夹

src/main/javasrc/test/java是和一般的Java项目一样,存放源码配置的位置,方便调试,和``·src```是一样的。

gradle文件夹

存放gradle的版本里面有一个 wrapper文件夹

gradlw wrapper 包含一些脚本文件和针对不同系统下面的运行文件。wrapper 有版本区分,但是并不需要手动去下载,当运行脚本的时候,如果本地没有会自动下载对应版本文件。

image.png
image.png

build.gradle

配置整个projeck的项目的构建的依赖

apply plugin: 'java-library' 声明:我们构建的是一个java的library

image.png

setting.gradle

这个 setting 文件定义了哪些module 应该被加入到编译过程,对于单个module 的项目可以不用需要这个文件,但是对于 multimodule 的项目就需要这个文件,否则gradle 不知道要加载哪些项目。这个文件的代码在初始化阶段就会被执行。

image.png

gradlew和gradlew.bat

gradkew的配置和运行文件

image.png

Gradle 的 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"
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,701评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,649评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,037评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,994评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,018评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,796评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,481评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,370评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,868评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,014评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,153评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,832评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,494评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,039评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,437评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,131评论 2 356

推荐阅读更多精彩内容