文章目录
- gradle简介
- 特性说明
- 为什么使用 Groovy?
- gradle安装
- gradle使用
- 构建基础
- Projects 和 tasks
- helloworld
- 进阶语法
- 基础语法
- 外部依赖
- 自定义Type
- 自定义Plugin
- 构建文件
- 构建文件
- 内置变量
- 环境变量
- 构建java
gradle简介
Gradle,这是一个基于 JVM 的富有突破性构建工具。
它为您提供了:
- 一个像 ant 一样,通用的灵活的构建工具
- 一种可切换的,像 maven 一样的基于约定约定优于配置的构建框架
- 强大的多工程构建支持
- 强大的依赖管理(基于 ApacheIvy)
- 对已有的 maven 和 ivy 仓库的全面支持
- 支持传递性依赖管理,而不需要远程仓库或者 pom.xml 或者 ivy 配置文件
- ant 式的任务和构建是 gradle 的第一公民
- 基于 groovy,其 build 脚本使用 groovy dsl 编写
- 具有广泛的领域模型支持你的构建
特性说明
基于声明的构建和基于约定的构建
Gradle 的核心在于基于 Groovy 的丰富而可扩展的域描述语言(DSL)。 Groovy 通过声明性的语言元素将基于声明的构建推向下层,你可以按你想要的方式进行组合。 这些元素同样也为支持 Java, Groovy,OSGi,Web 和 Scala 项目提供了基于约定的构建。 并且,这种声明性的语言是可以扩展的。你可以添加新的或增强现有的语言元素。 因此,它提供了简明、可维护和易理解的构建。
为以依赖为基础的编程方式提供语言支持
声明性语言优点在于通用任务图,你可以将其充分利用在构建中. 它提供了最大限度的灵活性,以让 Gradle 适应你的特殊需求。
构建结构化
Gradle 的灵活和丰富性最终能够支持在你的构建中应用通用的设计模式。 例如,它可以很容易地将你的构建拆分为多个可重用的模块,最后再进行组装,但不要强制地进行模块的拆分。 不要把原本在一起的东西强行分开(比如在你的项目结构里),从而避免让你的构建变成一场噩梦。 最后,你可以创建一个结构良好,易于维护,易于理解的构建。
深度 API
Gradle 允许你在构建执行的整个生命周期,对它的核心配置及执行行为进行监视并自定义。
Gradle 的扩展
Gradle 有非常良好的扩展性。 从简单的单项目构建,到庞大的多项目构建,它都能显著地提升你的效率。 这才是真正的结构化构建。通过最先进的增量构建功能,它可以解决许多大型企业所面临的性能瓶颈问题。
多项目构建
Gradle 对多项目构建的支持非常出色。项目依赖是首先需要考虑的问题。 我们允许你在多项目构建当中对项目依赖关系进行建模,因为它们才是你真正的问题域。 Gradle 遵守你的布局。
Gradle 提供了局部构建的功能。 如果你在构建一个单独的子项目,Gradle 也会帮你构建它所依赖的所有子项目。 你也可以选择重新构建依赖于特定子项目的子项目。 这种增量构建将使得在大型构建任务中省下大量时间。
多种方式管理依赖
不同的团队喜欢用不同的方式来管理他们的外部依赖。 从 Maven 和 Ivy 的远程仓库的传递依赖管理,到本地文件系统的 jar 包或目录,Gradle 对所有的管理策略都提供了方便的支持。
Gradle 是第一个构建集成工具
Ant tasks 是最重要的。而更有趣的是,Ant projects 也是最重要的。 Gradle 对任意的 Ant 项目提供了深度导入,并在运行时将 Ant 目标(target)转换为原生的 Gradle 任务(task)。 你可以从 Gradle 上依赖它们(Ant targets),增强它们,甚至在你的 build.xml 上定义对 Gradle tasks 的依赖。Gradle 为属性、路径等等提供了同样的整合。
Gradle 完全支持用于发布或检索依赖的 Maven 或 Ivy 仓库。 Gradle 同样提供了一个转换器,用于将一个 Maven pom.xml 文件转换为一个 Gradle 脚本。Maven 项目的运行时导入的功能将很快会有。
易于移植
Gradle 能适应你已有的任何结构。因此,你总可以在你构建项目的同一个分支当中开发你的 Gradle 构建脚本,并且它们能够并行进行。 我们通常建议编写测试,以保证生成的文件是一样的。 这种移植方式会尽可能的可靠和减少破坏性。这也是重构的最佳做法。
Groovy
Gradle 的构建脚本是采用 Groovy 写的,而不是用 XML。 但与其他方法不同,它并不只是展示了由一种动态语言编写的原始脚本的强大。 那样将导致维护构建变得很困难。 Gradle 的整体设计是面向被作为一门语言,而不是一个僵化的框架。 并且 Groovy 是我们允许你通过抽象的 Gradle 描述你个人的 story 的黏合剂。 Gradle 提供了一些标准通用的 story。这是我们相比其他声明性构建系统的主要特点。 我们的 Groovy 支持也不是简单的糖衣层,整个 Gradle 的 API 都是完全 groovy 化的。只有通过 Groovy才能去运用它并对它提高效率。
The Gradle wrapper
Gradle Wrapper 允许你在没有安装 Gradle 的机器上执行 Gradle 构建。 这一点是非常有用的。比如,对一些持续集成服务来说。 它对一个开源项目保持低门槛构建也是非常有用的。 Wrapper 对企业来说也很有用,它使得对客户端计算机零配置。 它强制使用指定的版本,以减少兼容支持问题。
自由和开源
Gradle 是一个开源项目,并遵循 ASL 许可。
为什么使用 Groovy?
内部 DSL(基于一种动态语言)相比 XML 在构建脚本方面优势非常大。它们是一对动态语言。 为什么使用 Groovy?答案在于 Gradle 内部的运行环境。 虽然 Gradle 核心目的是作为通用构建工具,但它还是主要面向 Java 项目。 这些项目的团队成员显然熟悉 Java。我们认为一个构建工具应该尽可能地对所有团队成员透明。
你可能会想说,为什么不能使用 Java 来作为构建脚本的语言。 我认为这是一个很有意义的问题。对你们的团队来讲,它确实会有最高的透明度和最低的学习曲线。 但由于 Java 本身的局限性,这种构建语言可能就不会那样友善、 富有表现力和强大。 [1] 这也是为什么像 Python,Groovy 或者 Ruby 这样的语言在这方面表现得更好的原因。 我们选择了 Groovy,因为它向 Java 人员提供了目前为止最大的透明度。 其基本的语法,类型,包结构和其他方面都与 Java 一样,Groovy 在这之上又增加了许多东西。但是和 Java 也有着共同点。
对于那些分享和乐于去学习 Python 知识的 Java 团队而言,上述论点并不适用。 Gradle 的设计非常适合在 JRuby 或 Jython 中创建另一个构建脚本引擎。 那时候,对我们而言,它只是不再是最高优先级的了。我们很高兴去支持任何社区努力创建其他的构建脚本引擎。
gradle安装
确定jdk已经安装完毕(自行百度)
从 Gralde 官方网站下载 Gradle 的最新发行包。
下载地址:https://services.gradle.org/distributions/
配置环境变量
运行 gradle 必须将 GRADLE_HOME/bin 加入到你的 PATH 环境变量中。
确认是否安装成功
C:\Users\liaomin>gradle -v
------------------------------------------------------------
Gradle 6.5.1
------------------------------------------------------------
Build time: 2020-06-30 06:32:47 UTC
Revision: 66bc713f7169626a7f0134bf452abde51550ea0a
Kotlin: 1.3.72
Groovy: 2.5.11
Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019
JVM: 1.8.0_261 (Oracle Corporation 25.261-b12)
OS: Windows 10 10.0 amd64
gradle使用
构建基础
Projects 和 tasks
projects 和 tasks是 Gradle 中最重要的两个概念。
任何一个 Gradle 构建都是由一个或多个 projects 组成。每个 project 包括许多可构建组成部分。 这完全取决于你要构建些什么。举个例子,每个 project 或许是一个 jar 包或者一个 web 应用,它也可以是一个由许多其他项目中产生的 jar 构成的 zip 压缩包。一个 project 不必描述它只能进行构建操作。它也可以部署你的应用或搭建你的环境。不要担心它像听上去的那样庞大。 Gradle 的 build-by-convention 可以让您来具体定义一个 project 到底该做什么。
每个 project 都由多个 tasks 组成。每个 task 都代表了构建执行过程中的一个原子性操作。如编译,打包,生成 javadoc,发布到某个仓库等操作。
到目前为止,可以发现我们可以在一个 project 中定义一些简单任务,后续章节将会阐述多项目构建和多项目多任务的内容。
helloworld
//首次定义使用task关键字
task helloworld {
//任务定义时就会执行,执行其他任务这个也会初始化所以也会执行
println '类似于静态快'
//action只有 gradle -q 任务名 这个action才会执行
//doFirst表示任务开始时执行 ,doLast表示任务结束时执行
//新定义的doFirst都会在旧的doFirst之前执行,新定义的doLast都会在旧的doLast之后执行。
doFirst {
println("执行doFirst")
}
}
//动态指定任务的action
helloworld.doLast{
println("执行doLast")
}
//动态指定任务的action,之前定义过 task关键字可省略
helloworld{
doFirst {
println("执行doFirst1")
}
doLast{
println("执行doLast1")
}
}
执行命令 : gradle -q hellworld
输出:
D:\test\gradle\hello>gradle -q helloworld
类似于静态快
执行doFirst1
执行doFirst
执行doLast
执行doLast1
-q参数表示只是输出打印结果,不打印启动日志,去掉-q会输出日志信息。
进阶语法
基础语法
具体更复杂语法请参考:https://docs.gradle.org/current/userguide/tutorial_using_tasks.html
action参考:https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#N18CD0
task testb {
println '测试闭包'
doFirst {
println("执行testb")
}
}
task testa {
println '测试测试'
}
#定义依赖关系
testa.dependsOn testb
//使用变量
task upper{
dependsOn testb
String str="my name is jiaozi"
2.times {
println "$str --- ${str.toUpperCase()}"
}
}
int add(int a,int b) {
a + b;
}
//调用方法
task addTask{
doLast{
println add(100,23)
}
}
//通过动态循环定义多个task
3.times { counter->
task "task_$counter" {
doFirst{
println tasks.upper.name
tasks.upper.doFirst()
println "task_$counter"
}
doLast{
println "end task_$counter"
}
}
}
//动态指定依赖关系
task_1.dependsOn task_0
//ext任务中定义全局变量
ext {
compileSdkVersion = 21
buildToolsVersion = "24.0.1"
minSdkVersion = 9
targetSdkVersion = 19
versionCode = 29
versionName = '3.1.0'
targetCompatibility = 1.7
sourceCompatibility = 1.7
}
task aaa{
println rootProject.ext.compileSdkVersion
}
外部依赖
如果在外部脚本中需要引用外部包,调用类和方法可以使用buildscript块 。
比如maven依赖
import org.apache.commons.codec.binary.Base64
buildscript {
repositories {
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public/' //使用阿里云镜像
}
mavenCentral() //使用maven中央仓库
}
dependencies {
classpath group: 'commons-codec', name: 'commons-codec', version: '1.2' //添加codecmaven依赖
}
}
task encode {
doLast {
def byte[] encodedString = new Base64().encode('hello world\n'.getBytes())//调用导入的Base64类
println new String(encodedString)
}
}
如果需要所有父子项目都使用相同的依赖配置
allprojects {
repositories {
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public/'
}
maven {
url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
}
}
}
自定义Type
gradle支持两种类型的task,一种是在task代码块中定义的doFirst和doLast定义action,另外一种是使用Type定义task类型,自动执行预先定义的action
class GreetingTask extends DefaultTask {
@Input //该注解表示是预先定义输入的字段
String greeting = 'hello from GreetingTask'
@TaskAction //执行task默认执行的action
def greet() {
println greeting
}
}
task hello(type: GreetingTask) //定义task类型是GreetingTask greeting是默认值
task hello1(type: GreetingTask){
greeting="hello user define" //定义task类型是GreetingTask greeting是被覆盖
}
打印输出
d:\test\gradle\type>gradle -q hello1
hello user define
d:\test\gradle\type>gradle -q hello
hello from GreetingTask
同时如果需要修改自定义Type对应的属性值可以使用,一般在gradle提供的插件中经常需要修改,比如修改编译字符集等等:
tasks.withType(GreetingTask) {
greeting="update hello GreetingTask"
}
自定义Plugin
插件实际上是一系列构建脚本的集合,预先定义好后,使用者可按照配置简易操作某些功能。
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
project.task('hello') {
doLast {
println 'Hello from the GreetingPlugin'
}
}
}
}
// Apply the plugin
apply plugin: GreetingPlugin
执行命令 gradle -q hello
同时在命令中可以定义一些拓展属性
class GreetingParamPluginExtension {
String message = 'Hello from GreetingPlugin'
}
class GreetingParamPlugin implements Plugin<Project> {
void apply(Project project) {
// Add the 'greeting' extension object
def extension = project.extensions.create('greeting', GreetingParamPluginExtension)
// 定义task可以直接使用定义拓展属性
project.task('helloParam') {
doLast {
println extension.message
}
}
}
}
apply plugin: GreetingParamPlugin
// 配置的ext对象可直接在项目中使用
greeting.message = 'Hi from Gradle'
//如果有多个属性情况下使用{}方式
greeting{
message = 'Hi from Gradle'
}
helloParam{
doFirst{
println("first "+greeting.message)
}
}
其他关于插件更复杂需求参考:https://docs.gradle.org/current/userguide/custom_plugins.html#sec:getting_input_from_the_build
构建文件
构建文件
- build.gradle:构建的任务定义脚本文件,是gradle启动入口。
- gradle.properties:gradle默认会读取的属性配置文件。
- gradle-wrapper.properties:Android Studio打开一个工程时,首先会读取gradle-wrapper.properties 文件,从而知道这个工程需要哪个版本的gradle,然后就会去保存gradle的文件夹GRADLE_USER_HOME 去找看存不存在这个版本的gradle,不存在则会去distributionUrl去下载
- gradlew.bat: 我们在新建的目录下使用cmd输入gradle wrapper,这时可以看到gradlew.bat文件,windows上的可执行文件格式,此时可以使用gradlew命令了,效果和gradle相同,那么区别是什么呢?
gradle版本会不断更新,每个人使用的版本可能会不同,而gradlew(wrapper)可以算是gradle的一层包装,让我们使用相同版本的gradle进行构建,我们在gradle -> wrapper中可以看到gradle-wrapper.properties文件,打开,可以看到配置的gradle版本的信息:我们使用gradlew命令的时候,会根据这个文件来使用对应的gradle进行构建,没有则会下载,下载后运行下载的gradle执行。 - settings.gradle settings.gradles是模块Module配置文件,大多数setting.gradle的作用是为了配置子模块,比如
rootProject.name = 'gradlejavatest' //表示根项目名称
include 'gradlejavaapi' //包含的子模块,可包含多个include
include 'gradlejavatestapp'
内置变量
gradle内嵌了一些变量可以访问当前的构建目录,当前项目信息,当前action等,具体属性参考:https://docs.gradle.org/current/dsl/org.gradle.api.Project.html
当然其中也包含系统环境变量和gradle本身定义的环境变量,参考下章节:环境变量。
defaultTasks 'ttt'
apply plugin: 'java'
group = 'org.yousharp'
version = '1.0-SNAPSHOT'
task aaa{}
task ttt(dependsOn:aaa) {
println rootProject //多模块项目根项目
println project //当前项目对象,该对象的所有属性和方法都可以直接调用比如project.tasks可省略未tasks
println this //当前项目对象
println tasks //当前项目所有的task
println defaultTasks //通过defaultTasks设置的默认项目
println ext //定义拓展的属性,参考其他语法章节
println allprojects //所有的root和项目
println buildDir //buildDir如果是java项目是target目录
println buildFile //build文件一般是指定的build.gradle文件
println buildscript //buildScript对象
println projectDir //项目的根目录
println version //当前项目的版本 比如java插件的version版本
println System.properties['suser'] //获取系统环境变量
doLast{
}
doFirst{
}
println actions //当前台task所有的action,这里有两个doFirst和doLast
println dependsOn //当前task依赖的其他task
}
环境变量
Gradle为配置Gradle本身和特定项目的行为提供了多种机制。 以下是使用这些机制的参考。
在配置Gradle行为时,您可以使用这些方法,按最高优先级到最低优先级的顺序列出(第一个获胜):
- 命令行标志,如-build-cache。 它们优先于属性和环境变量。
- 系统属性,如systemProp.http.proxyHost=somehost.org存储在gradle.properties文件中。
- Gradle属性,如org.gradle.caching=true,通常存储在项目根目录或环境变量中的Gradle.properties文件中。
- 环境变量,如执行Gradle的环境来源的GRADLE_OPTS。
- 除了配置构建环境之外,还可以使用Project属性(如-Prelease Type=final)配置给定的项目构建。
比如定义 gradle.properties
#设置System properties,可以修改jvm的行为的
systemProp.http.proxyHost=somehost.org
#设置Gradle properties 参考:https://docs.gradle.org/current/userguide/build_environment.html
#自带影响gradle行为的properteis
org.gradle.caching=true
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#定义project properties
foo=bar
username=zs
执行任务脚本:gradle -d ttt
task ttt{
println username
println project.properties['username']
println project.properties['foo']
println foo
println System.properties['http.proxyHost']
println System.properties['java.vm.version']
}
输出结果为:
ls
ls
bar
bar
nn.com
25.261-b12
可以看到日志中设置的一些jvm参数和gradle properties一致:
2020-08-05T14:13:22.100+0800 [INFO] [org.gradle.launcher.daemon.client.DefaultDaemonConnector] Found daemon DaemonInfo{pid=2860, address=[b8d6b9c0-76f5-4535-a37e-07f879ed4308 port:49623, addresses:[/127.0.0.1]], state=Idle, lastBusy=1596607853809, context=DefaultDaemonContext[uid=307fc510-cdbd-4de5-8484-eeb001a97385,javaHome=C:\Program Files\Java\jdk1.8.0_261,daemonRegistryDir=C:\Users\liaomin\.gradle\daemon,pid=2860,idleTimeout=10800000,priority=NORMAL,daemonOpts=-XX:MaxMetaspaceSize=256m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=GBK,-Duser.country=CN,-Duser.language=zh,-Duser.variant]} however its context does not match the desired criteria.
At least one daemon option is different.
可以通过命令行-D修改系统参数,-P修改project参数
也可以通过系统参数-D org.gradle.project.project参数吗=project参数值修改project参数
gradle -Dhttp.proxyHost=nn.com -Pusername=ls -Dorg.gradle.project.foo=false -q ttt
输出结果为:
ls
ls
false
false
nn.com
25.261-b12
构建java
应用java插件,默认会自动将src/main/java代码作为源代码,src/test/java作为测试源代码,
默认提供了以下几个task用于执行编译,测试等功能:
- compileJava任务: 编译 src/main/java源码
- compileTestJava任务:编译src/test/java
- test任务:运行src/test/java下所有单元测试。
- jar任务,打包编译的累和src/main/resources下的资源进入单个jar名称为: -.jar
- javadoc任务:主类生成javadoc
一般普通java项目就以下配置即可,多模块项目修改settings.gradle指定即可
plugins {
id 'java'
}
group 'cn.net'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
maven {
url("http://maven.aliyun.com/nexus/content/groups/public/")
}
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
具体细节参考:https://docs.gradle.org/current/userguide/building_java_projects.html
如果需要提示可使用idea等开发工具。