Gradle 基础用法

命令行

执行任务

可以通过命令行执行一个或多个任务

# 执行任务 compile
> gradle compile

# 按顺序执行多个任务任务 compile, test
> gradle compile test

任务依赖

下面定义四个任务,disttest依赖于comile任务,执行gradle dist testcompile任务只会被执行一次。

tasks

build.gradle

task compile {
    doLast {
        println 'compiling source'
    }
}

task compileTest(dependsOn: compile) {
    doLast {
        println 'compiling unit tests'
    }
}

task test(dependsOn: [compile, compileTest]) {
    doLast {
        println 'running unit tests'
    }
}

task dist(dependsOn: [compile, test]) {
    doLast {
        println 'building the distribution'
    }
}

执行gradle dist test后输出

> gradle dist test
:compile
compiling source
:compileTest
compiling unit tests
:test
running unit tests
:dist
building the distribution

BUILD SUCCESSFUL in 0s
4 actionable tasks: 4 executed

任务名称缩写

在命令行指定任务名时不必使用完整的任务名,只需提供能唯一识别任务的部分即可。

比如任务zee可以通过以下命令执行:

> gradle z
> gradle ze
> gradle zee 

假设同时存在任务zeezoo,执行gradle z 将失败。

可以对驼峰式任务名中的各个单词使用缩写,比如任务fooBar可以通过以下命令执行:

> gradle fB
> gradle foB
> gradle fooB 
...
> gradle foBa
... 
> gradle fooBar 

获取构建信息

Gradle提供了一些内建任务以获取特定的构建信息,以便调试问题和理解构建的结构与依赖。

# 以树形结构列出当前项目子项目
> gradle -q projects

# 显示当前项目项的任务列表
> gradle -q tasks 
# 显示当前项目项的所有任务
> gradle -q tasks --all

# 查看任务信息
> gradle -q help --task <task>
 
# 显示当前项目的依赖
> gradle dependencies
# 显示指定子项目的依赖
> gradle <subproject>:dependencies

# 显示当前项目buildscript的依赖
> gradle buildEnvironment
# 显示指定子项目buildscript的依赖
> gradle <subproject>:buildEnvironment

# 查看特定配置中指定依赖的依赖
> gradle -q <subproject>:dependencyInsight --dependency <dependency> --configuration <configuration>

# 查看项目属性 
> gradle -q <subproject>:properties

命令行选项

  • -?,-h,--help: 打印所有的命令行选项
  • -i, --info: 改变日志级别为INFO
  • -q, --quiet: 只打印错误信息
  • -S, --full-stacktrace: 发生错误时打印完整堆栈信息
  • -s, --stacktrace: 发生错误时打印堆栈信息
  • -b, --build-file: 指定执行的构建脚本(默认build.gradle)
  • -c, --settings-file: 指定配置脚本(默认settings.gradle)
  • -D, --system-prop: 传递一个系统属性给JVM,比如:-Dmyprop=myvalue
  • -P, --project-prop: 传递一个项目属性值给构建脚本,比如:-Pmyprop=myvalue
  • --offline: 以离线模式运行构建(Gradle只检查本地缓存中的依赖)
  • -x, --exclude-task: 执行构建时排除指定任务

参考

https://docs.gradle.org/current/userguide/command_line_interface.html

构建脚本

Gradle 的一切建立在 项目(project)与任务(task) 这两个基本概念上。 参考

  • 每个Gradle构建由一个或多个项目组成,项目代表什么取决于你想用做什么。它可以是一个JAR库或Web应用,也可以是一个由其它项目发行了ZIP。
  • 每个项目由一个或多个任务组成,任务表示在构建中执行的某些原子的工作内容。比如编译一个类,创建一个JAR,生成Javadoc等。

在命令行使用gradle命令时,它会在当前目录寻找build.gradle文件,这个文件就是构建脚本(build script),定义了项目和它的任务

任务基本写法

// 通过命令 gradle hello 执行
// 使用-q参数不输出日志 gradle -q hello
task hello {
    doLast {
        println 'Hello world!'
    }
} 

// 任务可以有依赖关系
task intro(dependsOn: hello) {
    doLast {
        println "I'm Gradle"
    }
}

// doFirst和doLast可以被执行多次,动作被添加到列表中,任务执行时被依次调用。
hello.doLast {
    println 'Hello Mars'
}
hello {
    doLast {
        println 'Hello Jupiter'
    }
}

// 为任务添加额外的属性
task myTask {
    ext.myProperty = "myValue"
} 
task printTaskProperties {
    doLast {
        // 访问添加的属性
        println myTask.myProperty
    }
}

构建的生命周期(build lifecycle)

构建分为三个阶段

  • 初始化(Initialization),Gradle支持单项目和多项目构建,在初始化阶段,确定哪些项目是构建的一部分,并创建Project实例。
  • 配置(Configuration),在这个阶段所有项目对象(任务...)都被配置,属于构建的所有项目的build scripts都被执行。
  • 执行(Execution),确定要被执行任务的子集并执行,此任务子集由命令行传入的任务名和当前目录决定。

settings.gradle 在初始化阶段被执行

println '===> initialization'

build.gradle

println '===> configuration - build.gradle - project a'

afterEvaluate {
    println '===> evaluation - build.gradle - project.after'
}

beforeEvaluate {
    println '===> evaluation - build.gradle - project.before'
}

task testOne {
    println '===> configuration - build.gradle - task.one'
}

println '===> configuration - build.gradle - project b'

task testTwo {
    doLast {
        println '===> execution - build.gradle - task.two'
    }
}

