半小时掌握Android Gradle

御弟哥哥 等级 590 0 1
标签: gradle闭包Java

目前国内对Android领域的探索已经越来越深,不少技术领域如插件化、热修复、构建系统等都对Gradle有迫切的需求,不懂Gradle将无法完成上述事情。所以Gradle必须要学习。

Gradle 里的几乎任何东西都是基于这两个基础概念:

  • task
  • project

掌握了这两个,你就掌握了一大半的 Gradle 知识了。

首先讲 Task

字面理解为任务,Gradle 中所有执行的事件都是借由 Task 执行的。
例如我们新建一个 Android 工程,在其根目录中输入:

gradle tasks -q 

可以看到如下输出(你可能需要事先配置gradle的环境变量,或也可使用./gradlew替代):

半小时掌握Android Gradle

根据上图可以看到当前工程中的每条task都已罗列出,并且有黄色的输出表示当前task的描述。
其中-q表示忽略gradle本身的log信息,加上这个参数可以屏蔽很多无关的输出,不加也不会影响执行。

Task声明格式

声明一个 task 只需要在任务名前面加上task就可以了,例如下面声明了一个hello的Task。

task hello 

通常我们会给task附带一些执行动作,称之为Action,例如

hello.doFirst{
    println "hello first"
}

hello.doLast{
    println "hello last"
} 

也可以附带一个闭包配置,称之为Configuration,闭包中不仅可用做赋值操作,也可以执行一些自动执行的配置。

hello {
    println "hello"
} 

Task依赖

单独声明一个task在实际开发中几乎不会有任何的意义,更多的时候是让多个task组合起来,一个依赖另一个,形成一连串的任务集。

task hello

hello.doFirst{
    println "hello "
}

task world(dependsOn: "hello") << {
    println "world"
} 

上面这段代码定义了两个task,当我们执行hello任务的时候,会输出 hello,而执行world任务的时候,由于声明了dependsOn: "hello",表示world依赖hello,会先执行hello,再执行world。

task xxx << {
} 

这样的语法等价于

task xxx
xxx.dolast {
} 

你可以在任意位置新建一个名为build.gradle的文本,来练习上面讲述的task定义与依赖。

半小时掌握Android Gradle

gradle, android, kotlin, tasks

接着讲 Project

Android
   │ 
   ├──app
   │   └──build.gradle
   │
   ├──library
   │   └──build.gradle
   │
   ├──*.properties
   │
   ├──build.gradle
   │
   └──setting.gradle 

一个 Android 工程,通常是由上述结构构成,其中有着许多不为人知的巧妙用法。

setting.gradle文件

关于setting.gradle中也可以写代码,是很多人不知道的。在setting.gradle文件中,可以指定一个project位置,这里就可以将一个外部工程中的模块导入到APP工程中了。

getLocalProperties().entrySet().each { entry ->
    def moduleName = entry.key
    if (Boolean.valueOf(entry.value)) {
        def file = new File(rootProject.projectDir.parent, "/${moduleName.replace("\\W", "")}/${moduleName.toLowerCase()}")
        if (file.exists()) {
            include ":${moduleName.toLowerCase()}"
            project(":${moduleName.toLowerCase()}").projectDir = file
        }
    }
} 

build.gradle

一个项目的根gradle文件,用于描述这个项目的统一资源,其中包括各子资源的使用方式、插件的依赖环境等等。

subprojects{
    apply plugin: 'com.android.library'
    dependencies {
      compile 'com.xxx.xxx:xxx:1.0.0'
   }
} 

通常我们在每个模块都会引用的 aar 的时候,都会在每个模块里面都去手动的compile一遍,例如support包。 但实际上有一个非常简单的办法,写一遍就可以了,就是在项目的根gradle文件中的subprojects闭包中声明这个dependencies

通常在写compile依赖的时候,我们都会写成这样:

compile 'com.android.support:appcompat-v7:25.0.0' 

其实在gradle中,这是一个方法调用,它的本质是compile()方法传入了一个map参数,因此完整的写法实际上是这样的:

compile group: 'com.android.support' name:'appcompat-v7' version:'25.0.0' 

同时,map 的可使用 key 不只是有常用的groupnameversion,还包括不常用的configurationclassifier等等。

再看Task

