美文网首页Manba陪你学AndroidgradleAndroid进阶之路
Android 自定义Gradle插件的3种方式

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

作者: 唠嗑008 | 来源:发表于2019-12-10 17:06 被阅读0次

    前言

    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中加入如下代码:

    Build script.png

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

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


    buildSrc项目

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

    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项目目录如下:

    项目结构

    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<Project> {
    
        @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()方法中打印的日志。

    运行结果

    小结:

    • 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目录下。

    uploadArchives

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

    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种方式

        本文链接:https://www.haomeiwen.com/subject/rapwgctx.html