Groovy概览
- 输出
println ‘Hello, Groovy!’
- 无方法括号。
- 无分号结尾
- 不需要namespace。(对比
System.out.println
)
字符串可以使用单引号和双引号,双引号可以嵌入表达式。$作为嵌入表达式标记。
1
2
3def name = 'Andy'
def greeting = "Hello, $name!"
def name_size "Your name is ${name.size()} characters long."动态修改代码体:
1 | def method = 'toString' |
定义类和属性
1
2
3
4
5
6
7class SampleClass {
String greeting
String getGreetting() {
return 'Hello !'
}
}Groovy的方法和类的可访问性默认为
public
,属性的默认为private
。- 属性会自动带有Getter和Setter,同时直接访问属性的话也会调用Getter。(类似OC)。Getter和Setter可以被覆写。
def
语句用于声明变量,方法。方法不需要返回值
1
2
3
4def square(def num) {
num * num
}
square 4闭包实现
1
2
3
4def square = { num ->
num * num
}
square 8闭包
1
2
3
4
5Closure square = {
// 隐含的参数
it * it
}
square 16android
和dependences
都是闭包类型。列表
1
2
3
4List list = [1, 2, 3, 4, 5]
list.each() { element ->
println element
}Map
1
2
3
4
5Map pizzaPrices = [margherita:10, pepperoni:12]
// 访问元素
pizzaPrices.get('pepperoni')
pizzaPrices['pepperoni']
pizzaPrices.pepperoni
Gradle中的Groovy
- Gradle中大量使用Groovy的简写形式。
apply
1
2
3
4// 这个Groovy的简写
apply plugin: 'com.android.application'
// 等价于
project.apply([plugin: 'com.android.application'])
apply
:方法名plugin: 'com.android.application’
:Map类型的参数
dependencies
1 | project.dependencies({ add('compile', 'com.google.code.gson:gson:2.3', { |
Tasks
使用
task
语法创建Task1
2
3task sayHello {
println 'Hello!'
}以上将创建一个叫做
sayHello
的Task,但是这个Task是在Task的Gradle构建生命周期的Configuration过程执行的。- 生命周期:
- Initialization 初始化:创建Project实例。每个Module/每个build.gradle文件都对应一个Project实例。
- Configuration 配置:针对每个Project实例,创建和配置其中的Tasks。Tasks之间的依赖关系就是在这个阶段生成的。
- Execution 执行:执行特定的Tasks。Task是否执行依赖于启动构建的参数和当前的目录。
- 因为Configuration是针对Project中的所有Task,所以即便是执行其他Task的时候,
sayHello
依然会执行。
- 生命周期:
使用
<<
语法创建一个在Execution过程执行的Task。1
2
3task sayHello << {
println 'Hello!'
}创建任务的其他写法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14// task是`Project`类的方法。
task(hello) << {
println 'Hello, world!'
}
task('hello') << {
println 'Hello, world!'
}
// tasks是Project类中的TaskContainer的一个对象。
// create方法接收一个Map和一个闭包作为参数,返回Task对象
tasks.create(name: 'hello') << {
println 'Hello, world!'
}创建的Task实际上继承自
DefaultTask
,DefaultTask
又继承自AbstractTask
,AbstractTask
是Task
接口的实现类,实现了其所有方法。- Task包含一系列Actions对象,Action在Execution阶段依次执行。(即便Task没有使用
<<
符号声明为Execution阶段的Task,其中的Action依然在Execution阶段执行;但是Task中的代码是在Configuration阶段执行的。) 使用
doFirst
和doLast
添加Action。Action实际上是一个闭包对象。1
2
3
4
5
6
7
8
9
10
11task hello {
println 'Configuration'
doLast {
println 'Goodbye'
}
doFirst {
println 'Hello'
}
}doFirst
总是将Action添加到起始位置,所以后写的Action会在先写的前面执行。doLast
类似。- Tasks的执行顺序由
mustRunAfter()
方法指定。1
2
3
4
5
6
7task task1 << {
println 'task1'
}
task task2 << {
println 'task2'
}
task2.mustRunAfter task1
gradlew task2 task1
命令的执行结果为:
1
2
3
4 :task1
task1
:task2
task2
mustRunAfter()
方法仅指定执行顺序,如果单独先执行task2,后执行task1,顺序将不受mustRunAfter()
方法的控制。dependsOn
方法用以指定Task之间的依赖,下面代码将使得单独执行task2时,也会先执行task1。1
2
3
4
5
6task2.dependsOn task1
// 或者在创建task2时指定
task task2 << {
dependsOn task1
println 'task2'
}配置发布密钥的task实例
1
2
3
4
5
6
7
8
9
10
11
12
13task getReleasePassword << {
def password = ''
if (rootProject.file('private.properties').exists()) {
Properties properties = new Properties();
properties.load(rootProject.file('private.properties').newDataInputStream())
password = properties.getProperty('release.password')
// 类似Swift和Kotlin的语法
if (!password?.trim()) {
password = new String(System.console().readPassword ("\nWhat's the secret password? "))
}
}
}
将密钥保存到private.properties文件中,使用k=v格式保存。
- 添加依赖。
1
2
3
4
5
6 tasks.whenTaskAdded { theTask ->
if (theTask.name.equals("packageRelease")) {
// 为所有packageRelease任务添加getReleasePassword依赖
theTask.dependsOn "getReleasePassword"
}
}
package
是Gradle内置的Task,packageRelease
就是针对Release这种构建类型的Task。Assemble
会依赖package
,所以以上代码使package
任务依赖getReleasePassword
,就会让Release版本的构建依赖getReleasePassword
。上面代码不适用于包含
ProductFlavor
的情况。针对每中构建版本处理
1
2
3android.applicationVariants.all {variant ->
//
}each
内的闭包会在each
执行时对每个item都执行一次,而all
方法在每当向list中添加item时执行一次。each
在Android插件还没有生成变体之前就执行了;all
方法在生成变体并添加到list时执行。修改输出文件名
1
2
3
4
5
6
7
8android.applicationVariants.all {
// outputs而不是output的原因,是因为每个构建其实有多个输出。
// 通常认为只有一个Apk,是因为对Android应用而言,只有一个Apk。
variant -> variant.outputs.each { output ->
def file = output.outputFile
output.outputFile = new File(file.parent, file.name.replace(".apk", "-${variant.versionName}.apk"))
}
}动态创建Task,在Execution步骤之前根据构建配置创建。将生成
runXxxYyyZzz
类的Tasks。1
2
3
4
5
6
7
8
9
10
11
12
13
14android.applicationVariants.all {
variant -> if (variant.install) {
tasks.create(name: "run${variant.name.capitalize()}", dependsOn: variant.install) {
// description会在执行`./gradlew tasks`中展示
description "Installs the ${variant.description} and runs the main launcher activity."
doFirst {
exec {
executable = 'adb'
args = ['shell', 'am', 'start', '-n', "${variant.applicationId}/.MainActivity"]
}
}
}
}
}
创建插件
- 文档: Gradle - Plugins
- 插件可以使用
Groovy
、Java
或任何能够运行在JVM上的语言编写。 - Android插件中的大部分都是Java和Groovy混合编写的。
创建插件的方法:自定义类实现
Plugin
接口,实现apply
方法1
2
3
4
5
6
7
8
9
10
11class RunPlugin implements Plugin<Project> {
void apply(Project project) {
project.android.applicationVariants.all {
variant -> if (variant.install) {
project.tasks.create(name: "run${variant.name.capitalize()}", dependsOn: variant.install) {
// Task definition
}
}
}
}
}apply plugin:
语句的顺序会影响插件之间的依赖关系,上面的插件必须写在Android插件的后面。插件项目也使用Gradle构建,其build.gradle文件如下:
1
2
3
4
5
6
7apply plugin: 'groovy'
dependencies {
compile gradleApi()
// 本地的Groovy SDK
compile localGroovy()
}项目结构
1
2
3
4
5
6
7
8
9
10plugin
└── src
└── main
├── groovy
│ └── com
│ └── package
│ └── name
└── resources
└── META-INF
└── gradle-plugins // 插件配置目录,配置文件以插件ID命名配置文件名称:com.gradleforandroid.RunPlugin
- 配置文件内容:
1
implementation-class=com.gradleforandroid.RunPlugin
其他文章