2018年的第一篇文章将会给大家介绍Gradle,这会是一个系列的文章,名字依旧是一口一口吃掉。
相信很多朋友都和我一样从eclipse转到Android Studio时是又爱又恨,爱是因为Android Studio功能强大,UI也很炫酷,当然还有Google爸爸支持;恨是因为从比较熟悉的eclipse一下子转到了Android Studio,本以为速度会快很多,然而现实却给了自己一记大耳光,其次就是Android Studio采用了Gradle来对项目进行编译,但是Gradle是个啥鬼咯,配置文件又看不懂,首次编译还得下载,下载速度贼慢,不fq就gg。
Android Studio现在已经更新到3.0.1.0,如果你对Gradle还不是很熟悉,那这个系列的文章将会帮到你。相信仔细看完整个系列之后你将会对如何在Android开发中使用Gradle得心应手。祝你好运,我们出发吧!


何为Gradle

在了解Gradle之前,我们来讲讲在Gradle之前我们构建Android程序的时候使用的最多的是Ant以及Maven,我们简单看看三者有什么区别。

Ant

Ant是在2000年的时候发布的,因其简单易学的特点很快就成为了十分流行的Java项目的构建工具。
Ant的优点就是:

  • 简单、易学,不需要什么特殊准备就能上手
  • 基于过程式编程思想使得构建非常灵活

不足之处就是使用XML作为脚本配置格式,如果项目比较大的话,XML文件将会很难管理。

Maven

Maven是在2004年的时候发布的,他的出现在一定程度上解决了Ant的一些缺点。但是Maven同样沿用了Ant的做法:即把XML作为构建配置的文件格式,不过文件结构却有了巨大的变化:

  • Ant需要开发者将执行task所需的全部命令都列出来
  • 而Maven依靠约定并提供现成的可调用的目标
  • 不仅如此,Maven更重要的一个进步是具备从网络上自动下载依赖的能力(当然Ant后来通过Ivy 也具备了这个功能)。

Maven的缺点就是:

  • 依赖管理不能很好地处理相同库文件不同版本之间的冲突(Ivy在这方面更好一些)
  • XML作为配置文件的格式有严格的结构层次和标准,定制化目标很困难

Gradle

Gradle则是在2012年发布的,它吸收了前两者的优点并极大的改进了他们的缺点,使其成为了Google官方推荐的构建语言。Gradle最大的改进就是摒弃了XML而是使用了一门基于java的Groovy语言作为构建脚本的书写语言,使得原本采用XML、冗杂得难以维护的配置文件变得清爽强大许多。

如果你还想对三者的对比有一个更直观的印象,可以查看这篇文章了解更详细的内容。这篇文章介绍了完成同一任务,三个构建工具的代码如下:
Ant的ivy.xml文件

1
2
3
4
5
6
7
<ivy-module version="2.0">  
<info organisation="org.apache" module="java-build-tools"/>
<dependencies>
<dependency org="junit" name="junit" rev="4.11"/>
<dependency org="org.hamcrest" name="hamcrest-all" rev="1.3"/>
</dependencies>
</ivy-module>

Ant的build.xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<project xmlns:ivy="antlib:org.apache.ivy.ant" name="java-build-tools" default="jar">  
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="lib.dir" value="lib" />
<path id="lib.path.id">
<fileset dir="${lib.dir}" />
</path>

<target name="resolve">
<ivy:retrieve />
</target>

<target name="clean">
<delete dir="${build.dir}"/>
</target>

<target name="compile" depends="resolve">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="lib.path.id"/>
</target>

<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"/>
</target>

</project>

Maven的pom.xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.technologyconversations</groupId>
<artifactId>java-build-tools</artifactId>
<packaging>jar</packaging>
<version>1.0</version>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
</plugin>
</plugins>
</build>

</project>

Gradle的build.gradle文件则只需要如下代码即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apply plugin: 'java'  
apply plugin: 'checkstyle'
apply plugin: 'findbugs'
apply plugin: 'pmd'

version = '1.0'

repositories {
mavenCentral()
}

dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
}

单单从代码量上做一个选择的话,相信大家都会选择Gradle吧!

Gradle有啥作用

我们一直在说Gradle是一个构建工具,可是构建(build)究竟是个啥意思呢?我们以Android平台为例,构建就是将我们的代码,资源文件进行打包,编译最后形成一个可以安装运行的apk文件的过程。如果你还不是很了解,那么我们来瞧瞧Google官方给出的Android应用程序构建的完整流程图吧!

典型 Android 应用模块的构建流程
典型 Android 应用模块的构建流程

上述的流程主要包含以下几个过程:
1
2
3
4
将程序中的以及引用的第三方库中的资源文件、代码文件、和aidl文件通过java编译器编译成.class文件,再通过dex工具将.class文件转换为.dex文件。
使用apkbuilder工具将所有未编译的资源(如图片),已编译的资源和.dex文件打包到.apk文件中。
jarsigner工具使用调试密钥或正式发行版本的秘钥将.apk文件签名。
使用zipalign工具对齐.apk包中的文件,以减少其在设备上运行时的内存占用。

