×

Gradle系列(一):Groovy基础

96
08_carmelo
2017.04.17 21:49* 字数 1149

Gradle系列(一):Groovy基础
Gradle系列(二):AndroidStudio的Gradle简介
Gradle系列(三):项目实践

前言

关于Gradle的文章很多,但是大多是以一些技巧为主,东敲西打看了之后可能解决了一些问题,但对于新的需求,gradle如何运用到项目中还是一知半解。我准备稍微深层一点了解gradle,从基本语法开始到如何用到实际项目中,在此我把gradle的学习分成三个部分,分享给大家:

  • 第一部分:Groovy基础
  • 第二部分:android studio中gradle插件简介
  • 第三部分:项目实践

Groovy基础

项目中build.gradle都是用groovy写的,不了解一下groovy怎么能看得懂呢?这里只需要知道groovy的一些基础知识,比如怎么定义变量,定义方法,方法怎么使用,闭包的使用,这些就差不多了。
首先要知道groovy是一种脚本语言,有下面三个特点:

  • 是一种动态语言,不需要编译直接生效
  • 是一种DSL,即Domain Specific Language(专门领域的编程语言,所以比较难阅读)
  • Groovy基于Java同时也像是一种脚本语言(基于java,这个看下面基本语法就明白了)

基本语法

  • ****定义基本变量:****
   def variable1 = 1   //可以不使用分号结尾
   def varable2 = "I am a person"
   def  int x = 1   //变量定义时,也可以直接指定类型
  • ****字符串:****

1  单引号''中的内容严格对应Java中的String,不对$符号进行转义
 
   def singleQuote='I am $ dolloar'  //输出就是I am $ dolloar
2  双引号""的内容则和脚本语言的处理有点像,如果字符中有$号的话,则它会$表达式先求值。
 
   def doubleQuoteWithoutDollar = "I am one dollar" //输出 I am one dollar
   def x = 1
   def doubleQuoteWithDollar = "I am $x dolloar" //输出I am 1 dolloar
3 三个引号'''xxx'''中的字符串支持随意换行 比如
 
   def multieLines = ''' begin
     line  1
     line  2
     end '''

  • ****定义函数:****

String testFunction(arg1,arg2){//无需指定参数类型
  ...
}

def  nonReturnTypeFunc(){
     last_line   //最后一行代码的执行结果就是本函数的返回值
}
 
//如果指定了函数返回类型,则可不必加def关键字来定义函数
String  getString(){
   return "I am a string"
}

  • ****函数调用:****

println("test") ---> println "test"// 可以不加括号,但是建议:自定义的方法调用加上括号! API提供的方法调用可以不用括号

  • ****数据类型:****

  • ** java中的基础数据类型**

在Groovy中所有事物都是对象,int count = 12; //这里的count其实是Integer类型,其他的使用和Java一样

  • ****容器类****

1.List


变量定义:List变量由[]定义,也可以赋予一些初始值,比如
 
def aList = [5,'string',true] //List由[]定义,其元素可以是任何对象
 
变量存取:可以直接通过索引存取,而且不用担心索引越界。如果索引超过当前链表长度,List会自动
往该索引添加元素
 
assert aList[1] == 'string'
assert aList[5] == null //第6个元素为空
aList[100] = 100  //设置第101个元素的值为10
assert aList[100] == 100
 
那么,aList到现在为止有多少个元素呢?
 
println aList.size  ===>结果是101

2.Map


Map由[:]定义,注意其中的冒号。冒号左边是key,右边是Value。key必须是字符串,value可以是任何对象。另外,key可以用''或""包起来,也可以不用引号包起来。比如

    def mapData = [:]
    mapData.put("name","test name")
    println(mapData.get("name"))//输出“test name”

3.闭包(Closure)

  • 定义:闭包,是一种数据类型,它代表了一段可执行的代码。他可以作为方法的参数,或者返回值,也可以独立运行
//自定义一个闭包
def aClosure = { //闭包是一段代码,所以需要用花括号括起来..
String param -> println("test closure,para = $param") //这个箭头很关键。箭头前面是参数定义,箭头后面是代码
        return 200 //返回值
    }
//调用这个闭包:(用call方法或者直接蚕食写在括号里面)
def count = aClosure.call("dml")
//    def count2 = aClosure("dml")
    println("$count")

在Gradle控制台看一下输出:

Paste_Image.png

上面说到Closure也可以作为方法的参数,在Android Gradle中有不少这样的用法,比如:


    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug{
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                        // 输出apk名称为boohee_v1.0_2015-01-15_wandoujia.apk
                        def fileName = "boohee_v${defaultConfig.versionName}_${variant.productFlavors[0].name}.apk"
                        output.outputFile = new File(outputFile.parent, fileName)
                    }
                }
            }
        }
    }

分析一下这里代码是什么意思:
这里debug的配置代码:
作用是根据多渠道打包配置,重新命名APK(这里的实例代码是在productFlavors中配置了“wandoujia”),这里不考虑这个配置,看下这段代码用到了
applicationVariants.all和variant.outputs.each两个Android Gradle插件API提供了两个方法,第一个方法大致意思是获取project对应的app,第二个方法大致意思是遍历生成的所有debug和release的apk,并且重命名!

Paste_Image.png

看下each这个方法,参数就是一个Closure,并且遍历自己,把每一个item传入这个自定义的Closure执行,而在这个Closure中就是我们自己的实现:传入
output变量,对output重命名。Closure有点类似java的函数回调。

  • 闭包使用注意:

1.如果一个方法的最后一个参数是Closure那么,可以不用圆括号,比如上面的all方法和each方法

2.如果闭包没有定义参数,那么它默认拥有参数it,类似于java的this:

    def bClosure = {println("param = $it")
    }
    bClosure.call("this closure!") //输出: param = this closure!

3.闭包的参数怎么传
比如上面的
variant.outputs.each方法,虽然知道他要传入closure参数,但是这个closure参数传几个呢 ? 我们无法确定,只有通过API:

Paste_Image.png

才能知道这个closure只接受一个参数!如果我们传入多参数的closure这里会报错,所以说closure和上下文有很强的关联性,我们必须熟悉一些api才能很好地传入closure!

  • IO操作
    Groovy提供了简单的读取文件的方法,通过一个实例了解一下:
    在我们公司项目中,一些基础功能比如网络模块,通用控件等单独编译成aar文件,放到项目的根目录lib文件夹。
Paste_Image.png

我们可以利用gradle的IO操作读取lib里面的file名称:

   //获取基础库版本号
    def path = rootProject.getRootDir().getAbsolutePath() + "/libs"
    def configFile = new File(path)
    def files = configFile.listFiles()
    def aar1 = files[0].getName()
    def aar2 = files[1].getName()
       println(aar1 )
    println(aar2 )

输出:

Paste_Image.png

那这个有什么用呢,后面第三部分的实践会讲到。

其他

Groovy还有一些技巧:

  1. 读取xml文件,比如读取manifest.xml文件信息
  2. 封装独立的工具类tools.gradle,比如获取Android版本名称,版本号,拷贝文件等IO操作

这些等用到的时候再说

Android经验分享
Web note ad 1