老砒霜写插件(1)----Gradle插件基础以及一个简单的打印插件

1,479 阅读4分钟

Gradle干嘛的

Gradle是一款自动化开源构建工具,目前android开发者好像没有谁离开它(当然,有那种大神自己通过命令行编译的,不在范围内)。什么是构建工具,对于android开发者简单来说就是将你的代码和资源等等构建出相应的apk或者aar。下面这张图是android的打包流程图

可以发现是身份复杂的,包括java代码的编译,dex文件的生成,apk签名等等一系列工具过程,如果每一个节点都由开发者自己去做,那无疑对生产效率是大打折扣,而gradle通过自身提供的api可以让这一系列流程结合起来,只需要相应的输入,就给你想要的输出。

构建要素

一个Gradle构建通常包含三个基本构建块:project,task和property。每个构建至少包含一个project,一个project可以包含一个或者多个task,project和task可以暴露属性来控制构建。

project

project在android项目中往往对应一个module,每个project至少包含一个build.gradle。而project中又可以注册多个task。

task

task可以理解为具体的行为动作,无论是打印还是编译java代码,都可以在task中定义和执行,task就是具体的干活人,上面android打包流程图中,几乎每个节点就是一个task,gradle通过构建有向无环图,来顺序执行图中相应的task。

property

project和task都提供了可以通过getter和setter方法访问的属性,外部使用者可以通过属性向构建过程中传递相应的参数,以此来改变构建的不同流程或者结果。

Gradle插件

说了这么半天,那么什么是Gradle插件呢?Gradle插件打包了可重用的构建逻辑,可在许多不同的项目和构建中使用。一般来看,一个Gradle插件往往会包含多个task(当然也可以不包括),我们在项目中看到的

apply plugin: 'com.android.application'

这其实就是我们应用了一个pluginId为com.android.application的插件,我们在编译android项目过程中用到的很多task其实都是在这个plugin中定义的。

如何自定义Gradle插件

目前定义Gradle插件的方式有三种:gradle脚本、 buildSrc项目、Standalone项目,其中gradle脚本和创建buildSrc module的项目不能通过依赖引入,只能拷贝到相应的工程使用,比较麻烦,Standalone项目可以发布项目到maven,然后通过gradle的classpath引入,但是不好调试,这里我们使用buildSrc module编写插件,然后发布生成的jar包到maven,之后其他项目就可以通过gradle引入了。

编写老砒霜Gradle差价

1.新建一个项目,创建buildSrc module

这里注意的是如果创建啊玩builddSrc后编译报错提示:

'buildSrc' cannot be used as a project name as it is a reserved name,那么就把settings.gradle中的include:‘buildSrc'移除掉,因为在Gradle6.3以后buildSrc现在被保留作为一个工程或者子工程的名字。以前Gradle没有阻止使用buildSrc作为一个在 多工程构建或者作为一个被包括在构建列表名称的 子工程的名字。现在,这样已经不允许了。现在buildSrc这个名字被保留给传统的构建额外逻辑的buildSrc工程。这次改变没有影响典型的buildSrc的用法,仅仅影响在setting.gradle文件中使用include(“buildSrc”) or includeBuild(“buildSrc”)方式构建。

2.修改buildSrc中的gradle文件

 buildscript {
    ext.kotlin_version = "1.4.20"
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
apply plugin: 'java-library'
apply plugin: 'kotlin'

java {
    sourceCompatibility = JavaVersion.VERSION_1_7
    targetCompatibility = JavaVersion.VERSION_1_7
}

repositories {
    jcenter()
    google()
}

dependencies {
    implementation gradleApi()
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

buildSrc module会独立于目前的根项目,所以它的配置不会走最外层的settings.gradle配置,所以需要在这个gradle文件中指定相应的buildSrcipt,也就是编译环境,这里的classpath其实就是对插件的引用。

3.定义plugin

class LaoPiShuangPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.tasks.register("HelloProject", PrintProjectNameTask::class.java)
    }
}

open class PrintProjectNameTask : DefaultTask() {

    override fun getGroup(): String? = "laopishuang"

    @TaskAction
    fun execute() {
        project.rootProject.subprojects.forEach {
            println("hello ${it.name}")
        }
    }
}

这里我们定义一个名为LaoPiShuangPlugin的plugin,这里我们通过

project.tasks.register("HelloProject", PrintProjectNameTask::class.java)

注册了一个task,task的名称为HelloProject,PrintProjectNameTask执行会打印当前project根project的所有project的名字

4.定义plugin id

按照图示路径添加一个名为laopishuang.properties的文件,其中laopishuang就是plugin id的名称。laopishuang.properties的内容为

implementation-class=com.skateboard.laopishuang.LaoPiShuangPlugin

填入刚才LaoPiShuangPlugin的全类名。

5.使用

在app modul的build.gradle中调用

apply plugin:'laopishuang'

在命令行执行./gradlew HelloProject,就会打印出相应的project name

其中HelloProject就是刚才在plugin中注册的task的名称,或者你可以在gradle面板中在laopishuang下找到该task,双击执行,laopishuang对应刚才定义的PrintProjectNameTask的复写的getGroup()返回的值

结语

之后会围绕android相关的插件编写一个系列,不限于Gradle插件,这期的例子较为简单,下期写一个复杂一些的Gradle插件

欢迎关注我的公众号:"滑板上的老砒霜"