以上的每个步骤就是构建工具需要完成的,也就是说这其中的许多事情都是由Gradle来干的。所以说没有Gradle那就需要我们手动一个步骤一个步骤做,有了构建工具,程序员只需要动动手指就可以啦!

搭建Gradle开发环境

工欲善其事,必先利其器,想要了解并且使用Gradle,我们得先把开发环境搭建起来。

下载

下载的方法有很多种,这里介绍的是适用于各个平台的,首先需要到Gradle官网,然后找到你想要的版本下载即可。需要注意的是Gradle官网的服务器在国外,所以下载速度贼慢,最好是能够自备梯子,否则你需要耐心等待一段时间。
在这个页面中你会看到同一个版本号也有几个版本,如:-src对应的是Gradle源代码,这个不是我们需要下载的;-bin对应的是二进制版本,但不包含源代码,文档等,体积相对较小;-all版本是完全版,既包含了编译需要的二进制文件,也包含了源代码和开发文档等。
推荐大家一开始可以下载一个-all版本作为你主要使用的版本,如果你需要使用到其他版本号的,再去下载其他版本号对应的-bin版本,这样可以节省磁盘空间。当然如果你只安装了-bin版本,你可以到这里查看在线的官方文档,在这里查看Gradle的源代码。

解压&配置环境变量

下载完成之后需要解压,以-all版本为例,解压之后的目录结构如下图所示:

gradle-4.1-all目录结构图
gradle-4.1-all目录结构图

接着就是配置环境变量
Linux系统下
1
2
3
4
5
vim /etc/profile
## 将"/usr/local/gradle-4.3"替换为你解压好的gradle的根目录
export GRADLE_HOME=/usr/local/gradle-4.3
PATH=$PATH:$GRADLE_HOME/bin
source /etc/profile

Windows系统下
在环境变量配置页面新增一个系统变量GRADLE_HOME,值为你解压好的gradle的根目录;接着修改Path变量,在最后追加%GRADLE_HOME%\bin;,之后点击应用,确定即可。

配置好之后需要测试一下Gradle的开发环境是否搭建成功,在linux下打开终端,在Windows下则是打开命令行,输入gradle -v然后回车,如果输出的信息与下面类似那就说明Gradle的开发环境已经搭建成功啦!

1
2
3
4
5
6
7
8
9
10
11
12
bob@bob-PC:~$ gradle -v
------------------------------------------------------------
Gradle 4.3
------------------------------------------------------------

Build time: 2017-10-30 15:43:29 UTC
Revision: c684c202534c4138b51033b52d871939b8d38d72

Groovy: 2.4.12
Ant: Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM: 1.8.0_131 (Oracle Corporation 25.131-b11)
OS: Linux 4.9.0-deepin4-amd64 amd64

写一个Hello World的小demo

前面我们说到Gradle是基于Groovy的,所以我们还得再学Groovy,下面的这个例子我们就先来领略一下Groovy,具体的语法我们将在下一篇文章继续学习。
首先我们新建一个目录,然后在目录下新建一个build.gradle文件,接着用记事本或者sublime打开,写入如下代码:

1
2
3
task hello{
println 'Hello World'
}

之后保存,之后打开终端(Windows使用命令行)进入当前目录(Windows可以直接在当前目录下同时按住Shift键和鼠标右键选择命令行或者Powershell打开则可以直接进入当前目录),输入如下代码:

1
gradle -q hello

不出意外的话屏幕上会打印Hello World。

我们再来回顾一下整个过程,首先是新建一个build.gradle文件,有没有很熟悉呢?在Android项目中,也经常会出现build.gradle文件,在工程中他扮演着十分重要的角色,现在只需要知道它是整个项目的入口即可,具体的我们后续再讲。
接着我们再来看看在build.gradle文件中插入的代码是什么意思:

1
2
3
task hello{
println 'Hello World'
}

首先声明了一个task(任务),这个任务的名称叫做hello,接着使用{}将该任务的内容包围起来,即花括号里面的内容就是这个hello任务的内容,我们看到他的输出语句与java十分相似,但是也有不同点:

  • java中方法的声明和调用需要使用(),但是groovy则可以不用,这样可以更加简洁。
  • java使用双引号来表示字符串,但是在groovy中则直接使用了单引号,这是因为在groovy的语法中,字符串的表达方式比较多种,有的需要单引号'',有的需要双引号"",还有的需要三引号'''''',每种符号都有他使用的场景与作用,这个我们也是放到后面再讲。
  • java需要使用分号来表示一行语句的结束,而groovy与kotlin一样不需要使用分号来作为语句的结束标志,只需要换行即可。
    最后我们使用命令行输入的gradle -q hello又是代表什么意思呢?
    首先gradle则是命令,它会去查找当前所在目录下的build.gradle文件,因为这个文件就是整个命令的入口,而hello就是我们刚才命名的任务的名称,那么-q又是什么呢?其实这里的-q代表quiet模式,它不会生成 Gradle的日志信息(log messages),所以用户只能看到tasks的输出,这样可以让输出信息更加清晰。