Groovy 是基于 Java 的,只不过在这基础上加了一大堆的闭包,来帮助更方便的开发构建脚本。如果你不会 Groovy,没关系,当成 Java 写就行了,其实当成 Kotlin 写是最恰当的。如果你还不会 Kotlin,我强烈推荐你查看我的 【 Kotlin Primer 】系列文章

每个Task都可以配置其输入与输出,如果一个Task的输出与上一次的输出一致,则不会重复执行。此刻,会在命令行中输出UP-TO-DATE表示已经是最新的结果。
例如如下Task:

task transform {
    ext.srcFile = file('hello.txt')
    ext.destDir = new File(buildDir, 'generated')
    inputs.file srcFile
    outputs.dir destDir
    doLast {
        destDir.mkdirs()
        def ins = new BufferedReader(new FileReader(srcFile))
        def stringBuilder = new StringBuilder()
        def temp
        while ((temp = ins.readLine()) != null) {
            stringBuilder.append(temp)
        }
        def destFile = new File(destDir, "world.txt")
        destFile.text = stringBuilder.toString()
    }
} 

重复执行后会输出UP-TO-DATE

半小时掌握Android Gradle

gradle, android, kotlin, tasks

骚操作的背后

学习任何一门技术,最快的途径就是看源码,gradle的源码位于src目录中,例如在我本机的路径为:
/Users/zhanghongjun/.gradle/wrapper/dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3/src
本地新建一个普通Java工程,导入源码查看代码与注释,这是最好的学习资料。

task hello 

在 Groovy 中,方法括号可以省略,如果字符串的类型是可以被推断的,那么引号也可以省略

public interface org.gradle.api.Project{
    Task task(String name);
    Task task(String name, Closure configureClosure);
}

// TaskFactory
public TaskInternal createTask(Map<String, ?> args) {
} 

闭包的存在,目的是为了更好的为对象初始化。同 Kotlin 一样,当闭包做为最后一个参数的时候,可以省略括号。

Copy a = task(myCopy, type: Copy)
a.from 'resources'
a.into 'target'
a.include('**/*.txt', '**/*.xml', '**/*.properties') 

等价于

task myCopy(type: Copy)

myCopy {
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
} 

本章就讲到这里,下一篇讲如何创建一个Gradle插件,完成编译时向指定类或新生成类中动态添加代码(包括jar包中)。

收藏
评论区

相关推荐

