Gradle自定义插件以及发布方法

前言

我们平常在进行Android开发时,都会使用 Gradle 来进行项目配置,通常在对应的module:app的build.gradle中,在最上面的一句话一般都为:

apply plugin: 'com.android.application'

这句话就是用来加载gradle的android开发插件,然后,我们就可以使用该插件提供的配置方法进行Android项目的配置了,即如下所示:

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
    defaultConfig {
        applicationId "com.yn.gradleplugintest"
        minSdkVersion 23
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

更多 android 插件配置详情,请查看:Android Plugin DSL Reference

简单来讲,Gradle插件允许我们做一些额外的扩展工作,比如我想在module每次build完成后,把生成的jar/aar移动到另一个项目的libs文件内,相当于动态更新库文件······
其实像上面这种操作用 Gradletask 就可以完成,但是使用 task 的一个弊端就是没办法做到复用,而使用 Gradle 你就能在任何项目,任何模块中使用同一套逻辑功能,甚至于你还能对不同的模块进行动态化的个性配置,只要插件代码支持即可。

更多 Gradle 使用方法,请查看官网:Gradle User Guide

自定义插件

上面我们说了自定义插件的诸多好处,那么,究竟该如何进行 Gradle 自定义插件的编写呢 ?
其实,自定义插件基于源码放置可以分为3种:

  • 第一种:Build script
    这种插件脚本的源码放置在模块内的 build.gradle 中,好处就是插件脚本会被自动编译并添加进模块的 classpath 中,我们完全不用做任何事情。但是,这种插件脚本只能在声明的这个 build.gradle 中使用,其他模块是没办法复用这个插件的。
//app build.gradle
apply plugin: BuildScriptPlugin

class BuildScriptPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('hello') {
            group = "test"
            description = "gradle build script demo,shares only in this build.gradle"
            doLast {
                println "Hello from the BuildScriptPlugin"
            }
        }
    }
}

如上面这个插件 GreetingPlugin,我们是在 appbuild.gradle 中声明定义的,然后,在控制台运行下: gradle app:tasks,或者直接看Android Studio的Gradle窗口,可以看到如下结果:

Build script

可以看到,只有我们声明编写的 app 中成功添加了一个 task:hello(根目录也会同时添加进这个插件功能),然后,你在工程其他 build.gradleapply plugin: GreetingPlugin 是无法成功的,因为这种插件对其他模块是不可见的。

所以,Build script 这种插件其实跟直接定义一个 task 没有多大区别。

  • 第二种:buildSrc project
    这种插件脚本要求源码放置在 rootProjectDir/buildSrc/src/main/groovy目录内(也就是工程根目录下创建 buildSrc 目录),然后 Gradle 就会自动编译和测试这个插件,同时,这种方法创建的插件对工程内的所有模块都是可以使用的。

buildSrc project

从上图可以看到,我们在模块 app 中成功加载了插件,所以,使用 buildSrc project 这种插件脚本方法就使得我们创建了一个工程插件。

在你工程只需扩展本工程额外功能,不需与其他工程或者其他开发者进行共用时,buildSrc project 这种插件开发或许是个不错的选择。

  • 第三种:Standalone project
    这种方法就是使用单独的一个工程/模块创建我们的 Gradle 插件,这种方法会构建和发表一个JAR文件,可以提供给多工程构建和其他开发者共同使用。通常来说,JAR文件内可能包含有一些自定义的插件脚本,或者是由一些相关的 task 类组合成的一个库,获取前面两者的结合······

下面我们来讲下 Standalone project 插件脚本编写方法,主要有以下几大步骤:

  1. 在Android Studio中新建一个project,然后建立一个 Android Module,然后删除掉目录下除了 src/mainbuild.gradle 之外的其他内容,把 build.gradle 内容清空。
  2. src/main/ 目录下创建一个 groovy 目录,用于存放 Gradle 插件代码。
  3. build.gradle 中添加 gradle sdkgroovy 语言支持
apply plugin: 'groovy'

dependencies {
    //gradle sdk
    compile gradleApi()
    //groovy sdk
    compile localGroovy()
}
  1. 现在,我们就可以进行 Gradle 插件代码的具体编写了,编写方法跟java 基本一致,这里,我就给出一个简单的 Demo:
