Gradle 实现自定义插件

释放双眼,带上耳机,听听看~!

一、以库项目形式创建插件

1.创建项目

如果仅仅是自己项目中来自定义插件,不对外发布,那么可以按照以下的语法来构建目录

1.1  创建一个Module,选择Java Library项目,项目名称必须是 buildSrc,否则插件不被识别

1.2 构建目录 buildSrc/src/main/groovy 本路径android studio会自动识别为 groovy类,否则可能出现实现类无法找到的问题。
1.3、在main目录中再构建 resources/META-INF/gradle-plugins,这个目录是groovy项目的资源文件目录。

 

注意,插件的代码可以是java实现,编程方式比较繁琐,这里我们使用groovy语言。

1.4 配置项目插件依赖

buildSrc 中的 build.gradle的定义,引入groovy插件,并依赖 gradleApi()、localGroovy()。

apply plugin:'groovy'  #必须

group='com.ncf.plg'
version='3.0.0'

dependencies { 
    implementation gradleApi() #必须
    implementation localGroovy() #必须
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.tools.build:gradle:2.2.2' //如果要实现Transform,需要引用该类

}
repositories {
    mavenCentral() #必须
}


sourceCompatibility = "1.7"
targetCompatibility = "1.7"

2、代码实现
新建groovy文件 CustomPluginTest.groovy,代码如下

package com.ncf.plg

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


class  CustomPluginTest  implements  Plugin<Project>{

    @Override
    void apply(Project project) {
        //增加闭包名称,闭包为customPlugin,是 CustomPluginTestExtension类型,因此CustomPluginTestExtension类型中的JaveBean类型的属性可以任意设置
        project.extensions.add("personInfo",PersonInfo)  //personInfo用于build.gradle中添加配置块
        project.task("showPersonInfo") << {
            if(project.personInfo==null) return ;
            println("姓名:" + project.personInfo.name)
            println("年龄:" + project.personInfo.age)
            println("地址:" + project.personInfo.address)
        }
        project.extensions.add("bookInfo",BookInfo);
        project.task("showBookInfo",dependsOn:"showPersonInfo" ) << {  
         //注意,showBookInfo依赖showPersonInfo,dependsOn:"showPersonInfo"
            def book =  project.extensions.findByType(BookInfo);
            println("喜欢的书籍:" + book.name + ", " + book.id + ", " + book.price+'元'+','+book.address+","+book.isbn);
        }

    }
}

PersonInfo类

package com.ncf.plg

class PersonInfo {
    def name = "init";
    def age = "init";
    def address = "init";
}

BookInfo类

package  com.ncf.plg

class BookInfo {
    def name = "《红楼们》";
    def isbn = "SW.SH.CN.I.20181227";
    def address = "北京市海淀区西北旺";
    def price = 25.9f
    def id = 'BS1001029'
}

配置MyCustomPlugin.properties

implementation-class=com.ncf.plg.CustomPluginTest

 

3、使用插件

在app项目的build.gradle中,我们引用插件

import com.ncf.plg.PersonInfo 


apply plugin: 'MyCustomPlugin'  //properties的名称
personInfo{
    name='张三'
    age=25
    address='北京市海淀区朝阳路'
}

4、调用任务

执行如下命令

gradle showBookInfo 【如果是windows系统,调用gradlew showBookInfo】

执行结果如下

> Configure project :app


> Task :app:showPersonInfo
姓名:张三
年龄:25
地址:北京市海淀区朝阳路

> Task :app:showBookInfo
喜欢的书籍:《红楼们》, BS1001029, 25.9元,北京市海淀区西北旺,SW.SH.CN.I.20181227

二、发布到本地Maven仓库

对于一些插件,希望通过共享的方式让所有人都能使用,我们需要做的是上传插件,由于buildSrc目录下的插件是自动加载,为了展示效果,我们将buildSrc更名成其他项目名,比如MyGradlePlugin

同时,修改setting.gradle中的:buildSrc为:MyGradlePlugin

://blog.csdn.net/eclipsexys/article/details/50973205

1.在build.gradle中添加uploadArchives 块

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

def group='com.ncf.plg'
def version='3.0.0'
def artfactid='myGradlePlugin'

dependencies { 
    implementation gradleApi() #必须
    implementation localGroovy() #必须
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}
repositories {
    mavenCentral() #必须
}


sourceCompatibility = "1.7"
targetCompatibility = "1.7"


uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: uri('../public'))  //注意相对路径,在主项目目录下
        }
        pom.groupId=group
        pom.artifactId=artfactid
        pom.version=version
    }
}

