深入理解Android之Gradle: http://blog.csdn.net/innost/article/details/48228651
Gradle完整指南(Android):http://www.jianshu.com/p/9df3c3b6067a
Gradle学习系列:http://www.kancloud.cn/digest/itfootball-gradle/
Gradle官方网站:https://gradle.org/
Groovy的API文档:http://www.groovy-lang.org/api.html
Gradle 各版本下载
:http://services.gradle.org/distributions/Gradle_Recipes_for_Android.pdf
,Android构建的实用文档: http://pan.baidu.com/s/1kVnq4WBBuilding_and_Testing_with_Gradle.pdf
,通用的构建与测试文档: http://pan.baidu.com/s/1jIM4wgIGradle User Guide.pdf
,官方给出的使用手册: http://pan.baidu.com/s/1qYIozFmGroovy
语言,但是其实际上是基于Java语言的,所以在编写脚本的时候可以直接使用Java语言。Groovy
语言基础虽然在编写脚本的时候可以直接使用java代码,但是使用脚本化语言更加的清晰。
Groovy
开发环境配置参看:http://www.jianshu.com/p/777cc61a6202
Groovy注释标记和Java一样,支持//或者/**/
Groovy语句可以不用分号结尾
Groovy中支持动态类型,即定义变量的时候可以不指定其类型,Groovy中,变量定义可以使用关键字def,注意,虽然def不是必须的,但是为了代码清晰,建议还是使用def关键字
Groovy中每一个对象的成员变量会自动为它生成getter
和setter
函数,所以我们可以直接调用其成员变量或者对应方法。
var0 = "no def no type"
def var1 = 1 //可以不使用分号结尾
def var2 = "I ama person"
def int x = 1 //变量定义时,也可以直接指定类型
String testFunction(arg1,arg2){//无需指定参数类型
...
}
//无类型的函数定义,必须使用def关键字
def nonReturnTypeFunc(){
last_line //最后一行代码的执行结果就是本函数的返回值
}
//如果指定了函数返回类型,则可不必加def关键字来定义函数
String getString(){
return"I am a string"
}
println("123") -> println "123"
def var = 123
println "i am a $var" // 最后打印 i am a 123
str = ''' 1223
122
556
'''
?.
运算符,相当于不为空,则执行某个操作list?.size()
//等同于
if(list != null){
list.size()
}
*.
运算符,用于对集合类型的对象的每个元素执行相同的方法,返回值为大小和该集合元素相同的List。def smaple = ['123','1','12345']
println smaple*.size()
.&
方法作为一个闭包参数传递def list = {1, 2, 3}
list.each{
println it
}
int printNumber(int number){
println number
}
//作为方法作为一个闭包传递
list.each(this.&printNumber)
.@
直接调用字段,在groovy中直接使用.
调用的是对应的getter方法class Todo {
String name
def getName() {
println "Getting Name"
name
}
}
def todo = new Todo(name: "Jim")
println todo.name
println todo.@name
========
result:
Getting Name
Jim
Jim
?:
替代Java
的三目运算符String name= person.name ? person.name : 'unknown'// java的写法
def name2= person.name ?: "unknown" // Groovy 的写法
主要介绍一下三种数据类型:
Groovy作为动态语言,其中一切事物都是对象,所以即使是基本数据类型,其也是被转化为相应的对象的。
def int var = 123
println var.getClass().getName() //打印的结果为 java.lang.Integer
Groovy中的容器类就三种:
//定义list变量,使用[]方式来定,其元素可以是任何的对象
def testList = [123, "string", true]
//元素的存储,注意我们不需要担心越界的问题,当越界了,groovy会自动增加list的容量
assert testList[1] == "string"
assert testList[3] == null //此时第4个元素是不存在的,可以自动增加
//直接设置越界索引的元素的值
testList[999] = 999
//打印testList的大小
println testList.size //结果为 1000
//变量的定义,使用[key:value,......]的方式定义,value可以是任何类型的对象,key可以使用''或者""包裹起来,如果不做处理则表示默认为字符串
def map = [key1: "value1", "321": true, 123:"value2"] //key1被默认为'key1'
//如果key要表示特定的类型或外部定义的变量的值,则使用"()"包裹起来。
def test = "999"
def map1 = [(test):"1000"]
//元素的存取,两种方式, map.keyName map[keyName]
println map."key1" + " " + map."123" //结果为 value1 null, 注意使用map."123" 方式获取到的值为null
println map1[test] + " " + map[123] //1000 value2,使用map[123]才能正确的获取到key值
//新增/修改元素 map.keyName = value
map."321" = false
println map."321"
map1["test2"] = "I an test 2"
println map1["test2"]
Range
继承自List,一种更方便的有序集合类型。
//def
def range = 10..1000 //表示从10到1000之间的元素
def range2 = 10..<1000 //使用'<'表示包含最后一个元素值
//打印
println range.from
println range.get(2)
println range.to
闭包其表示一段可以执行的代码块,看起来是函数与对象的结合体,闭包的最后一行是闭包的返回值,关于闭包可以参考:
def closure = {
parm1, parm2 -> // ->前是闭包的入参,如果没有参数,则可以直接省略这一行代码
code
...
code //最后一行代码,不管有没有return关键词,都表示闭包的返回值
}
//example
def testClosure = {
x, y ->
x = x + y
x
}
//使用closure.call
def val = testClosure.call(3, 4)
println val
//使用closure(参数)
def val2 = testClosure(5, 6)
println val2
it
,它的作用和this
相似。def itClosure = {"hello kitty $it"}
//其等同于:
// def itClosure = {it -> "hello kitty $it "}
println itClosure('funny')
//但是如果在定义闭包时,显式的使用 ->,而且前面没有任何的参数,则表示正真没有任何参数,如果调用时传入参数会报错
def noParamClosure = { -> "no param"}
println noParamClosure('it')//该行代码会报错
def simpleFunction(int x, String str, Closure c){
c.call(x, str) //在函数中调用闭包,并使用它作为返回值
}
def val = simpleFunction 4, " is a four", {x, str -> x + str}
println val
//还是上面的例子,使用闭包做为参数
def simpleFunction(int x, String str, Closure c){
c.call(x, str) //注意此处调用闭包时传递了两个参数,分别为x, str
}
//我们在调用该方法时,传入闭包参数时,注意参数的个数,类型要与函数调用时保持一致
def val = simpleFunction 4, " is a four", {x, str -> x + str} //此为正常调用
//以下都会报错,groovy.lang.MissingMethodException: No signature of method: ConsoleScript3$_run_closure2.call() is applicable for argument types:(java.lang.Integer, java.lang.String) values: [5, tsttt]
Possible solutions: any(), any(), doCall(调用时传入的参数类型)......
def val1 = simpleFunction 5, "tsttt", {x-> x}
def val2 = simpleFunction 5, "tsttt", {->'hahahh'}
def val3 = simpleFunction 5, "tsttt", {String str, String str2 -> str1 + str2}
xxx.groovy
文件编译成class文件//在命令行执行如下命令,编译成class文件
groovyc-d classes xxx.groovy
编译成class之后可以使用jd-gui工具反编译成java类进行查看。
//获取文件对象
def file = new File('e:/source/groovy/test.groovy')
//读取每一行并打印
file.eachLine{
String strLine -> println strLine
}
//一次性获取所有的文件内容
byte[] bytes = file.getBytes() //注意此处可以直接使用file.bytes
println bytes.length
//使用闭包的方式用inputstream流来读取,注意它的好处不用手动去关闭输入流
file.withInputStream{
is -> println(is.getText())
}
//
def writeFile = new File('e:/source/groovy/test2.groovy')
//写入数据,重新开始写,原来的数据会被清除,若文件不存在,则自动创建
writeFile.write("this is the first line")
//添加数据到最末尾
writeFile.append("this is add by append")
//使用流从一个文件读入写入到这个文件,原文件中的数据会别清除
def readFile = new File('e:/source/groovy/test.groovy')
writeFile.withOutputStream{
os ->
readFile.witInputStream{
is ->
os << is //重载了<< 符号,将输入流的数据传递给输出流
}
}
未完待续。
Gradle
概述Gradle
是一种DSL(特定领域)脚本构建框架,编写脚本使用的是Groovy语言(也可以直接使用Java语言)。Gradle
、Groovy
、Java
的API方法。//我们构建Android APP项目使用的插件是:
apply plugin: 'com.android.application'
//如果是构建一个library项目让其他的项目引用
apply plugin: 'com.android.library'
所以我们在脚本中能够使用的特定的方法、属性都是各种脚本决定的。
Gradle
和Android Gradle Plugin
的官方帮助文档Gradle releaseNote
(Gradle最新版本发布说明):https://docs.gradle.org/current/release-notesGradle User Guide
(最新版本用户指导手册):https://docs.gradle.org/current/userguide/userguide.htmlGradle DSL Reference
(最新领域语言说明):https://docs.gradle.org/current/dsl/Gradle Api JavaDoc
(JavaDoc说明):https://docs.gradle.org/current/javadoc/Goolge Gradle Plugin GitHub
(Google gradle 插件GitHub地址):https://github.com/google/android-gradle-dslGradle Android Plugin DSL Reference
(最新版本插件领域语言说明):http://google.github.io/android-gradle-dsl/current/Gradle Android Plugin Api JavaDoc
(最新版本插件API文档):http://google.github.io/android-gradle-dsl/javadoc/current/build.gradle
文件与之对应,查看project命令:gradle projects
gradle tasks
//多项目查看某个项目下的tasks,或者直接cd 到想查看的项目目录下面去,执行上面的命名。
gradle project_path:tasks
//拷贝complie 这个configuration的文件到指定目录中
task copyAllDependencies(type: Sync) {
//referring to the 'compile' configuration
//拷贝所有编译时依赖的文件如jar,aar等等
from configurations.compile
into 'build/output'
exclude 'recyclerview-v7-24.0.0-alpha1.aar' //过滤掉这个包
}
添加自定义的artifacts到指定的Configuration中:
//Configuration的申明:
configurations {
testConfig
//也可以继承
//testConfig.extendsFrom(compile)
}
//压缩so任务
task testZip(type:Zip){
baseName = 'armeabi'
println 'ready to copy!!!!'
println(rootProject.projectDir.absolutePath + '\\app\\libs\\armeabi\\')
from rootProject.projectDir.absolutePath + '\\app\\libs\\armeabi\\'
}
//关联一个自定义的文件Map
def map = [file:new File(rootProject.projectDir.absolutePath + '/app/debug.jks')]
artifacts{
testConfig map
//这里也可以直接传入AbstractArchiveTask类型的task(如Jar,Zip),也可以直接传入File对象
//testConfig new File(rootProject.projectDir.absolutePath + '/app/debug.jks')
//testConfig testZip
}
//使用配置项,用于Copy task的from参数
//copying all dependencies attached to 'compile' into a specific folder
task copyAllDependencies(type: Sync) {
//referring to the 'compile' configuration
//注意不能直接传递allArtifacts对象,要调用其getFiles()方法
from configurations.testConfig.allArtifacts.getFiles()
into 'build/output'
}
先看一个简单的执行流程图:
创建Gradle对象,在执行任何一条gradle命令时,都会先创建一个全局唯一的Gradle对象,该对象可以保存一些全局的基本的值。
创建Setting对象,Gradle每次构建都会创建一个Setting对象,如果存在settings.gradle文件则会去解析该文件配置Setting对象。一个setting.gradle文件对应一个Setting对象,当项目依赖编译多个项目时,就需要在settings.gradle中include需要编译的与依赖的项目。后面看DSL文档会Setting对象持有一个rootProject对象,注意该对象的类型为ProjectDescriptor
,而不是Project。
创建Project对象,在配置完Setinng对象后,开始创建Project对象,默认的创建的顺序:先创建rootProject 对象(注意这里的类型为Project),子模块的对象的创建依照settings.gradle文件中include的顺序进行。
解析上一步创建对象对应的build.gradle文件,按序添加task执行顺序,在解析完所有的Project对象后,最终会生成一个有向无环图表示所有需要执行task的执行顺序,注意解析文件是在其对应的Project对象后进行,而不是所有的Project对象创建后再进行。
依据上一步生成的有向无环图,执行脚本。
DSL中对Project生命周期的描述:
Lifecycle
- There is a one-to-one relationship between a Project and a build.gradle file. During build initialisation, Gradle assembles a Project object for each project which is to participate in the build, as follows:
- Create a Settings instance for the build.
- Evaluate the settings.gradle script, if present, against the Settings object to configure it.
- Use the configured Settings object to create the hierarchy of Project instances.
- Finally, evaluate each Project by executing its build.gradle file, if present, against the project. The projects are evaluated in breadth-wise order, such that a project is evaluated before its child projects. This order can be overridden by calling Project.evaluationDependsOnChildren() or by adding an explicit evaluation dependency using Project.evaluationDependsOn(java.lang.String).
在上面步骤中的3-4之间,Gradle给我们提供了一个钩子函数gradle.beforeProject
,可以做一些额外的自定义操作:
//如果该钩子在setting.gradle中申明,每一个对象创建都会执行一次
gradle.beforeProject{rootProject ->
println 'in xxx build.gradle beforeProject called!!!'
println rootProjct.rootDir
}
同样在4-5之间也可以使用钩子函数gradle.taskGraph.whenReady
,该函数在建立完有向图后执行脚本之前调用:
gradle.taskGraph.whenReady {
println 'in xxx build.gradle whenReady called!!!'
if(rootProject == project){ //若在rootProject的build.gradle中调用该方法,则会打印
println 'xxx project = rootProject'
}
}
在执行完脚本之后,gradle给我们提供了一个gradle.buildFinished
钩子函数供我们做一些自定义操作:
gradle.buildFinished {
println 'in xxx build.gradle buildFinished called!!!'
}
注意上面的所列举的三个钩子函数传递的参数都是闭包,是可以在多个.gradle
文件中调用的,可以各自实现不同的闭包逻辑,但是决定其何时生效取决于调用该方法的.gradle
文件是否已经被解析,文件中调用的钩子函数是否被添加到监听器列表中,比如在rootProject
的build.gradle
中是无法监听到它自己的beforeProject
钩子的,因为调用该钩子函数时,build.gradle
都还没有被解析,所以我们需要在setting.gradle
中声明钩子。
Gradle
对象Gradle
对象每次执行脚本时,创建的一个唯一的对象,它表示一次脚本的执行,它一直存在于脚本执行的各个阶段。以下是它属性的截图,前面说到的很多钩子函数都属于这个类。
Settings
对象确定本次build需要配置Project以及执行顺序和依赖关系,多个项目关联编译时需要用到这个对象,全局唯一,在Android Studio项目通常根目录下存在一个settings.gradle
文件,我们可以通过它来配置Settings
对象。
参考文档: Gradle命令行用户指导:https://docs.gradle.org/current/userguide/gradle_command_line.html
- 查看Gradle
版本号
gradle -v
gradle task1
//执行多个task
gradle task1 task2
//静默执行task,还有其他三种模式
gradle -q task
//过滤task2不执行,加-x参数
gradle task1 -x task2
gradle projects
gradle tasks
//显示所有
gradle --gui
gradle --help