我是靠谱客的博主 能干乌龟,最近开发中收集的这篇文章主要介绍Gradle 里的神奇操作,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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

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

* task
* project

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

## 首先讲 Task 

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

```
gradle tasks -q
```

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

![tasks](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ebbc289d1aa844b1bdd7a129521d0932~tplv-k3u1fbpfcp-zoom-1.image)

根据上图可以看到当前工程中的每条`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`定义与依赖。  

![tasks](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/95f5632961804b359d3a1e2873d906f3~tplv-k3u1fbpfcp-zoom-1.image)

## 接着讲 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 不只是有常用的`group`、`name`、`version`,还包括不常用的`configuration`、`classifier`等等。  

### 再看Task

Groovy 是基于 Java 的,只不过在这基础上加了一大堆的闭包,来帮助更方便的开发构建脚本。如果你不会 Groovy,没关系,当成 Java 写就行了,其实当成 Kotlin 写是最恰当的。

每个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`

![tasks](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8f8f2ae11b27426eb4b1d71581832e0c~tplv-k3u1fbpfcp-zoom-1.image)


## 骚操作的背后

学习任何一门技术,最快的途径就是看源码,`gradle`的源码位于`src`目录中,例如在我本机的路径为:   
`/Users/zhangtao/.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 里的神奇操作的全部内容,希望文章能够帮你解决Gradle 里的神奇操作所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部