作为合格的 Android 开发者必须了解的Gradle文件及其背后的原理
来源:互联网 发布:java volatile 原子类 编辑:程序博客网 时间:2024/06/09 17:07
在Android开发中,很多时候我们不需要修改 *.gradle 文件太多,我们添加依赖、修改target compile、最低支持API level,或者修改签名配置和build类型。其它更复杂一些逻辑,我们最后可能就是从Stack Overflow中copy了一些自己也不太懂的代码。本文中我们将一步一步介绍Android工程中用到的gradle文件及其背后的原理。
1. Groovy
1.1 语法
Gradle文件其实是用Groovy脚本写的,我们都会写java,所以入门Groovy非常简单。首先我们需要了解一下几点:
1.调用至少包含一个参数的方法时不需要使用括号:
2.如果方法的最后一个参数是闭包(或者说是lambda表达式),可以写在括号外(注:这个特性很重要,gradle文件中的很多配置其实都是参数为闭包的方法):
3.对于Groovy方法中命名过的参数,会被转移到一个map中做为方法的第一个参数,那些没有命名的参数则加在参数列表之后:
这段程序会打印“John is 24 years old”和“John works as Android developer at Tooploox”,方法调用的参数可以是乱序的,map会被作为第一个参数传入!这里的方法调用也省略了括号。
1.2 闭包
闭包是一个非常重要的特性,需要解释一下。闭包可以理解为lambada。他们是一段可以被执行的代码,可以有参数列表和返回值。我们可以改变一个闭包的委托:
我们可以看到 printClosure 调用了不同委托的 printText 方法,之后会解析这个特性在gradle中的重要性。
2. Gradle
2.1 脚本文件
有三个主要的gradle脚本,每个都是一个代码块。
- build.gradle 文件,针对 Project 对象
- settings.gradle文件,针对 Settings 对象
- 全局配置的初始化gradle脚本,针对 Gradle 实例
2.2 Projects
gradle 构建一般包含多个Project(在Android中每个module对应这里的project),project中包含tasks。一般至少有一个root project,包含很多subprojects,subproject也可以嵌套project(注:Android 中对应每个library module还可以依赖其它library module)。
3. 构建基于Gradle的Android工程
Android工程中我们一般有如下的结构:
1是root project的setting文件,被 Settings 执行
2是root project的build配置
3是App project的属性文件,会被注入到 App的 Settings 中
4是App project的build配置
3.1 创建gradle工程
我们新建一个文件夹,命名为 example , cd 进入后执行 gradle projects 命令,之后就已经拥有一个gradle project了:
3.2 配置projects层级
如果我们要建立一个默认的Android project(空的root project和一个包含Application的app project),我们就需要配置 settings.gradle , the documentation 中介绍 settings.gradle :
声明需要实例化的配置和build的project的层级体系配置
我们通过void include( String [] projectPaths)方法来添加projects:
这里的冒号 : 用于分隔子project,可以参考这里 here 。因此我们在这里写 :app , 而不是直接写 app 。
在 settings.gradle 中写 rootProject.name = <<name>> 也是一个比较好的实践。如果没有写,那么root project 的默认名字就是project所在文件夹的名字。
3.3 配置Android 子project
我们已经配置了root project的 build.gradle ,现在来看看如何配置Android project。
从 user guide 可以知道我们首先要为app project配置 com.android.application 插件,我们来看看 apply 方法:
尽管第三个方法很重要,我们通常使用是第二个方法,它用到我们之前提到的特性,通过map来传递参数。通过文档我们可以查看可以使用哪些参数:
以下是可用的参数:
from: 可以引入一个脚本apply(...),如 apply from: "bintray.gradle" 从而导入一个可用脚本。
plugin: apply的plugin的id或者实现类
to: 委托目标
我们知道需要传递一个id值作为 plugin 的参数,可以写作: apply(plugin:'com.android.application') ,这里的括号也可以省略,我们在app的 build.gradle 中配置:
命令行中运行:
报错了,找不到 com.android.application 的定义,这不奇怪,我们并没有配置,但是gradle是如何查找Android的plugin jar包呢?在 user guide 可以找到答案,我们需要配置plugin的路径。
现在我们可以在root project或者app的 build.gradle 中配置路径,但是因为 buildscript 闭包是 ScriptHandler 执行的,其它子project也需要使用,因此最好配置在root project的 build.gradle 中:
如果我们在上边的代码中添加括号,那么就会发现其实都是带有闭包参数的方法调用。如果我们研究下 文档 ,我们就可以知道是有哪些对象执行这些闭包的,总结如下:
buildscript(Closure) 是 Project 实例中调用的,传递的闭包的由 ScriptHandler 执行
repositories(Closure) 是在 ScriptHandler 实例中调用,传递的闭包由 RepositoryHandler 执行
dependencies(Closure) 是在 ScriptHandler 实例中调用,传递的闭包由 DependencyHandler 执行。
也就是说 jcenter() 是由 RepositoryHandler 调用
classpath(String) 是由 DependencyHandler(*) 调用
译者注:如果这里看不懂的同学,可以再回头看看groovy的语法部分,其实这里上边的代码都是方法,如buildscript是Project的方法,我们知道groovy语法中如果最后一个参数是闭包的话,可以不写括号。
如果查看 DependencyHandler 的代码,我们会发现其实没有 classpath 这个方法,这是一种特殊的调用,我们在稍后讨论。
3.4 配置Android subproject
如果我们现在执行Gradle task,依然有错误:
显然,我们还没有设置Android相关的配置,但是我们的Android plugin已经可以被正确apply了,我们增加一些配置:
到这里我们知道,android方法被加入到了 Project 实例中,闭包传递给了delegate(这里是AppExtension),定义了 buildToolsVersion 和 compileSdkVersion 方法,Android plugin使用这种方式接收所有的配置,包括default configuration,flavors等等。
想要执行gradle task,还需要两个文件: AndroidManifest.xml 和 local.properties , local.properties 中配置 sdk.dir ,(或者在系统环境中配置 ANDROID_HOME ),指向Android SDK的位置。
3.5 扩展
android 方法是如何出现在 Project 实例中的呢,还有我们的build.gradle是怎样被执行的?简单的说,Android plugin 用android这个名字注册 AppExtension 类为 extension 。这个超出了本文的范围,但是我们要知道Gradle可以为每一个注册过的 plugin增加闭包配置。
3.6 依赖
还有一个重要的部分,dependencies还没有讨论:
为什么这里特殊呢,因为如果查看 DependencyHandler ,也就是执行这个闭包的委托,它是没有 compile , testCompile 等方法的。这个问题是有意义的,如果我们随意增加一个 freeCompile 'somelib' ,可以吗? DependencyHandler 不会定义所有的方法,其实这里涉及到Groory语音的另一个特性: methodMissing ,这允许在运行时catch对于未定义方法的调用。
实际上Gradle使用了 MethodMixIn 中声明的 methodMissing ,类似的机制在为定义的属性中也是一样的。
相关的dependency操作可以在 这里 找到,它的行为如下:
如果未定义方法的调用方有至少一个参数,如果存在 configuration() 与被调用方法有相同的名字,那么就根据参数的类型和数量,调用具有相关参数的 doAdd 方法。
每个plugin都可以增进configuration到dependencies handler中,如Android插件增加了 compile, compileClasspath, testCompile 和一些其它配置 here ,Android 插件还增加了 annotationProcessor 配置,根据不同build类型和产品形式还有 <variant>Compile, <variant>TestCompile 等等。
由于 doAdd 是私有方法,一次这里调用的是公有的 add 方法,我们可以重写上边的代码,但最后不要这样做:
3.7 Flavors, build types, signing configs
我们看以下代码:
如果我们查看源码,可以发现productFlavors是这样声明的:
Action<T> 是Gradle中定义的由 T 执行的闭包
所有这里我们有了 NamedDomainObjectContainer , NamedDomainObjectContainer 可以创建和配置多个 ProductFlavorDsl 类型的对象,并根据 ProductFlavorDsl 的名字保存 ProductFlavorDsl 。
这个容器可以使用动态方法创建指定类型的对象(这里的ProductFlavorDsl),并和名字一起存放在容器中,所以当我们使用 {} 参数调用 prod 方法时,他被 productFlavors 实例执行,执行说明如下:
NamedDomainObjectContainer 获取到被调用方法的名字,生成 ProductFlavorDsl 对象,配置给定的闭包,保存方法名字到新的配置 ProductFlavorDsl 的映射。
Android plugin可以从 productFlavors 中获取 ProductFlavorDsl ,我们可以把它作为属性进行访问: productFlavors.dev ,这样我们就可以拿到名字为 dev 的 ProductFlavorDsl ,这也是我们可以写 signingConfig signingConfigs.debug 的原因。
4. 总结
对于Android开发者来说,Gradle文件是非常常用的,并不是什么黑魔法。但是Gradle有很多约定,而且使用Groovy语言也增加了一些复杂性,知道这两点,Gradle并不是什么魔法。希望了解通过这篇文章介绍的内容,即使是从stackoverflow中粘贴代码,也能知道它背后的意义。
这是一篇译文,原文作者对Android的gradle进行了比较深入的介绍,希望各位同学可以真正了解我们常用的gradle文件背后的原理,而不仅仅是简单地配置gralde。文中有些不太容易理解的地方,可以根据文中给出的链接了解更多内容。
写在最后:FOR Freedom 看看外边的世界,以及IT这一行,少不了去Google查资料,最后,安利一个V——PN代理。一枝红杏 加速器,去Google查资料是绝对首选,连接速度快,使用也方便。我买的是99¥一年的,通过这个链接(http://my.yizhihongxing.com/aff.php?aff=2509)注册后输上会员中心得优惠码,平摊下来,每月才7块钱,特实惠。
本文标签: Android Gradle文件 Android开发 Gradle实例 服务器
转自 SUN'S BLOG - 专注互联网知识,分享互联网精神!
原文地址: 《作为合格的 Android 开发者必须了解的Gradle文件及其背后的原理》
相关阅读:《我是 G 粉,一直关注 Google,最近 Google 有一些小动作,可能很多人不太了解》
相关阅读:《机器学习引领认知领域的技术创新,那么SaaS行业会被机器学习如何改变?》
相关阅读:《VPS 教程系列:Dnsmasq + DNSCrypt + SNI Proxy 顺畅访问 Google 配置教程》
相关阅读: 对程序员有用:2017最新能上Google的hosts文件下载及总结网友遇到的各种hosts问题解决方法及配置详解
相关阅读:《Aaron Swartz – 互联网天才开挂的人生历程:每时每刻都问自己,现在这世界有什么最重要的事是我能参与去做的?》
相关阅读:《网站环境apache + php + mysql 的XAMPP,如何实现一个服务器上配置多个网站?》相关阅读:《什么是工程师文化?各位工程师是为什么活的?作为一个IT或互联网公司为什么要工程师文
相关阅读: 《win10永久激活教程以及如何查看windows系统是不是永久激活?》
相关BLOG:SUN’S BLOG - 专注互联网知识,分享互联网精神!去看看:www.whosmall.com
原文地址:http://whosmall.com/?post=245
- 作为合格的 Android 开发者必须了解的Gradle文件及其背后的原理
- 作为 Android 开发者必须了解的 Gradle 知识
- 合格网络管理员必须了解的主要职责
- 作为前端,你必须了解的浏览器工作原理
- Android 开发者和设计师必须了解的颜色知识
- 一个合格的站长必须了解身边的营销模式
- android 开发者需要了解的
- 作为.NET开发者你必须熟悉的几个工具
- 作为.NET开发者你必须熟悉的几个工具
- 作为开发者必须知道的5个安卓应用推广方式
- 作为程序员,你必须了解的几个开源协议
- 作为一个优秀程序必须了解的知识
- 关于iOS中的图片格式,一个合格的开发者必须知道的5个知识点
- 移动开发者必须了解的10大跨平台工具
- 移动开发者必须了解的10大跨平台工具
- 移动开发者必须了解的10大跨平台工具
- 移动开发者必须了解的10大跨平台工具
- 移动开发者必须了解的10大跨平台工具
- 原生ECMAScript模块(ECMAScript modules)概述
- nginx如何启用对HTTP2的支持 | nginx如何验证HTTP2是否已启用
- 网站是PHP程序写的,我为什么说要选linux系统的php虚拟主机?
- 中文翻译为"具象状态传输"的RESTful的架构风格和设计思想
- 堆排序:什么是堆?什么是最大堆?二叉堆是什么?堆排序算法是怎么样的?PHP如何实现堆排序?
- 作为合格的 Android 开发者必须了解的Gradle文件及其背后的原理
- 关于 TensorFlow 的 gentlest 的介绍:了解 TensorFlow(TF)进行多个特征的线性回归和逻辑回归
- 如何从Chrome源码看浏览器如何计算CSS?
- 归纳9种CSS样式自动生成在线工具的优缺点
- 微信小程序开发笔记:为了做一个录制按钮,研究了下小程序的实时圆形进度条实现
- 谷歌Google是如何开发出来Web 框架的?
- Tensorflow【机器学习】:关于fast neural style【快速风格化图像】的理解和实现
- TensorFlow【机器学习】:如何正确的掌握Google深度学习框架TensorFlow(第二代分布式机器学习系统)?
- 谈一谈几种处理 JavaScript 异步操作的办法