gradle 和 gradlew 的区别
如果配置好了 gradle 环境变量后, 就可以在 cmd 中使用 gradle 命令了
在 cmd 中输入: gradle -v
输出如下:
------------------------------------------------------------ |
但是有时候没有配置环境变量,却在 Android 项目根目录使用 gradlew 命令
./gradlew -v |
输出的版本和 gradle-wrapper.properties 文件中的版本一致
其实 gradlew 是 gradle wrapper 的简写。Gradle wrapper 是 Gradle 的核心特性,能够让机器在没有安装 Gradle 运行时的情况下运行 Gradle 构建,也可以让构建脚本运行在一个指定的 Gradle 版本上。
使用 Wrapper 被认为是最佳实践,这样在不同的机器上面,构建的版本就能够保证统一。使用了包装器的 Gradle 脚本非常适合作为自动化发布的一部分,比如持续集成。
我们每个 Android 项目的根目录下都有一个 gradlew 的可执行文件,./gradlew 正是访问的这个文件
Gradle 构建块
每个 Gradle 构建都包含三个基本构建块:project、task、property。每个构建至少包含一个 project,进而包含一个或者多个 task。project 和 task 暴露的属性可以用来控制构建。
Gradle 使用的是领域驱动设计(DDD)的原理为其自己的领域构建软件建模。因此,在 Gradle API 中有相应的类来表示 project 和 task。
Gradle API 中有相应的类来表示 project 和 task。这一点是要明确的,Gradle 中的脚本实际上是转为代码来执行的。
项目 Project
在 Gradle 术语中,一个项目(project)代表一个正在构建的组件,比如一个 JAR 文件,或一个想要完成的目标,如部署应用程序。
当构建进程启动后,Gradle 基于 build.gradle 中的配置实例化 org.gradle.api.Project 接口,并且能够通过 project 变量使其隐式可用。
关于 Project 的介绍可以看这里: https://www.jianshu.com/p/434eba22561e
任务 Task
任务动作 task action,定义了一个当任务执行时最小的工作单元。
任务依赖 task dependency,很多时候运行一个 task 之前需要运行另一个 task。
Gradle task 对应的 API 是 org.gradle.api.Task 接口。
关于 task 更多的介绍可以看这里 https://www.jianshu.com/p/60bf794cdf91
属性 Property
每个 Project 和 Task 实例都提供了可以通过 getter 和 setter 方法访问的属性。一个属性可能是一个任务的描述或者项目的版本。
你也可以定义自己的属性。Gradle 允许用户通过扩展属性自定义一些标量
Gradle 插件分类
Gradle 插件分为两类:
脚本插件,是一个普通的 Gradle 构建脚本,它可以被导入到其它的构建脚本中。
对象插件,需要实现 org.gradle.api.Plugin 接口。
1 使用脚本插件
假设我们有一个脚本名为 sayhello.gradle ,它里面有一个 task:
task sayHello << { |
然后我们在 build.gradle 中依赖这个外部脚本,调用 Project 的 apply 方法,apply 方法调用时传入 from 属性,它的值可以是任何类型的 URL,比如 HTTP 地址。
apply from: 'sayhello.gradle' |
此时我们运行 gradle sayHello 命令,可以看到 sayHello 这个 task 执行了:
:sayHello |
通过 apply from 的方式引入脚本插件,就好像那个脚本插件中的内容是写在当前的 build.gradle 中一样。它是使用比较简单,这里就不多做介绍了。
对象插件
我们之前讲了自定义的 task,它的实现逻辑是一种可维护、可测试的解决方案。通过打包成 jar 文件,task 可以在独立的项目中被重用。然而,该方式仍有一些限制。
优点:
- 定制逻辑在类中是自包含的,并且可以通过增强型 task 配置
- 通过将 task 属性用注解标志可以支持声明式增量构建
自定义的 task 可以测试
缺点:自定义的 task 仅仅暴露独立的工作单元。所提供的额外的公式化代码、约定和生命周期的整合并不是很直接
- 自定义的 task 仅仅能通过增强型 task 来配置。通过自定义的 DSL,缺乏有表达性的扩展机制
- 其他插件的功能不容易使用或扩展
而使用对象插件的方式,可以给你最大的灵活性去封装高复杂度的逻辑,并且提供一种强大的扩展机制可以在构建脚本中定制它的行为。比如编译 Java 代码,我们会通过一句话来引入 Java 插件:
apply plugin :'java' |
然后我们还可以配置很多属性来控制编译逻辑。这个 Java 插件就是一个对象插件。
对象插件的实现方式
对于实现一个对象插件,有 4 个基本元素是非常重要的。
- 在放置插件实现的位置方面 Gradle 给你完全的灵活性。代码可以放在构建脚本中或者 buildSrc 目录下,也可以作为一个独立的工程被开发并且以 jar 文件方式发布。
- 每个插件都需要提供一个实现类,它代表着插件的入口点。插件可以用任何 JVM 语言编写并编译成字节码。
- 应用到项目中的插件可以通过暴露出来的扩展对象进行定制。如果用户想要在构建脚本中覆盖插件的默认配置时,这一点特别有用。
- 插件描述符是一个属性文件,它包含了关于插件的元信息。通常,它包含有插件的简短名字和插件实现类的映射。
编写插件
编写一个插件最低的要求是提供org.gradle.api.Plugin<T>
接口的一个实现类。该接口仅仅定义了一个简单的方法:apply(T target)
。
现在我们来演示自定义一个插件,这个插件的作用是提供一个 task 来打印用户凭证。
我们前面已经提到,自定义对象插件和自定义 task 方式类似,代码可以放在构建脚本中或者 buildSrc 目录下,也可以作为一个独立的工程被开发并且以 JAR 文件方式发布,下面我们根据这三种方式来分别演示如何自定义和使用插件。
放在构建脚本中
在 build.gradle 中,代码如下:
apply plugin:CredentialPlugin |
Gradle 将语言结构化模型作为扩展,扩展可以被添加到许多 Gradle 对象中,如果一个类实现了 org.gradle.api.plugins.ExtensionAware 接口,比如 Project 或者 Task,就认为它是扩展可知的。每个扩展都是一个数据模型,它是扩展的基础。这个模型可以是一个 POJO 或者 Groovy Bean。
在上面的代码中,userCredential 闭包中的内容,可以从构建脚本中给 task 提供所需要的属性值,这个 userCredential 就是我们暴露的一个 DSL。
ExtensionAware 对象有一个方法 getExtensions(),该方法返回一个 ExtensionContainer 对象,ExtensionContainer 对象可以通过 create() 方法来注册我们的扩展,也就是把我们配置的 DSL 和具体的类关联起来。在本例中就是把 userCredential 这个闭包和 CredentialExtension 这个类关联起来,这就是插件的扩展机制。
扩展对象 vs 额外属性 被用来扩展一个对象的 DSL 的扩展是扩展可知的,一个已注册的扩展模型会暴露一些属性和方法,用来给构建脚本建立新的构建语言结构,这些属性名和方法在创建的时候已经定好。扩展模型的典型用例是插件。额外属性,是一些通过 ext 命名空间创建的简单变量,它们一般提供给用户空间也就是构建脚本使用,额外属性的属性名是可以任意指定的。请尽量避免在插件实现中使用额外属性。
放在 buildSrc 目录下
与自定义 task 一样,Groovy 代码放在buildSrc/src/main/groovy
目录下,
package com.sososeen.credential |
在与 buildSrc 同级的目录下,创建 build.gradle 脚本,引入这个 plugin:
apply plugin:com.sososeen.credential.CredentialPlugin |
然后执行 gradle printUserCredential 命令,可以看到打印结果:
:printUserCredential |
可以看到,我们引入这个插件的时候是把它的包名带类名写上了,这显得太长了,不好写。我们可以给这个插件一个有意义且精简的名字。在 src/main/resources/META-INF/gradle-plugins 目录下,我们可以创建一个属性文件来配置。比如创建一个 credentials.properties,它就是一个插件描述符,暴露了插件名字是 credentials。在这个文件中,将该插件类的全局类名赋值给键 implemention-class,如下:
implementation-class = com.sososeen.credential.CredentialPlugin |
然后应用插件就可以这样子:
apply plugin : 'credentials' |
执行 gradle printUserCredential 命令,可以看到打印结果与之前一样。
以 jar 文件形式提供插件
这个步骤与自定义 task 打包为 jar 文件一样,新建一个项目,把 buildSrc 目录下的文件复制过来,同时,在该项目下创建一个 build.gradle 文件。
apply plugin: 'groovy' //应用这个插件来编译Groovy代码 |
执行 gradle uploadArchives 命令后就可以看到,在与当前项目同级的 lib 文件目录中生成了我们期望的 jar 文件。
我们再新建一个工程,这个工程中有一个脚本文件 build.gradle:
apply plugin : 'credentials' |
执行 gradle printUserCredential 命令,可以看到打印结果与之前一样。
REF
https://www.jianshu.com/p/158851436e82
本文链接:http://agehua.github.io/2021/07/18/gradle-plugin/