前言
做为一个做 Android 的同学,我想对于 "Gradle" 是再熟悉不过了,但是对于 Gradle 却是有点陌生,几个月前,只是停留在这样简单的使用上.
compile "com.strange.unfamiliar: 1.0"
什么让我意识到其重要性呢?应该是在秋招完后,刷刷拉勾,看到杭州某创业公司对应届 Andoid 40k 的诱惑,赶紧投了一波,投投投,然后收到了面试邀请,刚开始面,感觉这不按套路出牌啊,并不是很偏 cs 基础,而是在工程实践上,期间问到了 gradle 的问题,当时内心 OS
勉强凑合了几句之后,继续追问,然后全程
面完之后要了面试官的联系方式,进行了一些沟通,意识到了其重要性,然后想着通过项目驱动来深入的学习一波,决定撸 QQ 空间热修复实现方式中打补丁包的 Gradle 插件,没错,就是要抄个 nvwa.
so,准备出一系列文章来分享整个学习的过程.文章其实是从去年已经开始写了两篇,然后持续 delay 了,这里重新捡起来.本篇将对 Gradle 的一些功能,重要性和其一些基础做下讲解,接下来,将进行 Android 项目中 Gradle 的讲解,如何在 AndroidStudio 中使用 Gradle 来进行一些自定义构建.接着来进行一个简单的插件实现,最后着手来进行 hotfix 插件的实现,共分为四个部分,希望在对自己的学习做一个总结的同时,能够让零基础入门的 Gradle 的能够跟随博客对 Gradle 有个认识,同时能够实现一个简单的 Gradle 插件.
Gradle 是什么?
Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化建构工具.它使用一种基于 Groovy 的特定领域语言来声明项目设置,而不是传统的 XML.
那么 Gradle 相比于 Ant 和 Maven 的构建方式,有那些优势呢?
自动处理包相依关系 - 取自 Maven Repos 的概念
自动处理布署问题 - 取自 Ant 的概念
条件判断写法直觉 - 使用 Groovy 语言
过去 Java 开发者常用 Maven 和 Ant 等工具进行封装布署的自动化,或是两者兼用,不过这两个包彼此有优缺点,如果频繁改变相依包版本,使用 Ant 相当麻烦,如果琐碎工作很多,Maven 功能不足,而且两者都使用 XML 描述,相当不利于设计 if,switch 等判段式,即使写了可读性也不佳,而 Gradle 改良了过去 Maven,Ant 带给开发者的问题,至今也成为 Android Studio 内置的封装布署工具.
Android 中 Gradle 可以做什么?
上一篇文章中讲到了一个 Android 项目的构建过程,Android 构建系统编译应用资源和源代码,然后将它们打包成可供您测试,部署,签署和分发的 APK.Android Studio 使用 Gradle 这一高级构建工具包来自动化执行和管理构建流程,同时也允许您定义灵活的自定义构建配置.每个构建配置均可自行定义一组代码和资源,同时对所有应用版本共有的部分加以重复利用.Android Plugin for Gradle 与这个构建工具包协作,共同提供专用于构建和测试 Android 应用的流程和可配置设置.
Gradle 和 Android 插件独立于 Android Studio 运行.这意味着,可以在 Android Studio 内,使用计算机上的命令行工具或在未安装 Android Studio 的计算机(例如持续性集成服务器)上构建 Android 应用.如果您不使用 Android Studio,可以学习如何从命令行构建和运行您的应用.无论您是从命令行,在远程计算机上还是使用 Android Studio 构建项目,构建的输出都相同.
如上图所示,在一个 Project 中,除了我们项目自身的代码和资源之外,会有多个与项目构建相关的. gradle 文件,这些. Gradle 文件用来对于我们使用 Gradle 进行构建项目的整个过程中来使用.
Gradle 中,每一个待编译的工程都叫一个 Project.每一个 Project 在构建的时候都包含一系列的 Task.比如一个 Android APK 的编译可能包含:Java 源码编译 Task,资源编译 Task,JNI 编译 Task,lint 检查 Task,打包生成 APK 的 Task,签名 Task 等.
####Gradle 工作流程
Gradle 的工作流程如下图所示,在每一个工作流程的前后,我们都可以进行一些 hook 操作,来满足自己的需求.
Gradle 工作包含三个阶段:
首先是初始化阶段.对我们前面的 multi-project build 而言,就是执行 settings.gradle
Initiliazation phase 的下一个阶段是 Configration 阶段.
Configration 阶段的目标是解析每个 project 中的 build.gradle.比如 multi-project build 例子中,解析每个子目录中的 build.gradle.在这两个阶段之间,我们可以加一些定制化的 Hook.这当然是通过 API 来添加的.
Configuration 阶段完了后,整个 build 的 project 以及内部的 Task 关系就确定了.一个 Project 包含很多 Task,每个 Task 之间有依赖关系.Configuration 会建立一个有向图来描述 Task 之间的依赖关系.所以,我们可以添加一个 HOOK,即当 Task 关系图建立好后,执行一些操作.
最后一个阶段就是执行任务了.当然,任务执行完后,我们还可以加 Hook.
简言之,Gradle 有一个初始化流程,这个时候 settings.gradle 会执行. 在配置阶段,每个 Project 都会被解析,其内部的任务也会被添加到一个有向图里,用于解决执行过程中的依赖关系.然后才是执行阶段.你在 gradle xxx 中指定什么任务,gradle 就会将这个 xxx 任务链上的所有任务全部按依赖顺序执行一遍!
Gradle 主要有三种对象
这三种对象和三种不同的脚本文件对应,在 gradle 执行的时候,会将脚本转换成对应的对象:
Gradle 对象:当我们执行 gradle xxx 或者什么的时候,gradle 会从默认的配置脚本中构造出一个 Gradle 对象.在整个执行过程中,只有这么一个对象.Gradle 对象的数据类型就是 Gradle.我们一般很少去定制这个默认的配置脚本.
Project 对象:每一个 build.gradle 会转换成一个 Project 对象.
Settings 对象:显然,每一个 settings.gradle 都会转换成一个 Settings 对象.
构建的生命周期,首先根据 settings.gradle 文件构建出一个 Seetings 对象,然后根据 Seetings 中的配置,创建 Project 对象,去找各个 project 下的 build.gradle 文件,根据文件内容来对 project 对象进行配置.
一个 project 中 Task 的数量,取决于其中应用的插架的数目多少,通过
apply plugin: 'com.android.library'
一个 Task 包含若干 Action.所以,Task 有 doFirst 和 doLast 两个函数,用于添加需要最先执行的 Action 和需要和需要最后执行的 Action.Action 就是一个闭包.对于原有的 Task,我们可以在其执行之前或者执行之后,进行一系列的 Hook 操作,在其执行之前和执行之后,添加一些操作.
tasks.getByName("task") {
it.doLast {
println "do the task"
}
}
Groovy 概述
这里将对 Groovy 语言进行一个简单的介绍,通过简单地语法上的介绍,可以很好地看明白接下来对于构建过程中一些简单地 Groovy 语法.通过简短的介绍,可以很好地帮助我们看懂 Gradle 中的一些配置信息.
Groovy 是一种动态语言,基于 Java 并拓展了 Java. Java 程序员可以无缝切换到使用 Groovy 开发程序.Groovy 让写 Java 程序变得像写脚本一样简单.写完就可以执行,Groovy 内部会将其编译成 Java class 然后启动虚拟机来执行.下图是 Groovy 和 Java 代码和 JVM 的关系图.
语言概述
Groovy 中支持动态类型,即定义变量的时候可以不指定其类型.(def 不是必须的,但是为了代码清晰,建议还是使用 def 关键字)
def a = 5;
def b = "groovy"
函数的定义,我们也无需进行参数类型的声明,同时也可以不进行返回值类型的声明,但是需要通过 def 字段来定义,函数的最后一行作为返回值.
def function1(arg1, arg2) {
arg1 + arg2
}
String function2(str1, str2) {
return str1 + str2
}
函数调用支持
参数名:参数值
方式调用
apply plugin: 'com.android.library'
plugin: 参数名,'com.android.library':参数值
强大字符串支持功能
//单引号对应Java中字符串
str1 = 'this string'
//双引号,可通过$进行相应的转译
x = 1 str2 = "This is $x"
//通过换行实现每一行的间距
str3 = '''begin
line1
line2
end'''
闭包
(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数.这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外.所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体.对于闭包的实现,从函数式编程的角度来看就为了解决一个输入对应一个输出的问题.例如当我们想实现一个加法,我们必须通过传递两个参数来实现,但是借助于函数式编程,我们可以做到只传递一个参数.
function plusAny(first) {
return function(second) {
return first + second;
}
}
var longLiveSeniorFunc = plusAny(1);
longLiveSeniorFunc(1);
Closure 结构定义
def xxx = {paramters -> code}
def xxx = {无参数,纯code}
根据上述两种结构,下面分别举例
def closure = {
String param ->
println "This is $param"
}
def closure = {
println 'This is closure'
}
如何调用闭包
closure.call('Hello')
closure('Hello')
闭包隐含一个自身参数 it
def closure = {
println "This is $it"
}
当闭包作为一个函数的参数时
def testClosure(Closure closure) {
closure()
}
testClosure(
println 'Test'
)
总结
本文围绕 Gradle 是什么,可以做什么,在 Android 中起到了什么作用,然后是 Gradle 的工作流程,Gradle 中使用语言 Groovy 的一个概述,帮助我们了解如何更好的使用 Gradle.
参考文章
深入理解 Android(一):Gradle 详解
来源: https://juejin.im/post/5a634ddff265da3e3c6c3dbe