您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
拥抱 Android Studio(三):溯源,Groovy 与 Gradle 基础
 
作者:唐小引 来源:CSDN 发布于: 2016-1-7
  1562  次浏览      35
 

本文为“拥抱Android Studio”系列第三篇。作者何畅彬,现任BugTags技术总监,关注移动SDK研发、后端服务设计与实现。

在将 ADT 与 Android Studio 进行对比鼓励开发者们积极拥抱,并列举了 Android Studio 与 Gradle 下一些深入实用的功能,分享自己以及在帮助用户集成过程中遇到的坑之后,作者追本溯源,对 Groovy 与 Gradle 进行了讲解,帮助开发者们更快上手。

关于学习方式续

回忆起大学那个白衣飘飘的年代,开始金工实习却发现基础学的不牢靠,越来越胆小,越来越糊涂。所幸得到一位高年级学姐指导,赶紧找当时的书或者笔记,快速把基础知识温习一遍,再结合实践中思考,终于豁然开朗。

相信看过前一篇《Android Studio 与 Gradle 深入》的同学,有一部分就会遇到我初识 Gradle 时的困惑:代码我也依稀看得懂,但就是不知道还能这样写,为什么这样写。

问题与解决方案

回想我在 Gradle 的学习过程中遇到的问题与及其解决方案,总结出下面三点:

  • 原理不懂:学习 Groovy 与 Gradle 的基础原理
  • Gradle 实践不懂:学会找示例,学习开源例子
  • 方法和属性不懂:学会查文档

下面的我将以解决三个问题为线索,介绍 Groovy 和 Gradle。

学习 Groovy

Groovy 概述

Gradle 采用了 Groovy 语言作为主要的脚本语言。一个 build.gradle 文件,其实是一个 Groovy 类。

Groovy 是一个基于 JVM 的语言,代码最终编译成字节码(bytecode)在 JVM 上运行。它具有类似于 Java 的语法风格,但是语法又比 Java 要灵活和方便,同时具有动态语言(如 ruby 和 Python)的一些特性。

Groovy 的诸多特定,很适合用来定义DSL(Domain Specific Language)。

简单的来讲 DSL 是一个面向特定小领域的语言,如常见的 HTML、CSS 都是 DSL,它通常是以配置的方式进行编程,与之相对的是通用语言(General Purpose Language),如 Java 等。

既然是一门语言,就肯定有自己的特性。我们要从下面几个步骤来介绍 Groovy:

  • 环境安装
  • 语言基础
  • 语言特性及其本质

环境安装

Groovy 官方安装文档提供多种方式进行安装,确保你不会在跪在环境配置的路上 ^-^?

  • Windows 下推荐 binary 包配置环境变量
  • Mac 下推荐使用 sdkman 或者 Brew 进行安装
  • Linux 下推荐 sdkman
  • 嵌入在程序中,则推荐使用 Maven 远程依赖

初学者也没有必要使用IDE,平添障碍,后期用 Intellij IDEA Community 版本足矣。

下面只介绍 Mac 下使用 sdkman 的安装方式。

  • 下载安装 sdkman,执行下面命令,按照提示安装即可
curl -s http://get.sdkman.io | bash
  • 使环境变量生效
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
  • 安装 Groovy
$ sdk install groovy
  • 查看当前版本,如果能否运行且输出对应版本,就是成功了
$ groovy -version
Groovy Version: 2.4.4 JVM: 1.8.0_25 Vendor: Oracle Corporation OS: Mac OS X

初探

安装好环境之后,先来一个 hello, world!

  • 新建文件
$ vim test.groovy
  • 在其中写上内容
println "hello, world!"
  • 保存退出,执行
$ groovy test.groovy
hello, world!

Wow, So easy!

语言基础

下面将会用一些实际的例子,介绍一些最重要的点,

例子都已经传到 github 的?demo?项目中。?

第一次使用 demo 项目的时候,需要等待自动下载几个远程包。?

笔者一个 Java 程序员,可以你能够看到很多 Java 的习性还是留在代码中。

文件与类,变量与函数

Groovy 代码文件,支持不显式声明类:

ScriptClass.groovy

ScriptClass.groovy

这样一个 Groovy 脚本,经过编译之后,会产生一个继承自 groovy.lang.Script 类的子类:

是不是能看出点什么?

groovy/build/classes/main/io/kvh/as/groovy/ScriptClass.class

public class ScriptClass extends Script {
public ScriptClass() {
CallSite[] var1 = $getCallSiteArray();
}
public ScriptClass(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}

public ScriptClass(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}

public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].call(InvokerHelper.class, ScriptClass.class, args);
}

public Object run() {//关键方法
CallSite[] var1 = $getCallSiteArray();
return var1[1].callCurrent(this, "hello,world");// got it?
}
}

Groovy 支持如下的方式来定义变量和函数:

VarAndMethod.groovy

def varAndMethod() {
def a = 1//不显式声明变量类型
a = "abc"//运行时改变类型

println a//无需;结束一行代码
a = 4//最后一行作为返回值
}
def ret = varAndMethod()//文件内运行方法

