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

前言

Gradle插件在Android中的应用很广泛,很多字节码插桩方案就用到了这方面的知识,Android官方提供了很多可用的插件,比如apply plugin: 'com.android.application':它表示生成一个apk应用的插件;apply plugin: 'com.android.library':它表示生成AAR包。

本文只是为入门Gradle插件提供一些思路与实践方案,不深入解析Gradle工作原理和Task相关的内容。

Gradle插件官方文档地址:
https://docs.gradle.org/current/userguide/custom_plugins.html

Gradle Plugins简介

Gradle插件打包了可重用的构建逻辑,可以在不同的项目中使用。Gradle提供了几种方式来让你实现自定义插件,这样你可以重用你的构建逻辑,甚至提供给他人使用。

可以使用多种语言来实现Gradle插件,其实只要最终被编译为JVM字节码的都可以,常用的有GroovyJavaKotlin。通常,使用Java或Kotlin(静态类型)实现的插件比使用Groovy实施的插件性能更好。

打包插件的3种方式

  • Build script:在build.gradle构建脚本中直接使用,只能在本文件内使用;
  • buildSrc project:新建一个名为buildSrc的Module使用,只能在本项目中使用;
  • Standalone project:在独立的Module中使用,可以发布到本地或者远程仓库供其他项目使用。

Build script

直接在构建脚本中编写插件代码,并应用插件。比如说在appbuild.gradle中加入如下代码:

Android 自定义Gradle插件的3种方式_第1张图片
Build script.png

按照官方文档的做法,build.gradle内引入上面的代码,会发现PluginProject2个类是无法被引入的。而且这种方案有个弊端,只能在构建脚本文件内部使用,这样就没办法提供给其他module或者project使用了。这种方案基本不会在真实项目中使用

注意:对于Gradle而言,每一个Module都是一个项目。先知道这个概念,后面会解释。


buildSrc项目

1、创建好项目之后,新建一个名称为buildSrc的Module,项目类型任意,只保留build.gradle文件和src/main目录,其余文件全部删掉。注意:名字一定要是buildSrc,否则应用插件的时候会找不到插件。修改后的目录如下:

Android 自定义Gradle插件的3种方式_第2张图片
buildSrc.png

踩过的坑:创建buildSrc这个Module的时候,如果选择了Android Library类型会有Plugin with id 'com.android.library' not found.的异常,这是因为buildSrc是Android的保留名称,只能作为plugin插件使用,后面修改buildSrc的build.gradle文件后就不报错了。如果选择Java Library类型,好像就没有这个异常,而且这个类型的文件少一些,为了方便,建议大家选择Java Library类型。

2、修改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() //必须
}

注意:如果引入了com.android.tools.build:gradle:3.3.0,需要加入google()仓库,我试过只引入 jcenter()mavenCentral()仓库中,会提示找不到。

3、在main下新建groovy目录,在groovy目录下创建包名目录,在包名目录下新建一个groovy文件,并且实现org.gradle.api.Plugin接口,注意文件名需要以.groovy结尾。

4、在main下新建resources目录,在resources目录下新建META-INF目录,再在META-INF下新建gradle-plugins目录,在gradle-plugins目录下新建properties文件,比如com.zx.plugin.properties,注意:这个文件命名是没有要求的,但是要以.properties结尾。

buildSrc项目目录如下:

Android 自定义Gradle插件的3种方式_第3张图片
项目结构

CusPlugin.groovy源码如下:
注意:这里是groovy语言写的,当然也可以用java、kotlin写,他们都是基于JVM的。PluginProject是Gradle的API,所以需要先在脚本文件中配置好了再写插件实现类,否则是找不到这2个类的。

package com.zx.plugin

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


class CusPlugin implements Plugin {

    @Override
    void apply(Project project) {
        println("this is CusPlugin")
    }
}

这里没有去定义一系列Task任务,只是简单的打印Log。在实际应用中,会定义一些任务去执行,这个后面的文章会讲。