package com.yn.test

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

class StandAlonePlugin implements Plugin<Project> {
    void apply(Project project) {
        note()
        //create an extension object:Whyn,so others can config via Whyn
        project.extensions.create("whyn", YNExtension)
        project.task('whyn'){
            group = "test"
            description = "gradle Standalone project demo,shares everywhere"
            doLast{
                println '**************************************'
                println "$project.whyn.description"
                println '**************************************'
            }

        }
    }

    private void note(){
        println '------------------------'
        println 'apply StandAlonePlugin'
        println '------------------------'
    }
}

class YNExtension {
    String description = 'default description'
}

这里,我们提供了扩展属性的功能,方便我们在其他地方使用扩展属性,让我们的插件能够接收传递信息。

  1. 代码写完后,为了让 Gradle 能够找到我们插件的实现类,我们还需要提供一个properties文件,具体做法如下:
    main 目录下新建 resources 目录,然后在 resources 目录里面再新建 META-INF 目录,再在 META-INF 里面新建 gradle-plugins目录,最后在 gradle-plugins 里面新建一个 properties 文件(注:该 properties 的命名就是最后别人 apply plugin:时使用的名称),最后在该 properties 文件内写入插件完整包名:implementation-class=com.yn.test.StandAlonePlugin
    最后的目录结构如下图所示:
StandAlone project
  1. 最后,Standalone project 创建的插件需要先进行发布:Publish,才能被其他工程所使用。
    发布方法如下:
  • build.gradle 中添加如下内容:
apply plugin: 'maven-publish'

publishing {
    publications {
        mavenJava(MavenPublication) {

            groupId 'com.whyn.plugin'
            artifactId 'ynplugin'
            version '1.0.0'

            from components.java

        }
    }
}

publishing {
    repositories {
        maven {
            // change to point to your repo, e.g. http://my.org/repo
            url uri('D:/Android/repos')
        }
    }
}

从代码中可以看到,我这里是把插件发布到我本地路径: D:/Android/repos 中,如果把这个路径换成网络地址,那就是发布到网络上。

  • 现在就可以打开控制台窗口,输入 gradlew publish 进行插件发布。
    发布成功后,你就可以在本地路径中看到如下结果:

publish local

更多插件发布内容,请查看官网:Maven Publishing

  1. 到此,我们自定义的插件已经完成了编写和发布过程了,最后要做的就是,在其他功能模块中使用我们这个插件,具体方法如下:
  • 在工程的根目录的 build.gradle 中添加如下内容:
buildscript {
    
    repositories {
        google()
        jcenter()
        maven {//local maven repo path
            url uri('D:/Android/repos')
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0-alpha8'
        //group:artifactId:version
        classpath 'com.whyn.plugin:ynplugin:1.0.0'
//        classpath group: 'com.whyn.plugin', name: 'ynplugin', version: '1.0.0'            
    }
}
  • 然后,在Module的 build.gradleapply 这个插件:
//app build.gradle
apply plugin: 'com.whyn.plugin.StandAlone'

sync 一下,然后在控制台输入 gradlew whyn,你就可以看到以下输出:

whyn_plugin_default_extension

可以看到,我们成功地输出了插件中 description 的默认值,如果我们想改变这个值,那就再加载这个插件的 build.gradle 中配置一下我们插件提供的 extension

//app build.gradle
apply plugin: 'com.whyn.plugin.StandAlone'

whyn {
    description 'description in app build.gradle'
}

然后再 sync,再执行 gradlew whyn,就可以看到我们输出了自定义配置的内容了:

whyn_plugin_custom_extension

顺便在说一下,插件中 apply() 执行的时序是在我们 apply plugin: 的时候就会被调用执行的,也就是说,我们的 build.gradle 中录入 apply plugin:'com.whyn.plugin.StandAlone'后,sycn 的时候,apply plugin:'com.whyn.plugin.StandAlone' 就会被执行,从而插件的 apply(Project project) 就会被调用执行,所以我们每次在 sync 的时候,都可以在 Gradle Console 窗口中看到 apply(Project project) 中的输出信息:

sync

更多的自定义插件编写详情,请查看官网:Writing Custom Plugins

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容