概述

又开始了一个新的系列,这个系列学习Gradle,目标就是彻底理解Gradle,主要还是做下自己理解的笔记,防止忘记

Gradle系列(一):Groovy学习

Gradle学习系列(二):Gradle核心解密

Gradle学习系列(三):Gradle插件

简介

Gradle本身只是提供了基本的核心功能,其他的特性比如编译Java源码的能力,编译Android工程的能力等等就需要通过插件来实现了。
要想应用插件,需要把插件应用到项目中,应用插件通过 Project.apply()方法来完成。
在Gradle中一般有两种类型的插件,分别叫做脚本插件对象插件

脚本插件是额外的构建脚本,它会进一步配置构建,可以把它理解为一个普通的build.gradle。

对象插件又叫做二进制插件,是实现了Plugin接口的类,下面分别介绍如何使用它们。

脚本插件

比如我们在项目的根目录创建一个utils.gradle

def getxmlpackage(boolean x){
    def file=new File(project.getProjectDir().getPath()+"/src/main/AndroidManifest.xml");
    def paser = new XmlParser().parse(file)
    return paser.@package
}

ext{
    getpackage = this.&getxmlpackage
}

这就是一个简单的脚本插件,然后在app moudle引用这个脚本插件

apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"

然后就可以调用脚本插件中的方法了

对象插件

对象插件就是实现了org.gradle.api.plugins接口的插件,对象插件可以分为内部插件和第三方插件。

内部插件

Gradle包中有大量的插件,比如我们经常用的java插件和c的插件,我们可以直接引入

apply plugin:'java'
apply plugin:'cpp'

三方插件

第三方的对象插件通常是jar文件,要想让构建脚本知道第三方插件的存在,需要使用buildscrip来设置。
在buildscrip中来定义插件所在的原始仓库和插件的依赖 ,再通过apply方法配置就可以了。Android Gradle插件也属于第三方插件,如果我们想引入Android Gradle插件,可以这么写:

buildscript {
    repositories {
    	//配置仓库
        google()
        jcenter()
    }
    dependencies {
    	//配置插件依赖
        classpath 'com.android.tools.build:gradle:3.5.3'
    }
}
//然后就可以在需要的地方引入android 插件了
apply plugin: 'com.android.application'

自定义对象插件

自定义一个插件主要是实现 org.gradle.api.Plugin

Build script

这种方式直接在构建脚本中写插件代码,但是这种方式只能在本文件中使用,比如我在app的build.gradle中直接加入如下代码

class myPlugin implements Plugin<Project>{
    @Override
    void apply(Project project) {
        println("myPlugin 执行了")

        project.task("myTask"){
            doLast {
                println("myTask执行了")
            }
        }
    }
}

然后引入在本文件定义的插件

apply plugin: myPlugin

这个就是直接在build.gradle 中实现了一个插件,在插件中定义了一个MyTask任务,但是这个插件只能在本文件中使用,我们直接执行Mytask任务./gradlew MyTask

> Task :mylibrary2:myTask
myTask执行了
执行阶段,task ':mylibrary2:myTask'耗时:1ms

这种方式实现的插件我们一般不使用,因为这种方式局限性太强,只能本Project,而其他的Project不能使用

buildSrc项目

buildSrc是Gradle默认的插件目录,编译Gradle的时候会自动识别这个目录,将其中的代码编译为插件,

  • 首先先建立一个名为buildSrc的java Module,然后只保留build.gradlesrc/main目录,其他全部删掉,注意名字一定是buildSrc,不然会找不到插件
  • 然后修改Gradle中的内容
apply plugin: 'groovy'  //必须
apply plugin: 'maven'

dependencies {
    implementation gradleApi() //必须
    implementation localGroovy() //必须
    //如果要使用android的API,需要引用这个,实现Transform的时候会用到
    //implementation 'com.android.tools.build:gradle:3.3.0'
}

repositories {
    google()
    jcenter()
    mavenCentral() //必须
}

//把项目入口设置为src/main/groovy
sourceSets {
    main {
        groovy {
            srcDir 'src/main/groovy'
        }
    }
}
  • 创建入口目录,在src/main下创建代码入口目录,如下:
  • android gradle和gradle的区别 gradle和gradle插件_gradle

  • 然后实现插件代码Text.groovy,注意文件后缀为groovy,文件要引入package com.renxh
package com.renxh

import org.gradle.api.Plugin
import org.gradle.api.Project

class Text implements Plugin<Project>{
    @Override
    void apply(Project project) {
        println("执行自定义插件")
        project.task("haha"){
            doLast{
                println("执行自定义插件 haha task")
            }
        }
    }
}
  • 接下来在main目录下创建resources目录,在resources目录下创建META-INF目录,在META-INF目录下创建gradle-plugins目录,在gradle-plugins目录下创建properties文件
  • properties文件可以自己命名,但是要以.properties结尾,比如com.renxh.plugin.properties
  • android gradle和gradle的区别 gradle和gradle插件_Gradle_02


  • 最后需要在properties文件中指明我们实现插件的类implementation-class=com.renxh.Text
  • android gradle和gradle的区别 gradle和gradle插件_maven_03