这里增加了Maven的支持和uploadArchives这样一个Task,这个Task的作用就是将该Module部署到本地的repo目录下。

终端中执行gradle uploadArchives指令,将插件部署到repo目录下

当插件部署到本地后,就可以在主项目中引用插件了。当插件正式发布后,可以把插件像其它module一样发布到中央库,这样就可以像使用中央库的库项目一样来使用插件了。

2、修改MyCustomPlugin.properties为插件包名,我这里是com.ncf.plugin.properties,这个很重要,在项目中引用是通过该文件名的

apply plugin: 'com.ncf.plugin'

3、引用插件

在buildSrc中,系统自动帮开发者自定义的插件提供了引用支持,但自定义Module的插件中,开发者就需要自己来添加自定义插件的引用支持。在主项目的build.gradle文件中,添加如下所示的脚本:



buildscript {
    repositories {
//省略其他仓库
        maven {
         
            url uri('./public')  //注意相对路径,和app目录并列
        }
    }
    dependencies {
       //省略其他环境遍历
        classpath 'com.ncf.plg:MyGradlePlugin:3.0.0'
    }
}

其中,classpath指定的路径,就是类似compile引用的方式:

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

配置完毕后,就可以在app项目中使用自定义的插件了

在app的build.gradle引入

apply plugin: 'com.ncf.plugin'

personInfo{
    name='张三'
    age=25
    address='北京市海淀区朝阳路'
}

4、插件改进

引入插件之后,执行如下命令可以一遍更新插件,一边实时预览效果

gradle uploadArchives && gradle showPersonInfo 

执行后我们发现,发布后的插件不同于buildSrc项目,我们在下面的方法中获取不到我们配置的personInfo信息

project.task("showPersonInfo") << {
            if(project.personInfo==null) return ;
            println("姓名:" + project.personInfo.name)
            println("年龄:" + project.personInfo.age)
            println("地址:" + project.personInfo.address)
}

问题处在哪里呢?

我们要知道,gradle插件执行分为2个周期,第一个是config周期,另一个是task执行周期,在config周期中插件只能获取到默认配置信息,而上述代码块本身处于config周期,因此,获取不到gradle中配置的信息,如何解决这个问题呢?

这里我们使用doFirst/doLast即可

package com.ncf.plg

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


class  CustomPluginTest  implements  Plugin<Project>{

    @Override
    void apply(Project project) {
        //增加闭包名称,闭包为customPlugin,是 CustomPluginTestExtension类型,因此C 
        ustomPluginTestExtension类型中的JaveBean类型的属性可以任意设置
        project.extensions.add("personInfo",PersonInfo)  //personInfo用于build.gradle中添加配置块
        
        def showPersonTask = project.task("showPersonInfo")  {
            
             println '配置 showPersonInfo'
           
        }
       showPersonTask.doLast{
            println("姓名:" + project.personInfo.name)
            println("年龄:" + project.personInfo.age)
            println("地址:" + project.personInfo.address)
       }

        project.extensions.add("bookInfo",BookInfo);
        def showBookTask = project.task("showBookInfo",dependsOn:"showPersonInfo" ) {  
                println '配置 showBookInfo'
        }
      showBookTask.doFirst{
          //注意,showBookInfo依赖showPersonInfo,dependsOn:"showPersonInfo"
            def book =  project.extensions.findByType(BookInfo);
            println("喜欢的书籍:" + book.name + ", " + book.id + ", " + 
         book.price+'元'+','+book.address+","+book.isbn);
       }

    }
}

5、获取android的配置参数

对于插件开发,很多时候需要依赖其他插件,比如android插件开发,为了开发某些功能,我们需要不可避免的获取android gradle的配置参数和api,因此我们需要添加相应的依赖库到插件的build.gradle中

implementation 'com.android.tools.build:gradle:2.1.3'

插件类apply中,使用如下方式获取

def android = project.extensions.getByType(com.android.build.gradle.AppExtension)
android.applicationVariants.all{variant ->
            println '::::>>> '+variant.buildType.name
            println "applicationId: "+android.defaultConfig.applicationId
        }

 

三、发布到远程Maven仓库

发布到远程maven仓库相对来说比较复杂,需要我们自己申请账号等一系列操作,这里我们暂时不写,以后补充。如果存在此类需求,可参考如下链接:

https://blog.csdn.net/pf_1308108803/article/details/78119591

人已赞赏
Android文章

Android 实现自定义Html解析器

2019-10-26 10:29:02

Android文章

Android 自动化埋点方案

2019-10-26 15:31:41

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
有新消息 消息中心
搜索