Gradle是基与Groovy的脚本配置的构筑工具,用与构筑Java及Android应用.
Gradle
Gradle是个构筑工具,本身是一个框架,提供了一系列的API,使用中则是执行.Gradle脚本文件,借助与其中的配置来进行构筑.
简单的来说,.Gradle文件就是使用Groovy语言配置及调用Gradle的API的脚本
对与Gradle而言,一个Project是一个执行单元,一个Project对应了一个build.gradle脚本.一个App或一个Library都算是一个Project.
GradleWrapper
一个使用Gradle的项目,如果在没有安装Gradle或对应的版本不对的环境时,需要手动去配置环境.为了避免这个情况,在项目中自带了Gradle的运行环境配置.
就是gradle\wrapper
目录.其配置文件为gradle-wrapper.properties
.
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
项目中gradlew
或gradlew.bat
就是不同平台下的gradle命令行.他使用的是指定的gradle环境.
1 首先会在指定的路径下wrapper/dists下查找是否有对应版本的环境
2 如果没有则会根据gradle-wrapper.properties
中的distributionUrl
下载对应的版本.
路径优先级如下
- GRADLE_USER_HOME
- GRADLE_HOME
- 如果使用AndroidStudio会在OffLine Work指定的目录
- User/.gradle
如上面的distributionUrl
,实际上就是下载gradle-3.3-all.zip
到指定路径的wrapper/dists/gradle-3.3-all/乱码/目录下.如C:\Users\花京院\.gradle\wrapper\dists\gradle-3.3-all\55gk2rcmfc6p2dg9u9ohc3hw9
这个乱码目录自动生成的.下载时会生成.lck文件.下载完成时会生成.ok文件.
所以,如果不能翻墙或下载很慢时,可以停止下载,从下载速度好的镜象网址中下载对应的版本放在该目录下,并新建一个空txt文件,改名成.ok文件.如gradle-3.3-all.zip.ok
为了更好的使用Gradle,可以注意两点
- 配置GRADLE_USER_HOME路径
- 把
gradle-wrapper.properties
中的distributionUrl
地址改成镜象的地址.
如https\://services.gradle.org/distributions/gradle-3.3-all.zip
改为http\://mirrors.flysnow.org/gradle/gradle-3.3-all.zip
一个不错的镜象网址
Project
Project
是一个接口,是Gradle的核心.通过Project
来访问所有的Gradle的功能.Project
和build.gradle
是一一对应的关系.
一个项目必须有一个builde.gradle
.它对应的Project
叫做rootProjcet
.这个Project
对其它Project
提供基础性及公共性的配置.它会创建一个Settings
的实例并根据setting.gradle
来配置这个实例.
-
Project
里含有一个容器TaskContainer
接口.用与创建,存取及管理所有的Task
. -
Project
里含有一个容器ConfigurationContainer
接口,来管理对应的项目配置 -
Project
里含有一个DependencyHandler
接口用与管理项目的依赖 -
Project
里含有一个RepositoryHandler
接口用来注册和管理依赖所需的Repository
.
属性property
Project
可以声明很多属性,没有类型限制.有多种来源
-
Project
自身带的属性 - 额外属性(
extra properties
),每个Project
都持有一个Map用来存放额外属性.这个Map的声明为ext.所以可用ext.属性名
来访问或用ext.属性名=xxx
来赋值 - 通过插件添加到
extensions
的extension
,可以做为同名的只读属性 - 通过插件添加
convention
属性,插件可以通过Project
的convention
对象添加属性和方法 - 父
Project
的属性
Project的动态方法
Project
中的方法有多个来源.
-
Project
自身的方法 -
builde.gradle
中声明的方法 - 通过插件提供的额外方法
- 把Task当成方法,通过把Task名当成方法名来调用Task中的Action或闭包.
- 父
Project
的方法,顶层直到rootProject
- 闭包形式的属性(
property
).可以把属性当成方法调用.
TASK
task
在gradle里可以看成是一个执行任务.除了自定义的task,其它的task都是通过pluging
引入的.像编译,打包,安装这些都是定义好的task.
windows调用task的方法是gradle或gradlew task名 ,在linux或mac下是./gradle或gradlew task名
task
在Gradle中是个接口,其默认实现类为DefaultTask
.其它的实现类都是继承与此.
创建Task
可以通过TaskContainer
对象的create方法来创建Task.但通常是使用task关键字来创建Task
使用task
关键字创建task实际上是使用了Project
对象的task
方法来创建的.共有四个重载方法.调用此方法会创建task
并保存在其中的TaskContainer
里.方法如下
Task task(String name)
Task task(String name, Closure configureClosure) //Cloure就是闭包
Task task(Map<String,?> args,String name)
Task task(Map<String,?> args,String name,Closure configureClosure)
//例子
task hello
task hello {xxx} //groovy语法
task hello(type:jar)
task hello(type:jar) {xxx} //gradle的DSL
doFirst和doLast
task
执行任务是基与Action
接口的.基内部维护了一个List
,通过List<Action<? super Task>> getActions()
方法可获取这个容器.在执行Task
时就是遍历这个容器,调用每个Action
为Task
添加Action
的方法就是doFirst
和doLast
.添加至List
的头和尾.这说明该List是LinkedList
参数有两种,一种为Action<? extend Task>
,另一种为闭包.通常使用闭包这种简便的方式
在gradle提供的DSL中对doLast提供了一个简化写法
task hello <<{
xxx
}
//等同与
task hello {
doLast {
xxx
}
}
读懂Gradle脚本
如上说的,Gradle脚本是基与Gradle的API.所以脚本中基本上都是在调用Gradle的API.
因为脚本使用的是Groovy语言,那么明白Groovy对了解脚本有很大的帮助.这里只说几个要点
- Groovy是基与Java的.可以看成是Java言的简写形式.也就是说可以把Groovy完全替换成Java代码.
- 在Groovy中所有的都是对象,基本数据类型对应的是其对象类,容器使用的是
List
和Map
,容器的声明是[]
,每个元素以,
分隔. - 在groovy中
Map
的定义是[key:value],key必须是字符串,如果不用''
或""
包含则会自动转成对应的字符串,如果key想使用变量引用,则需要加上()
,当方法参数时如果只有一个键值对时可以省略[ ]
def map=[k:`v`]
//这里key是"k",value是"v"
def key="k"
def map=[key:'value']
//这里key是"key"而不是k
def map=[(key):"value"]
//这里的key是'k'
- Groovy中不需要声明类型,但是所有的参数都是有类型的.其顶层是Object.声明一个变量或方法都用def关键字
- Groovy中有闭包,闭包是被{}包裹的可执行代码.可以看成是一个
Runable
,不过可以传递参数,如果不设置参数,则有一个默认的参数,在闭包中用it
表示.类型会自动推导 - Groovy里方法调用是可以链式调用的.方法名+空格+参数表示一个方法调用.省略了括号,在链式调用中方法名+()表示调用空参的方法.如果链式调用为奇数,最后一个参数视为成员变量,如
from a into b from(a).into(b); from a,b init() name from(a,b).init().name; from {} into {} name from({}).into({}).getName();
- Groovy里顶层方法调用可以省略括号,参数间以
,
分隔.但参数是方法调用的话是不能省略括号的.from(a)//可以写成from a from(a,get(b)) //不能写成 from a,get b,必须写成from a,get(b)
- 方法参数中含有闭包的可以把闭包放到括号外,并省略括号及
,
from(a,{}) from a {}
闭包
闭包是一个被{}包含的可执行代码.在Java中是没有闭包存在的,因为Groovy最终会转化为Java代码.实际上闭包会被转化成对应的对象.原理类似与Java8的Lamda.
比如说在对容器进行遍历时调用foreach
方法.就可以传入一个闭包对容器的元素进行操作.这个闭包是没有传递参数的.在闭包中这个元素可以用it来调用.可以理解为创建了一个Runable,含有一个成员变量it.这个变量就是遍历时对应的元素
调用Gradle的方法,传入一个闭包.可以简单的理解为需要传入一个指定的继承Runable的对象或者说是匿名内部类,它的run()方法由自己来实现.这在Gradle里叫委托.
在Gradle里需要传入闭包的方法都是委托指定的对象.所以在闭包中可以直接调用该对象的方法.具体的闭包对应的对象及其可调用的方法就需要查看Gradle的API文档.
解析几个常见的脚本
apply plugin: 'com.android.library'
apply from: 'config.gradle'
实际上都是在调用Gradle的API,apply(Map map)
方法,在方法调用时可以通过空格来省略方法的括号.实际可以写成
apply([plugin:'com.android.library'])
上面的代码也可以合起来写
apply [plugin: 'com.android.library',from:'config.gradle']
android {
compileSdkVersion 24
buildToolsVersion '24.0.1'
defaultConfig {
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName '1.0'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
- 这里首先调用了
android
方法,参数是个闭包A.这里是创建了一个Android
对象.闭包内的内容为对其的配置 - A中调用
compileSdkVersion
,buildToolsVersion
,defaultConfig
及buildTypes
方法.前两个方法为Android
对象的方法,后两个方法的参数为闭包B和C - B中调用了四个方法,C中调用了闭包D,在D中调用了
release
方法,参数为闭包E - E中调用了
minifyEnabled
及proguardFiles
方法 -
proguardFiles
方法的参数为proguard-rules.pro
字符串及方法getDefaultProguardFile('progurad-android.txt')
方法的返回值
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:support-v4:19.1.0'
}
- 这里调用了
dependencies
方法,闭包中为其配置 -
compile
为添加依赖的方法. -
fileTree(include: ['*.jar'], dir: 'libs')
做为compile
方法的参数.fileTree
是个方法,参数为一个List
用来表示添加的类型和一个Map
用来表示文件路径, -
'com.android.support:support-v4:19.1.0'
为依赖的名称.构建时会通过RepositoryHandler
在注册的Repository
里查找.
task clean(type: Delete) {
delete rootProject.buildDir
}
- 声明了一个
clean
的task
. -
task
的类型为Delete
,所以在闭包中可以使用对应的方法delete
- 删除的路径为
rootProject.buildDir
变量保存的路径