通过上面的说明大家应该都能够理解。

Gradle Wrapper

相信大家在运行github上的项目时经常会出现导入失败的问题,例如我们将一个项目导入了Android studio,但是由于项目使用的gradle版本与我们本机安装的不一致,尽管我们可以手动更改配置文件使得该项目使用我们本机的gradle,不过不同的gradle版本对应用程序的编译支持又不一样,所以最好就是还得自行下载gradle然后再运行,这就是为什么我们在Android studio倒入一个项目有的时候需要很久的原因。为了应对着一些列复杂的操作,Google推出了gradle wrapper(即gradle包装器)。接下来我们来看看gradle wrapper是如何解决的。

首先程序的开发者需要为工程提供gradle wrapper的支持

我们使用者想要使用gradle wrapper来构建项目,得需要项目的开发者为该工程添加gradle wrapper的支持,这样我们要使用的时候才知道需要哪个版本的gradle来构建项目。为工程添加gradle wrapper其实很简单,一般来说有两种方法。

使用终端(或命令行)添加gradle wrapper

在项目的根目录下打开终端或者命令行并进入到该目录,接着使用如下的命令即可:

1
2
3
4
5
## 将下方4.0换成你需要的gradle版本号,将all换成你需要的版本类型,例如bin
bob@bob-PC:~/workspace/gradle_workspace/how_to_use_gradleWrapper$ gradle wrapper --gradle-version 4.0 --distribution-type all

BUILD SUCCESSFUL in 9s
1 actionable task: 1 executed

如果出现了上方的构建成功的信息则代表已经成功为工程添加了gradle wrapper。

编写文件添加gradle wrapper

我们还可以通过编辑项目根目录的build.gradle文件,为该文件添加如下代码:

1
2
3
4
task wrapper(type: Wrapper) {
gradleVersion '4.0'
distributionType 'all'
}

我们可以看到其实就是添加了一个名为wrapper的任务,该任务还接受一个Wrapper类型的参数,然后在任务内部可以定义gradle的版本号,以及版本类型,根据我们的需要自行修改即可。
添加完该任务之后还是打开终端或者命令行进入项目的根目录执行wrapper任务:

1
2
3
4
bob@bob-PC:~/workspace/gradle_workspace/how_to_use_gradleWrapper$ gradle wrapper

BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

通过这种方式我们也是可以为项目添加gradle wrapper的。

添加了gradle wrapper之后项目的根目录下添加了如下几个文件:

1
2
3
4
5
6
7
8
.
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat

新增加的四个文件各有含义:

  • gradlew:linux下执行gradle wrapper的脚本
  • gradlew.bat:windows下执行gradle wrapper的脚本
  • gradle-wrapper.jar:gradle wrapper微类库,包含下载和解包gradle运行时的逻辑
  • gradle-wrapper.properties:gradle wrapper元信息,包含已下载gradle运行时的存储位置和原始URL

使用gradle wrapper构建项目

现在我们使用者已经拿到了支持gradle wrapper的项目,我们只需要打开终端或者命令行并导航到项目的根目录然后执行:

1
2
3
4
## linux系统下
./gradlew build
## Windows系统下
gradlew build

即可编译项目。这里的gradlew就是gradle wrapper的缩写了。当我们使用gradlew运行gradle时,他会首先检查wrapper对应的gradle是否可用,如果可用,他会将gradlew的所有参数委托给gradle,然后执行构建,如果gradle包不可用,它就会首先下载对应版本的gradle,然后再构建。

下载很慢怎么办?

如果执行了上述的命令之后发现gradle的下载很慢,那我们可以手动修改gradle-wrapper.properties文件,将其中的distributionUrl更改成下面这样,这样他就会复用我们本地的gradle而不是去服务器下载。

1
2
3
4
## linux系统下:
distributionUrl='file:/home/bob/gradle/gradle-4.0-all.zip'
## Windows系统下:
distributionUrl='file:///D:/grale/gradle-4.0-all.zip'

Gradle该如何学习

通过上面的学习想必大家对gradle应该有了初步的认识了,但是gradle的知识还有很多,那我们要怎么学呢?

  • 首先gradle是基于groovy语言的,所以我们需要对groovy的语法有所了解,我们将在下一节与大家一起学习。
  • 接着就是深入到Android项目中,来看看gradle的文件结构。
  • 随后需要了解的就是gradle的插件,这些插件有的是专门用于Android项目的构建的,所以我们需要结合文档一起来理解。
  • 再后面的话我们还得了解如何构建变体,例如我们需要为一个项目编译多个不同应用市场的渠道包。
    当然还有很多,这里只是先给大家一个思路,之后的文章我们一起继续学习。