task testThree {
    doFirst {
        println '===> execution - build.gradle - task.three.doFirst'
    }
    doLast {
        println '===> execution - build.gradle - task.three.doLast'
    }
    println '===> configuration - build.gradle - task.three'
}

执行 gradle testOne testTwo testThree 后输出

> gradle testOne testTwo testThree
===> initialization
===> configuration - build.gradle - project a
===> configuration - build.gradle - task.one
===> configuration - build.gradle - project b
===> configuration - build.gradle - task.three
===> evaluation - build.gradle - project.after
:app:testOne UP-TO-DATE
:app:testTwo
===> execution - build.gradle - task.two 
:app:testThree
===> execution - build.gradle - task.three.doFirst
===> execution - build.gradle - task.three.doLast

为项目添加属性(gradle.properties)

Gradle 有多种方式以特定的顺序为项目添加属性,以不同方式设置的相同属性排序靠后的将被设置:

  1. 父项目目录的 gradle.properties 文件
  2. 项目目录的 gradle.properties 文件
  3. Gradle 用户根目录的 gradle.properties 文件(~/.gradle/gradle.properties)
  4. ORG_GRADLE_PROJECT_ 开始的环境变量,对于环境变量 ORG_GRADLE_PROJECT_myProperty,会设置名为 myProperty 的属性。
  5. -Dorg.gradle.project. 开始的系统属性,对于系统属性 -Dorg.gradle.project.myProperty,会设置名为 myProperty 的属性。
  6. 在命令行中设置的 -P 参数

参考

https://docs.gradle.org/current/userguide/build_environment.html

Gradle 包装器

Gradle 包装器会自动下载并安装指定版本的Gradle运行时,为开发人员提供一致的构建环境。

wrapper 任务

可以为wrapper任务指定一些参数

  • --gradle-version 指定gradle运行时版本
  • --distribution-type 指定发行包类型:bin只有二进制文件;all包含二进制,源码和文档
  • --gradle-distribution-url 指定发行包下载地址

运行wrapper任务

> gradle wrapper --gradle-version 3.3 
:wrapper

BUILD SUCCESSFUL

Total time: 1.416 secs

wrapper任务会生成以下文件

<project-root>/
  gradlew
  gradlew.bat
  gradle/wrapper/
    gradle-wrapper.jar
    gradle-wrapper.properties

在运行gradlew命令构建时,它会先检查指定版本的Gradle运行时是否可用,如果不可用就先下载它。

下载的Gradle通常存放在 <project-root>/.gradle/wrapper/dists

参考

Gradle Wrapper
https://docs.gradle.org/current/userguide/gradle_wrapper.html

DSL Wrapper
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.wrapper.Wrapper.html

使用插件

https://docs.gradle.org/current/userguide/plugins.html

使用分为两步

  • 解析(resolve),找到正确的插件版本并添加到 script classpath。
    脚本插件是在应用时自解析的,Gradle自带的核心插件是自动解析的。
  • 应用(apply),在项目中对插件执行Plugin.apply(T)
    此操作是幂等的,多次调用无副作用。

应用插件

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

// 根据类型应用插件 
apply from: JavaPlugin

// 应用二进制插件 
apply from: ‘java’

使用buildscript解析插件并应用

build.gradle

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

apply plugin: "com.jfrog.bintray"

使用 plugins DSL 应用插件

plugins DSL 将解析与应用合并在一步执行,简化了用法。

plugins {
    // 应用核心插件
    id 'java' 
    // 应用已发布到 Gradle plugin portal 的插件
    id "com.jfrog.bintray" version "1.7.3"
}

使用 plugins DSL 应用自定义仓库中的插件

在 settings.gradle 引入自定义插件仓库

pluginManagement {
    repositories {
        maven { url 'custom-repo' }
        gradlePluginPortal() 
    }
}

在 build.gradle 中应用插件

plugins {
    id "ezy.example.gradleplugin" version "1.0.0"
}

自定义插件(Custom Plugin)

自定义插件可以可以放在以下几个地方:

  • 可以直接写在 build.gradle 中,但此插件不能被其它构建引用。
  • 在单独的文件中实现插件,放在buildSrc项目中(buildSrc/src/main/groovy/)。
    运行 Gradle 时,如果存在 buildSrc 目录,不需要额外的指令,其中的代码就会被编译测试并添加到构建脚本的 classpath 中,同一个工程中的所有构建文件中都可以引用。
  • 在单独的工程中自定义插件,上传到远程仓库。通过添加依赖,引用这个插件。

简单的例子

以下代码是一个简单的自定义插件示例。

在应用插件后会创建一个任务(hello),并且可通过greeting.message传入参数,在命令行中输入gradle hello执行

build.gradle

apply plugin: SimplePlugin

// 其它一些配置
// ...

greeting {
    message = "hello, hahahahahahha!"
}


class GreetingPluginExtension {
    String message = 'Hello from GreetingPlugin'
}

class GreetingPlugin implements Plugin<Project> { 
    void apply(Project project) {
        println "===>>> GreetingPlugin"

        project.extensions.create('greeting', GreetingPluginExtension)

        project.task('hello') {
            doLast {
                println "===>>> task hello : ${extension.message}"
            }
        } 
    }
}

使用 java-gradle-plugin 自定义插件

如果希望自己发布到自定义仓库中的插件也能使用plugins DSL引用,需要用到插件 java-gradle-plugin

Demo(https://docs.gradle.org/current/samples/sample_gradle_plugin.html)

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

推荐阅读更多精彩内容