Aandroid Studio 中使用 gradle 来管理一些信息,最早接触时感觉挺麻烦的,后来才逐渐感觉到它的厉害之处。前几年项目中接入了热修复 Tinker,我看了看它的源码,更感觉到脚本的厉害,还能动态的往 AndroidManifest 中添加一些信息,比如
首先创建个项目,然后创建个 module,我用的是 Java Library,此时我们可以直接书写 java 文件的代码了,但如果想写 groovy 文件,怎么办?直接创建文件肯定会失败,根本创建不出来。此时,得修改 module 中的 gradle 配置文件,
原版:
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
修改后:
apply plugin: 'groovy'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation gradleApi()
implementation localGroovy()
}
此时,apply plugin: 'groovy' 会引入 groovy 插件,implementation localGroovy() 导入 Groovy 的库。然后删除 main 里面的所有文件夹,创建新的 groovy 文件夹,此时,点击鼠标右键 file,输入 MyGroovy.groovy ,点击OK,会出现一个空白文本,在里面写
class MyGroovy {
}
这时候文本就会自动变为 groovy 格式,我们就可以在里面写代码了。注意,此时,需要在 gradle 中再添加些配置才能编译,新增内容如下:
task renameGroovyToJava {
doLast {
delete "$buildDir/classes/java"
File file = new File("$buildDir/classes/groovy")
// file.name = "java" 不行,会报错
println file.renameTo("$buildDir/classes/java")
}
}
compileJava.finalizedBy compileGroovy
compileGroovy.finalizedBy renameGroovyToJava
sourceSets {
main {
groovy {
srcDir 'src/main/groovy'
}
resources {
srcDir 'src/main/resources'
}
}
}
groovy 有两种写法,一种是 java 版,一种是脚本本。上面配置的这种是 java 版,在 gradle 中的写法是脚本版,不论是哪种方式,groovy 的语法是相同的。以 java 版为例,写个 main 入口, 打印个值
class MyGroovy {
static void main(String[] args){
println (" hello world ")
println " hello world args.length : ${args.length} "
}
}
打印结果:
hello world
hello world args.length : 0
在 groovy 中,打印时 println,可以带 (),也可以不带。 字符串中如果有引用,则使用 $ 或 ${} 来修饰。这点与 kotlin 一样,接下来好些东西都与 java 和 kotlin 一样,所以说,有 java 和 kotlin 基础,学起 groovy 特别快。
groovy 中的对象类型可以使用 def 来修饰,同样可以引用不用的类型,并且它有个闭包的概念,可以在方法内部用 it 来特指形参,比如
static void main(String[] args){
def va = 5
va = [a: 1, b: 2, c: 3]
va.each {it->
println(it.key +" " + it.value)
}
}
va 一开始指向的是 int 类型,接下来切换为 Map 类型,然后遍历,it 此时指的就是 Map 中的对象。也就是说,我们自定义了形参 it 来标识遍历的对象。
比如说IO流写入文本,或从文本中读取内容,groovy 也比较简单,如下
static void main(String[] args){
def file1 = new File("E:/a.txt")
file1.withWriter("utf-8") {
writer -> writer.writeLine(" hello world \n Death")
}
file1.eachLine {str->
println(str)
}
}
此时会在电脑的 E 盘创建一个文本,里面就是我们写进去的内容。控制台也会有日志打印,证明写和读都成功。
groovy 最主要的一个特点就是闭包,那么我们自定义个方法看看什么是闭包,如下
static void main(String[] args){
def d = appStr.call("this is string",100)
println(d)
}
static def appStr = { String param1, int param2 -> //箭头前面是形参,箭头后面是代码
println "this is code $param1 $param2" //这是代码
return "return : this is code $param1 $param2" //是返回值
}
打印日志为:
this is code this is string 100
return : this is code this is string 100
这样就比较清楚的标明了什么是闭包。 AS 中的gradle脚本配置中,尤其是配置打出包的地址时,就会用到闭包。
回到一开始的疑问,gradle 中是如何往配置清单中添加节点信息的?我们先看个案例,如果获取节点信息的
@TaskAction
def function() {
//获取到当前的manifest读取到的XmlSlurper中的读取结果
def gpathResult = new XmlSlurper().parse(new File("app/src/main/AndroidManifest.xml"))
//添加android对应的命名空间
gpathResult.declareNamespace('android': 'http://schemas.android.com/apk/res/android')
//读取meta-data示例
for (metaData in gpathResult.application.'meta-data'){
println "name=="+ metaData.@'android:name' + " value=="+metaData.@'android:value'
}
}
这样,它会把自定目录下的配置清单里的 meta-data 节点内容都读取出来。