到目前为止我们的插件项目已经写完了,在module引入我们写的插件apply plugin:'com.renxh.plugin',然后执行插件的Task,./gradlew haha

输出

> Task :mylibrary:haha
执行自定义插件 haha task
执行阶段,task ':mylibrary:haha'耗时:0ms

这种形式的写法,在我们整个工程的module都可以使用,但也只是限制在本工程,其他工程不能使用

自定义module,上传maven

第二种写插件的方式他只能在本工程中使用,而其他的项目工程不能使用,有时候我们需要一个插件在多个工程中使用,这时候我们就需要把插件上传maven中

  • 首先先建立一个java module,名字可以任意起,只保留build.gradlesrc/main,其他文件都删除
  • 修改Gradle中内容
apply plugin: 'groovy'  //必须
apply plugin: 'maven'  //要想发布到Maven,此插件必须使用


dependencies {
    implementation gradleApi() //必须
    implementation localGroovy() //必须
}
repositories {
    mavenCentral() //必须
}


def group='com.renxh.cusplugin' //组
def version='2.0.0' //版本
def artifactId='myplugin' //唯一标示


//将插件打包上传到本地maven仓库
uploadArchives {
    repositories {
        mavenDeployer {
            pom.groupId = group
            pom.artifactId = artifactId
            pom.version = version
            //指定本地maven的路径,在项目根目录下
            repository(url: uri('../repos'))
        }
    }
}

相比buildSrc方案,这个增加了Maven支持和uploadArchives这样的Task,这个Task作用就是把本地插件打包上传到本地的maven仓库,这里../repos表示项目根目录项下的repos,俩个.回退俩次,回退到项目的根目录

src/main生成groovy文件和生成properties文件的步骤和buildSrc方案一致的

编写插件

class CustomPlugin implements Plugin<Project>{

    @Override
    void apply(Project project) {
        project.task("cusplugin"){
            doLast{
                println("cusplugin任务执行111")
            }
        }
    }
}

然后执行./gradlew CusPlugin:uploadArchivesuploadArchives任务,然后就可以把repos目录布置到项目根目录了,如图:

android gradle和gradle的区别 gradle和gradle插件_maven_04

repos目录就是本地的Maven仓库,com/renxh/cusplugin就是脚本中指定的groupmyplugin也是脚本中指定的模块名字,是一个唯一标识,1.0.0就是脚本中version

  • 生成本地的maven仓库之后,就需要引用本地maven仓库中的插件了,首先需要在根目录的build.gralde中加入如下:
buildscript {
    repositories {
        google()
        jcenter()
        //引入本地仓库
        maven {
            url uri('./repos') //指定本地maven的路径,在项目根目录下
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.3'
        //引入本地仓库中的插件依赖
        classpath 'com.renxh.cusplugin:myplugin:1.0.0'

        
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }


}
  • classpath指定的路径格式,如下:

这三个参数都是在生成仓库的时候在build.gradle脚本中配置的

classpath '[groupId]:[artifactId]:[version]'
  • 配置完之后就可以在module中使用了
apply plugin: 'com.android.application'
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
apply plugin:'com.renxh.cusplugin'
  • 最后就可以执行插件中的任务 ./gradlew app:cusplugin
> Task :app:cusplugin
cusplugin任务执行111
执行阶段,task ':app:cusplugin'耗时:0ms

插件的扩展 Extension

我们也可以在插件运行的时候,给插件配置参数,插件的Extension就是用来把参数回传到插件中的

下面我就就给上面的插件添加Extension

首先建一个实体类,来接收参数

package com.renxh.cusplugin
class MyExtension {
    String name;
    int age;
}

然后去插件类中添加扩展

class CustomPlugin implements Plugin<Project>{

    @Override
    void apply(Project project) {
		//添加扩展
        project.extensions.add('myextension',MyExtension)

        project.task("cusplugin"){
            doLast{
                println("cusplugin任务执行111")

                MyExtension extension = project.myextension
                //3.输出插件扩展属性
                println ">>>>>> name: ${extension.name} age:${extension.age}"
            }
        }
    }
}
  • 通过project.extensions.add将自定以的实体类添加到扩展中,并起个名字
  • 然后通过起的名字拿到扩展的实体类
  • 最后拿到扩展中的属性

修改完之后重新上传maven

上传完之后,就可以在module中使用扩展实体类了

apply plugin: 'com.android.application'
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
apply plugin:'com.renxh.cusplugin'

myextension{
    name 'renxh'
    age 27
}

最后执行插件中的task,./gradlew app:cusplugin

> Task :app:cusplugin
cusplugin任务执行111
>>>>>> name: renxh age:27
执行阶段,task ':app:cusplugin'耗时:2ms

参考

Android 自定义Gradle插件的3种方式

Gradle之自定义插件