println ret//输出4

字符串

Groovy 支持单引号,双引号,三单引号声明一个字符串;

Quoted.groovy

def quoted() {
def singleQ = 'hello, single quot'// 声明为java.lang.String
def doubleQ = "hello, double quot ${singleQ}"// 如果有${},则为groovy.lang.GString,支持变量替换;否则为java.lang.String
def tripleQ = '''hello,
triple quot'''// 允许多行,而不需要+号

println singleQ
println doubleQ
println tripleQ
}

Groovy 还支持以:

"""..."""
/.../
$/.../$

来声明字符串,详情参见参考文档。

List,Array 和 Map

Groovy 默认使用 java.util.ArrayList 来提供 List 服务,但提供了更加灵活易用的操作方式:

Collections.groovy

def playList() {
def lst = ["a",2,true]//支持不同类型元素

println(lst)
}

playList()

要使用 Array,需要显式声明:

def playArray() {
def intArr = [1, 2, 3] as int[]//显示声明
String[] strArr = ["a", "b"]//另外一种方式

println(intArr)
println(strArr)
}

playArray()

使用 key:value 的方式定义 Map,注意 key 的正确使用方式:

def playMap() {
def map = [a: "a", b: "b"]

println(map)

def key = "name"
def map2 = [key: 'a']//未使用
def map3 = [(key): 'a']//使用

println(map2)
println(map3)
}

playMap()

import

Groovy 提供了更强大的 import

  • 默认 import,这些类都是被默认 import 到代码中的,可以直接使用
import java.lang.*
import java.util.*
import java.io.*
import java.net.*
import groovy.lang.*
import groovy.util.*
import java.math.BigInteger
import java.math.BigDecimal
  • import alias

引入一个类,通过 as 关键字赋予一个别名,有点 JavaScript 的意思么?

Import.groovy

import java.lang.String as KString

println(new KString("aaa"))

语言特性及其本质

Closure(闭包)

闭包的概念不再赘述,大概就是可以将函数作为参数传递和使用,详情参见wikipedia。

{ [closureParameters -> ] statements }

可以省略方括号内的内容,也就是说,可以没有参数列表。

Closure.groovy

当闭包不声明参数列表,默认参数是 it;闭包被定义之后,是一个 Closure 对象,可以对其调用 call 方法使其执行。

def defaultIt() {
3.times {
println it //默认参数 it
}
}

defaultIt()
def closureObj() {
def obj = { a ->
++a
}
println obj.call(1)
}

closureObj()

面向对象特性

  • 定义和实例化一个类

GroovyCLass.groovy

def defaultIt() {
3.times {
println it //默认参数 it
}
}

defaultIt()
def closureObj() {
def obj = { a ->
++a
}
println obj.call(1)
}

closureObj()

  • 方法的默认参数
def foo(String p1, int p2 = 1) {
println(p1)
println(p2)
}

foo("hello")

  • Field 和 Property

Field 是以各种修饰符修饰的变量。Property是私有变量和自带的 gettters/setters,

下面的类具有私有变量 name、age,并自带这两个变量的 getter 和 setter:

class People{
String name
int age
}

当变量声明为 final 的时候,默认就没有 setter

  • Trait

Groovy 提供了一个叫做 Trait 特性实现了多继承,还有很多强大的功能,读者可以自己探索。

trait Fly {
void fly() {
println("fly")
}
}

trait Walk {
void walk() {
println("walk")
}
}

class Duck implements Fly, Walk {

}

Duck duck = new Duck()
duck.fly()
duck.walk()

Groovy 基础小结

至此,我们已经熟悉了 Groovy 的基本语法和特性,相信你也能够使用 Groovy 写一些基础程序了。Groovy 还有很多深入的内容,请用到的时候,参考这本这个 pdf:《Programming Groovy 2》。

下面开始介绍使用 Groovy 写 Gradle 程序,主要的内容来自《Gradle Sser Guide》。

学习 Gradle

Gradle 安装

三种方式安装 Gradle:

  • 下载 zip安装包

  • Mac 下使用 home brew
brew install gradle
  • 推荐:使用 IntelliJ IDEA(Android Studio)自带的 wrapper 结构来下载 Gradle

Wrapper 是为了让不同版本的插件能够使用其对应版本的 Gradle 的一个机制

Gradle Wrapper 会把不同的版本 Gradle 安装在:

$USER_HOME/.gradle/wrapper/dists

Gradle Build 的生命周期

回忆一下《Android Studio 与 Gradle 深入》中的 Android Studio 项目文件结构:

.
├── app //app module
│ ├── build.gradle //app module 的 build.gradle
├── build.gradle //项目 build.gradle,通常配置项目全局配置,如 repositories 和 dependencies
├── gradle.properties //项目属性文件,通常可以放置一些常量
├── lib //lib module
│ ├── build.gradle //lib module 的 build.gradle
└── settings.gradle //项目总体设置,通常是配置项目中所有的 module