META-INF/gradle-plugins/com.zx.plugin.properties文件的内容如下:

implementation-class=com.zx.plugin.CusPlugin

它的作用是:申明Gradle插件的具体实现类

5、在要使用插件的Module中应用,比如在appbuild.gradle中,引用插件如下:

apply plugin: 'com.android.application'
//引用自定义插件
apply plugin: 'com.zx.plugin'

注意这里引用的插件名称就是properties文件的名称。接下来如果编译正常的话,就会看见插件实现类的apply()方法中打印的日志。

Android 自定义Gradle插件的3种方式_第4张图片
运行结果

小结:

  • module名称只能为buildSrc
  • buildSrc project下的插件是自动加载。

独立的项目使用

这种方案的Module名称可以自定义,可以发布到本地或者远程仓库(jcenter、maven等)中,这样就可以供其他项目使用。

1、新建一个Module,项目类型任意,名字任意,也是只保留build.gradle文件和src/main目录,其余文件全部删掉。

2、修改Gradle文件内容:

apply plugin: 'groovy'  //必须
apply plugin: 'maven'  //要想发布到Maven,此插件必须使用


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


def group='com.zx.cus_plugin' //组
def version='1.0.0' //版本
def artifactId='myGradlePlugin' //唯一标示


//将插件打包上传到本地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,它表示的是项目根目录下,这里用了2个.,1个.表示当前module根目录,2个.表示project的根目录。

3、src/main目录下的插件实现类和properties文件与buildSrc方案是一致的。

4、在终端中执行gradle uploadArchives指令,或者展开AS右侧的Gradle,找到对应moduleuploadArchivesTask,就可以将插件部署到项目根目录的repos目录下。

Android 自定义Gradle插件的3种方式_第5张图片
uploadArchives

插件部署到本地后的目录如下:
这个repos就是你本地的Maven仓库,com/zx/cus_plugin是脚本中的group指定的,myGradlePlugin表示模块名称,是一个唯一标示,1.0.0version指定

Android 自定义Gradle插件的3种方式_第6张图片
repos目录

5、引用插件
buildSrc中,系统自动帮开发者自定义的插件提供了引用支持,但完全自定义Module的插件中,开发者就需要自己来添加自定义插件的引用支持。

在project的build.gradle文件中,添加如下脚本:

buildscript {
    repositories {
        google()
        jcenter()
        maven {
            url uri('./repos') //指定本地maven的路径,在项目根目录下
        }
    }
    dependencies {
        //classpath 'com.android.tools.build:gradle:3.3.0'
        classpath 'com.zx.cus_plugin:myGradlePlugin:1.0.0'
    }
}

注意:

  • 这里的uri只用了1个.,因为project的build.gradle文件已经在项目根目录下了

  • classpath指定的路径格式如下:
    这3个参数是在build.gradle脚本文件中申明的

classpath '[groupId]:[artifactId]:[version]' 

配置完毕后,在需要使用的Module引用插件,例如:

apply plugin: 'com.android.application'
//引用buildSrc插件,properties文件名称的方式
//apply plugin: 'com.zx.plugin'
//引用完全自定义插件,properties文件名称的方式
apply plugin: 'com.zx.cus_plugin'

小结:

  • 方案3用完全自定义Module实现自定义插件,这里是打包上传插件到本地Maven,当然你也可以发布到远程仓库,参考:gradle插件上传Jcenter与自建Maven私服

  • 上传本地Maven需要注意脚本文件中uploadArchives配置,以及引用插件时地址的配置(我在这里踩过坑),一般放在project根目录下就可以

  • 如果重新修改了插件 代码,需要重新部署uploadArchives才能在别的地方引用插件

总结

虽然官方提供了3种方案,但实际开发中只会用到后2种,有一个比较方便的做法,开发调试的时候用buildSrc project模式,等后面需要把插件共享出去等时候,再把它改为第三种方案即可。

你可能感兴趣的:(Android 自定义Gradle插件的3种方式)