前一段时间看到不少人在技术论坛里问「刚学 Android 不久,对 Gradle 不懂,看了很多资料依然一知半解」,一时手痒对Gradle做了一些入门的整理,希望对大家有帮助!
说到Gradle ,Gradle是一种构建工具,它抛弃了基于XML的构建脚本,取而代之的是采用一种基于Groovy的内部领域特定语言。近期,Gradle获得了极大的关注,这也是我决定去研究Gradle的原因。
这篇教程讲授了三部分内容:
-
简单了解一下Gradle的基础Groovy 语言
-
理解Gradle构建的一些基本知识
-
理解Gradle在实际过程中的用途及应用
一. Groovy
Groovy 是没有类型的 Java 代码 ,语法更简洁,形式有点类似脚本语言,是被gradle用于构建脚本的语言
(一)特殊类型
1、范围
范围 是一系列的值。例如 “0..4” 表明包含 整数 0、1、2、3、4。Groovy 还支持排除范围,“0..<4” 表示 0、1、2、3。还可以创建字符范围:“a..e” 相当于 a、b、c、d、e。“a..<e” 包括小于 e 的所有值。
def range = 0..4
2、集合
def coll = ["Groovy", "Java", "Ruby"]
3、映射
def hash = [name:"Andy", "VPN-#":45]
(二)闭包Closure
闭包是可执行的代码块。它们不需要名称,可以在定义之后执行。
1、 闭包的格式
-
def xxx = {paramters -> code} //或者
-
def xxx = {无参数,纯code} 这种case不需要->符号
2、 闭包的特点
闭包在Groovy中大量使用,比如很多类都定义了一些函数,这些函数最后一个参数都是一个闭包。
Groovy中,当函数的最后一个参数是闭包的话,可以省略圆括号。比如
其实标识doLast为一个函数,函数的最后一个参数为闭包
-
doLast({
-
println'Hello world!'
-
})
有了圆括号,你会知道 doLast只是把一个Closure对象传了进去。很明显,它不代表这段脚本解析到doLast的时候就会调用println 'Hello world!' 。
但是把圆括号去掉后,就感觉好像println 'Hello world!'立即就会被调用一样!
举例:闭包用于迭代
def acoll = ["Groovy", "Java", "Ruby"] acoll.each{ println it }
闭包中的 it
变量是一个关键字,指向被调用的外部集合的每个值 — 它是默认值,可以用传递给闭包的参数覆盖它。
(三)groovy脚本的实质
既然是基于Java的,Groovy会先把xxx.groovy中的内容转换成一个Java类。比如:
test.groovy的代码是:
Groovy把它转换成这样的Java类:
执行 groovyc-d classes test.groovy
groovyc是groovy的编译命令,-d classes用于将编译得到的class文件拷贝到classes文件夹下
二.Gradle
Gradle是一种依赖管理工具,基于Groovy语言,面向Java应用为主,它抛弃了基于XML的各种繁琐配置,取而代之的是一种基于Groovy的内部领域特定(DSL)语言。 用于自动化构建、测试、发布打包。
(一)基本组件
Gradle是一个框架,它定义一套自己的游戏规则。我们要玩转Gradle,必须要遵守它设计的规则。下面我们来讲讲Gradle的基本组件:
Gradle中,每一个待编译的工程都叫一个Project。每一个Project在构建的时候都包含一系列的Task。比如一个Android APK的编译可能包含:Java源码编译Task、资源编译Task、JNI编译Task、lint检查Task、打包生成APK的Task、签名Task等。
1. gradle projects查看工程信息
到目前为止,我们了解了Gradle什么呢?
-
每一个Project都必须设置一个build.gradle文件。至于其内容,我们留到后面再说。
-
对于multi-projects build,需要在根目录下也放一个build.gradle,和一个settings.gradle。
-
一个Project是由若干tasks来组成的,当gradlexxx的时候,实际上是要求gradle执行xxx任务。这个任务就能完成具体的工作。
2. gradle tasks查看任务信息
gradleproject-path:tasks 就行。注意,project-path是目录名,后面必须跟冒号。
对于Multi-project,在根目录中,需要指定你想看哪个poject的任务。不过你要是已经cd到某个Project的目录了,则不需指定Project-path。
(二)gradle build的生命周期
-
Gradle有一个初始化流程,这个时候settings.gradle会执行。
-
在配置阶段,每个Project都会被解析,其内部的任务也会被添加到一个有向图里,用于解决执行过程中的依赖关系。
- 然后才是执行阶段。你在gradle xxx中指定什么任务,gradle就会将这个xxx任务链上的所有任务全部按依赖顺序执行一遍!
eg:Single project build example
settings.gradle
println 'This is executed during the initialization phase.'
build.gradle
task configured {
println 'This is also executed during the configuration phase.'
}
task test << {
println 'This is executed during the execution phase.'
}
task testBoth {
doFirst {
println 'This is executed first during the execution phase.'
}
doLast {
println 'This is executed last during the execution phase.'
}
println 'This is executed during the configuration phase as well.'
}
其中setting.gradle在多project的配置中,用于声明包含的project及其层级关系(平坦和层级结构的project都支持)
includeFlat 'project3', 'project4'
eg:Logging of start and end of each task execution
build.gradle
task broken(dependsOn: ok) << {
thrownew RuntimeException('broken')
}
gradle.taskGraph.beforeTask { Task task ->
println "executing $task ..."
}
gradle.taskGraph.afterTask { Task task, TaskState state ->
if (state.failure) {
println "FAILED"
}
else {
println "done"
}
}
三.Gradle用途
(1)依赖管理我们的project可能会用到其他的库(本地、maven或者ivy)
eg:Declaring dependencies
本地project依赖
compile fileTree(include: ['*.jar'], dir: 'libs')
compile project(':bugrpt')
}
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
compile 'org.hibernate:hibernate-core:3.6.7.Final'
}
eg:Usage of a remote Maven repository
build.gradle
maven {
url "http://repo.mycompany.com/maven2"
}
}
build.gradle
maven {
url "http://repo.mycompany.com/maven2"
}
}
repositories {
maven {
url "http://repo.mycompany.com/maven2"
}
}repositories {
ivy {
// URL can refer to a local directory
url "../local-repo"
}
}
(2)版本发布
可以将自己的lib工程发布到maven、jcenter等仓库供其他开发者使用
eg:发布工程
repositories {
ivy {
credentials {
username "username"
password "pw"
}
url "http://repo.mycompany.com"
}
}
}
(3) 差异管理
比如app生成不同版本(免费,收费),适配特殊机型,多渠道等需要发多个包,最终能编译出的apk的数量是由productflavor与BuildType决定的,BuildType默认有debug和release两种
eg:免费与收费设置不同包名
pay {
applicationId "me.ghui.gradledemo.pay"
}
free {}
}
eg:buildTypes 对应的不同版本
buildTypes {
debug {
applicationIdSuffix ".debug"
}
jnidebug {
initWith(buildTypes.debug)
packageNameSuffix ".jnidebug"
jniDebuggable true
}
}
}
对于每一种
buildTypes
会创建相应的
ssemble<BuildTypeName>
任务,比如debug会自动创建a
ssembleDebug
任务
创建一个新的的Build Types非常简单,只需要在buildTypes下面通过调用initWith或者使用闭包添加一个新的元素。下表是可以配置的属性以及默认值:
属性明 debug版本默认值release或其他版本默认值
debuggable true false
jniDebuggable false false
renderscriptDebuggable false false
renderscriptOptimLevel 3 3
applicationIdSuffix null null
versionNameSuffix null null
signingConfig android.signingConfigs.debug null
zipAlignEnabled false true
minifyEnabled false false
proguardFile N/A (set only) N/A (set only)
proguardFiles N/A (set only) N/A (set only)
eg:多渠道打包
附录 gradle脚本基础
1 project和task
task表示构建的一次原子操作,包括编译类、创建jar包、发布到repository、生成javadoc等,而project通常包含多个task
doLast {
println 'Hello world!'
}
}
这个脚本定义了一个叫做hello的task,并且添加了一个action,这个action实际上是由groovy语言编写的闭包,更简洁的写法
println 'Hello world!'
}
> gradle -q hello
Hello world!
2 task依赖
task taskX(dependsOn: ':projectB:taskY') << {
println 'taskX'
}
}
project('projectB') {
task taskY << {
println 'taskY'
}
}
3 可以动态创建task,并通过api操作task
task "task$counter" << {
println "I'm task number $counter"
}
}
task0.dependsOn task2, task3
4 task可以定义属性
ext.myProperty = "myValue"
}
task printTaskProperties << {
println myTask.myProperty
}
5 设置默认
task clean << {
println 'Default Cleaning!'
}
task run << {
println 'Default Running!'
}
task other << {
println "I'm not a default task!"
}
6 可以添加HOOK
println "We build the zip with version=$version"
}
task release(dependsOn: 'distribution') << {
println 'We release now'
}
gradle.taskGraph.whenReady {taskGraph ->
if (taskGraph.hasTask(release)) {
version = '1.0'
} else {
version = '1.0-SNAPSHOT'
}
}
7 定位task
1)使用task的名字
2)使用tasks collection
3)使用project:task路径定位
tasks.getByPath(':projectA:hello').path
8 配置task
Configuring a task - with closure
description 'Copies the resource directory to the target directory.'
from 'resources'
into 'target'
include('**/*.txt', '**/*.xml', '**/*.properties')
}
参考:
gradle入门 www.androidchina.net/2155.html
深入理解Android之Gradle blog.csdn.net/innost/arti…
构建神器Gradle jiajixin.cn/2015/08/07/…
Gradle多渠道打包 stormzhang.com/devtools/20…
gradle user guide docs.gradle.org/current/use…
Gradle Plugin User Guide tools.android.com/tech-docs/n…
精通groovy www.ibm.com/developerwo…
编写gradle build脚本 docs.gradle.org/current/use…
从零开始的Android新项目2 - Gradle篇blog.zhaiyifan.cn/2016/03/14/…
更多资讯请关注网易云捕微信公众号,网易云捕官方微博~~