Gradle 构建三个阶段:

  • 初始化:Gradle 支持单 module 构建和多 module 构建(Android Studio 创建的项目默认是多 module)。初始化阶段,Gradle 会为每一个 module 中的 build.gradle 文件创建一个 Project 实例。

  • 配置:项目根目录的 build.gradle 会首先被执行

  • 执行:执行所选取的 task

Settings.gradle

多 module 构建要求在项目根目录下有一个 settings.gradle,用来指定哪些 module 参与构建,如:

settings.gradle

include ':app', ':groovy'

println 'print in settings.gradle'

在 settings.gradle 文件中,添加一行打印语句,在控制台中,切换到当前项目根目录下执行:

typedef struct _zval_gc_info {

可以在看出 settings.gradle 的代码每次都会率先执行。

Task

接下来,我们开始学习 Gradle 的核心 Task。

groovy/build.gradle

定义一个 Task:

task hello {
doLast {
println 'Hello,'
}
}

执行命令,查看输出:

$ ./gradlew hello
Hello,

Task 也可以这样定义:

task World << {
println 'World!'
}

注意,如果定义成这样:

task hi {
println 'description hi'
}

在进行初始化和配置的时候,下面语句就会运行。

println 'hi'

这种语法通常是用来定义 task 的描述信息。

Task 可设置 dependsOn 和 finalizedBy:

task hello {
doLast {
println 'Hello,'
}
}

task intro(dependsOn: hello) << {
println 'intro'
}

World.finalizedBy hello

执行 intro 之前,会先执行 hello;执行 World 之后,会自动执行 hello。

Plugin

Gradle 的核心代码,只提供了一个框架,具体的功能(如构建 Android 工程)是通过插件机制来实现的。

Gradle 提供了大量官方的插件,如 Maven、Groovy、Java、Publishing、Signing等,也有大量第三方的插件(Android),甚至每个人都可以自己实现一个插件(如 笔者开发的 Bugtags 插件,这个将在最后一篇讲述)。

这些 plugin 定义了一系列的 task、DSL 和约定,在build.gradle 文件使用这些 plugin:

apply plugin: java

当你写了一个独立的 file_uri.gradle 文件,你可以通过:

apply from: 'file_uri.gradle'

来引入你的 gradle 文件,这个文件甚至可以在某个服务器上。

Gradle 实践参考

学习了基础理论之后,如果你还是不知道如何开始写,那就先来实现一个自定义 apk 名称的功能吧!

android.applicationVariants.all { variant ->//获取 variant 参数,就是 productFlavor x buildType
variant.outputs.each { output ->//获取输出文件
def file = output.outputFile//修改实例
output.outputFile = new File(
(String) file.parent,
(String) file.name.replace(
file.name,
// alter this string to change output file name
"Your_Apk_Name_" + variant.name + "_" + variant.versionName + ".apk"
)
)
}
}

你问我怎么知道 android 下有个 applicationVariants?其实我也不知道的,也得找文档。

因为使用的是 Android 的插件,那就得在谷歌搜 “android gradle plugin dsl”,果然有个Android Plugin DSL Reference。

点进去找找,里面有关于 build variant 的文档:applicationVariants,既然是一个 Set,那就可以调用 all 方法。

写代码调试,再配合文档,你就晓得该怎么写了。

如果你还是不知道如何入手,那我提供几个开源参考:

  • gradle-bintray-plugin:bintray 提供的开源插件
  • gradle-node-plugin: 一个运行 NodeJS 脚本的插件
  • linkedin-gradle-plugins: linkedin的 Gradle 插件集合

参考文档

相信参照开源项目动手写了几个小程序之后,你已经小有感觉了,那就记得把文档地址备齐了,用到的时候,查一下:

  • Groovy Documentation:Groovy 的详细介绍文档
  • Groovy API Reference:Groovy 的 API 文档,必要的时候查阅
  • Gradle User Guid:Gradle 的详细介绍文档,很有必要过一遍
  • Gradle Build Language Reference:Gradle DSL 参考,重点的几个 DSL 过一下,其他的用到再查
  • Android Plugin DSL Reference:使用 Android 插件必备

另外,也有大量很好的中文文档,比如这几篇:

  • 邓凡平老师的 Gradle 介绍
  • Gradle User Guide 中文版

总结

笔者从 Gradle 入门到现在略懂,经历了大量懵懂的时光。最后狠下心去系统学习了 Groovy 和 Gradle 的基础之后,最终茅塞顿开。希望读者遇到类似的情况,一定要沉下心,多学多练。

在接下来的两篇,我将分别介绍将发布远程库和编写 Gradle 插件。

   
1562 次浏览       35
 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
最新活动计划
嵌入式软件架构设计 12-11[北京]
LLM大模型与智能体开发实战 12-18[北京]
嵌入式软件测试 12-25[北京]
AI原生应用的微服务架构 1-9[北京]
AI大模型编写高质量代码 1-14[北京]
需求分析与管理 1-22[北京]

android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...