自定义gradle插件

 

1.Gradle插件
Gradle可以认为是一个框架,负责定义流程和规则。而具体的编译工作则是通过插件的方式来完成的。比如编译 Java 有 Java 插件,编译 Groovy 有 Groovy 插件,编译 Android APP 有 Android APP 插件,编译 Android Library 有 Android Library 插件。在Gradle中一般有两种类型的插件,脚本插件二进制插件。使用插件方式可以使得同一逻辑在项目中复用,也可以针对不同项目做个性化配置,只要插件代码支持即可。

1.1二进制插件

二进制插件就是实现了org.gradle.api.Plugin接口的插件,它们可以有plugin id,二进制插件一般都是被打包在一个jar里独立发布的,比如我们自定义的插件,在发布的时候我们也可以为其制定plugin id,这个plugin id最好是一个全限定名称,就像你的包名一样,这样发布的插件plugin id就不会重复了。

1.2脚本插件
build.gradle文件

apply from: 'version.gradle'
task ex << {
    println "app版本:" + versionName + ",版本号是:" + versionCode
}

 version.gradle文件

ext {
    versionName = '1.1'
    versionCode = 1
}

 其实这不能算一个插件,它只是一个脚本。应用脚本插件其实就是把这个脚本加载进来,和二进制插件不同的是它使用的是from关键字,后面紧跟的是一个脚本文件,可以是本地的,也可以是网络的,如果是网络上的话要使用HTTP URL。

虽然它不是一个真正的插件,但是不能忽略它的作用,它是脚本文件模块化的基础,我们可以把庞大的脚本文件,进行分块、分段整理,拆分成一个个共用、职责分明的文件,然后使用apply from来引用它们,比如我们可以把常用的函数放在一个utils.gradle脚本里,供其他脚本文件引用。
2.gradle自定义插件

Gradle插件是使用Groovy进行开发的,而Groovy其实是可以兼容Java的。Android Studio其实除了开发Android App外,完全可以胜任开发Gradle插件这一工作,下面来讲讲具体如何开发。

1.首先,新建一个Android项目,新建一个Android Module项目,类型选择Android Library。

2.将新建的Module中除了build.gradle文件外的其余文件全都删除,然后删除build.gradle文件中的所有内容。

打开Module下的build.gradle文件,输入

apply plugin: 'groovy'
apply plugin: 'maven'

dependencies {
    compile gradleApi()
    compile localGroovy()
}

repositories {
    mavenCentral()
}

3.在新建的module中新建文件夹,src/main/groovy目录,这时候groovy文件夹会被Android识别为groovy源码目录。除了在main目录下新建groovy目录外,你还要在main目录下新建resources目录,同理resources目录会被自动识别为资源文件夹。在groovy目录下新建项目包名,就像Java包名那样。resources目录下新建文件夹META-INF,META-INF文件夹下新建gradle-plugins文件夹。META-INF和gradle-plugins必须是父子目录。这样,就完成了gradle 插件的项目的整体搭建。目前,项目的结构是这样的。

 1.png

下面我们在包名下新建一个文件,命名为CustomPlugin.groovy

package com.pl.plugin

import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.TaskAction

class CustomPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        project.tasks.create('writeFile', CustomPluinTask) {
            def greeting = project.extensions.create('greeting', ParamsExtension);//使用类型向插件传递参数
            
            destination {
                project.greetingFile
            }
            doFirst {
                String args = project.args;//通过ext直接传递参数
                message = args + " " + greeting.message
                println "doFirst greeting.message:" + greeting.message
            }
            doLast {
                println(project.file(destination).text)
            }
        }
    }
}

class ParamsExtension {
    String message = "pl init"
}


class CustomPluinTask extends DefaultTask {
    def destination
    String message = "pl test"

    File getDestination() {
        //创建路径为destination的file
        project.file(destination);
    }

    @TaskAction
    def greet() {
        def file = getDestination();
        file.parentFile.mkdirs();
        //向文件中写文本
        file.write(message);
    }
}

 然后在resources/META-INF/gradle-plugins目录下新建一个properties文件,注意该文件的命名就是你只有使用插件的名字,这里命名为gradlePlugin.properties,在里面输入

implementation-class=com.pl.plugin.CustomPlugin

 注意:包名需要替换为你自己的包名,这样就完成gradle插件的开发工作,下面简单讲解一下,插件所做的整改,插件里面定义了一个名为writeFile的task,task将指定的message信息写入到,由destination指定路径的文件中。

3.发布到本地仓库中

接着,我们需要将插件发布到本地仓库就好了,在module项目下的buidl.gradle文件中加入发布的代码。

uploadArchives {
    repositories {
        mavenDeployer {
            //设置插件的GAV参数
            pom.groupId = 'com.pl.plugin'
            pom.artifactId = 'gradlePlugin'
            pom.version = '1.0.0'
            //文件发布到下面目录
            repository(url: uri('../repo'))
        }
    }
}

 上面的group和version的定义会被使用,作为maven库的坐标的一部分,group会被作为坐标的groupId,version会被作为坐标的version,而坐标的artifactId被用作插件的模块名称。后面定位引用插件时,将会用到上面设置的值。然后maven本地仓库的目录就是当前项目目录下的repo目录。 

 2.png

 点击uploadArchives这个Task,就会在项目下多出一个repo目录,里面存着这个gradle插件。

3.png

发布到本地maven仓库后,我们就使用它,接下来我们在项目根目录的build.gradle文件中加入如下代码

apply plugin: 'gradlePlugin'

ext.args = "hello"
greeting {
    message = 'test success'
}
ext.greetingFile = "$buildDir/hello.txt"

buildscript {

    repositories {
        maven {
            url = uri("$rootDir/repo")
        }
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.0'
        classpath 'com.pl.plugin:gradlePlugin:1.0.0'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

 注意:apply plugin后面引号内的名字就是前文gradlePlugin.properties文件的文件名,而class path后面引号里的内容,就是上面grade中定义的group,version以及moduleName所共同决定的,和maven是一样的。

4.png