Gradle技术之一 Groovy语法精讲
Gradle技术之一 Groovy语法精讲 gradle脚本是基于groovy语言开发的,想要学好gradle必须先要对groovy有一个基本的认识 1. Groovy特点 groovy是一种DSL语言,所谓的DSL语言,就是专门针对某一特定领域的语言,专精而不专广 是一种基于JVM的开发语言,也是编译成class字节码文件 结合和Pytho
Gradle技术之二 Groovy对文件的操作
Groovy对文件的操作 对文件的遍历 假设文件的原始内容为: hello,world 这里是北京 andorid and ios are good system 第一种方法:使用 eachLine() //1.1 new 一个File def file new File(filepath) //1.2 groovy对文件的遍历 file.
Gradle系列之三 Gradle概述以及生命周期
1 Gradle是一种编程框架 gradle主要由以下三部分组成 1 groovy核心语法 2 build script block 3 gradle api 注:本章所有的代码都在 https://github.com/jiulu313/gradledemo.git 如下图 73485499237410.png(https://img
Gradle技术之四 - Gradle的Task详解
1 Gradle的Task详解 1 Task定义和配置 2 Task的执行 3 Task的依赖和执行顺序 4 Task类型 5 Task结合gradle的生命周期 6 Task实战 1.1 Task定义和配置 1.1.1 查看所有的task java ./gradlew tasks 输出 Task :tasks
半小时掌握Android Gradle
目前国内对Android领域的探索已经越来越深,不少技术领域如插件化、热修复、构建系统等都对Gradle有迫切的需求,不懂Gradle将无法完成上述事情。所以Gradle必须要学习。 Gradle 里的几乎任何东西都是基于这两个基础概念: task project 掌握了这两个,你就掌握了一大半的 Gradle 知识了。 首先讲 Task
Groovy 集合与闭包
Groovy 集合 在 Groovy 提供的所有方便的快捷方式和功能中,最有帮助的一个可能就是内置的 集合。回想一下在 Java 编程中是如何使用集合的 — 导入 java.util 类,初始化集合,将项加入集合。这三个步骤都会增加不少代码。 而 Groovy 可以直接在语言内使用集合。在 Groovy 中,不需要导入专门的类,也不需要初始化对象。集合是语
Groovy中的类
Groovy 中的类 迄今为止,您已经用 Groovy 输出了许多次 “Hello World”,已经操作了集合,用闭包在集合上迭代,也定义了您自己的闭包。做所有这些工作时,甚至还没有讨论那个对 Java 开发人员来说至关重要的概念 — 类。 当然,您已经在这个教程中使用过类了:您编写的最后几个示例就是在不同类的 main() 方法中。而且,您已经知道,在
彻底理解js闭包
在文章开头,我先放出MDN给出的定义: 闭包是指那些能够访问独立(自由)变量的函数 (变量在本地使用,但定义在一个封闭的作用域中)。换句话说,这些函数可以“记忆”它被创建时候的环境。 现在不需要看懂它,我会在第一个例子中解释清楚它的意思。让我们开始吧! 2018.3.20更新:现在MDN上的定义已经改为:"A closure is the comb
Retrofit 动态修改BaseUrl 操作
开发中会遇到URL需要动态切换,若你还是通过gradle打包切换是否不太灵活,下面将介绍一下retrofit基于OKhttp中动态修改URL; 原理添加拦截器,在retrofit中的现实更加灵活了如下代码: language private RetrofitUrlManager() { if (DEPENDENCY_OKHTT
Python 中的闭包
闭包定义: 如果在一个内部函数里,对在外部作用于(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包 Python 中的闭包 原文出处: 田小计划(http://www.cnblogs.com/wilber2013/p/4658894.html) 闭包(closure)是函数式编程的重要的语法结构
Kotlin 协程中,关于 runBlocking, launch ,withContext ,async,doAsync 之间的简单区别
引入大佬的话,Kotlin的协程,本质上是一个线程框架,它可以方便的切换线程的上下文(如主线程切换到子线程/子线程切回主线程)。而平时我们要想在Android Studio使用协程,先要在gradle引入协程依赖: implementation "org.jetbrains.kotlinx:kotlinxcoroutinescore:1.3.3"
JS - 从执行上下文的角度来理解闭包
今天看到一篇关于闭包的文章,里面有这样一句话 “就我而言对于闭包的理解仅止步于一些概念,看到相关代码知道这是个闭包,但闭包能解决哪些问题场景我了解的并不多”,这说的不就是我么,每每在面试中被问及什么是闭包,大部分情况下得到的答复是(至少我以前是)A函数嵌套B函数,B函数使用了A函数的内部变量,且A函数返回B函数,这就是闭包。而往往面试官想要听到的并不是这样的
重学JavaScript(函数)闭包
序言学习JavaScript切勿好高骛远。正所谓贪多嚼不烂,前端标准和工具这几年的飞速发展,以及不时冒出的“新鲜玩意”让众多前端从业者惊呼:“学不动啦学不动啦!学习速度跟不上技术发展速度!我感到手忙脚乱、力不从心……"如果你有以上“症状”,请勿着急,这不过是你内心不安造成的。你为何追新?你又何苦追新?在根基不牢的情况下,就算盖楼盖到18层,再往上堆一块砖,都
小记面试题-2021
CSS类 1.解释浮动及其工作原理浮动的元素可以向左或者向右移动,直到它的外边缘碰到包含元素(父元素)或另一个浮动元素的边框为止。要想使元素浮动,必须为元素设置一个宽度。虽然浮动的元素已不在文档流中, 但是它浮动后所处的位置依然在浮动之前的水平方向上。因为浮动元素不在文档流中,所以文档流中的块元素表现的就像浮动元素不存在一样,下面的元素会填补原来的位置。有些
【IDEA】实战,阿里二面被问到构建及二次开发,直接裂开!!
JMeter5.4.1源码IDEA构建&二次开发(实战) 1.下载源码 2.导入IDEA 2.1 先设置Gradle目录未设置过Gradle的IDEA,建议先设置下Gradle的用户目录 2.2导入JMeter工程 2.3设置国内Gradle源 设置gradle的下载源速度直接起飞!😂重新加载Gradle,或者重新加载项目接下来就是耐心的等等待,网速好的话,