Gradle自定義插件以及發(fā)布方法

前言

我們平常在進(jìn)行Android開(kāi)發(fā)時(shí)熊响,都會(huì)使用 Gradle 來(lái)進(jìn)行項(xiàng)目配置奖唯,通常在對(duì)應(yīng)的module:app的build.gradle中,在最上面的一句話一般都為:

apply plugin: 'com.android.application'

這句話就是用來(lái)加載gradle的android開(kāi)發(fā)插件庞瘸,然后焰薄,我們就可以使用該插件提供的配置方法進(jìn)行Android項(xiàng)目的配置了,即如下所示:

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 插件配置詳情跟压,請(qǐng)查看:Android Plugin DSL Reference

簡(jiǎn)單來(lái)講胰蝠,Gradle插件允許我們做一些額外的擴(kuò)展工作,比如我想在module每次build完成后震蒋,把生成的jar/aar移動(dòng)到另一個(gè)項(xiàng)目的libs文件內(nèi)茸塞,相當(dāng)于動(dòng)態(tài)更新庫(kù)文件······
其實(shí)像上面這種操作用 Gradletask 就可以完成,但是使用 task 的一個(gè)弊端就是沒(méi)辦法做到復(fù)用查剖,而使用 Gradle 你就能在任何項(xiàng)目钾虐,任何模塊中使用同一套邏輯功能,甚至于你還能對(duì)不同的模塊進(jìn)行動(dòng)態(tài)化的個(gè)性配置笋庄,只要插件代碼支持即可禾唁。

更多 Gradle 使用方法,請(qǐng)查看官網(wǎng):Gradle User Guide

自定義插件

上面我們說(shuō)了自定義插件的諸多好處无切,那么荡短,究竟該如何進(jìn)行 Gradle 自定義插件的編寫呢 ?
其實(shí),自定義插件基于源碼放置可以分為3種:

  • 第一種:Build script
    這種插件腳本的源碼放置在模塊內(nèi)的 build.gradle 中哆键,好處就是插件腳本會(huì)被自動(dòng)編譯并添加進(jìn)模塊的 classpath 中掘托,我們完全不用做任何事情。但是籍嘹,這種插件腳本只能在聲明的這個(gè) build.gradle 中使用闪盔,其他模塊是沒(méi)辦法復(fù)用這個(gè)插件的弯院。
//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"
            }
        }
    }
}

如上面這個(gè)插件 GreetingPlugin,我們是在 appbuild.gradle 中聲明定義的,然后泪掀,在控制臺(tái)運(yùn)行下: gradle app:tasks听绳,或者直接看Android Studio的Gradle窗口,可以看到如下結(jié)果:

Build script

可以看到异赫,只有我們聲明編寫的 app 中成功添加了一個(gè) task:hello(根目錄也會(huì)同時(shí)添加進(jìn)這個(gè)插件功能)椅挣,然后,你在工程其他 build.gradleapply plugin: GreetingPlugin 是無(wú)法成功的塔拳,因?yàn)檫@種插件對(duì)其他模塊是不可見(jiàn)的鼠证。

所以,Build script 這種插件其實(shí)跟直接定義一個(gè) task 沒(méi)有多大區(qū)別靠抑。

  • 第二種:buildSrc project
    這種插件腳本要求源碼放置在 rootProjectDir/buildSrc/src/main/groovy目錄內(nèi)(也就是工程根目錄下創(chuàng)建 buildSrc 目錄)量九,然后 Gradle 就會(huì)自動(dòng)編譯和測(cè)試這個(gè)插件,同時(shí)颂碧,這種方法創(chuàng)建的插件對(duì)工程內(nèi)的所有模塊都是可以使用的荠列。

buildSrc project

從上圖可以看到,我們?cè)谀K app 中成功加載了插件载城,所以肌似,使用 buildSrc project 這種插件腳本方法就使得我們創(chuàng)建了一個(gè)工程插件。

在你工程只需擴(kuò)展本工程額外功能个曙,不需與其他工程或者其他開(kāi)發(fā)者進(jìn)行共用時(shí)锈嫩,buildSrc project 這種插件開(kāi)發(fā)或許是個(gè)不錯(cuò)的選擇。

  • 第三種:Standalone project
    這種方法就是使用單獨(dú)的一個(gè)工程/模塊創(chuàng)建我們的 Gradle 插件垦搬,這種方法會(huì)構(gòu)建和發(fā)表一個(gè)JAR文件呼寸,可以提供給多工程構(gòu)建和其他開(kāi)發(fā)者共同使用。通常來(lái)說(shuō)猴贰,JAR文件內(nèi)可能包含有一些自定義的插件腳本对雪,或者是由一些相關(guān)的 task 類組合成的一個(gè)庫(kù),獲取前面兩者的結(jié)合······

下面我們來(lái)講下 Standalone project 插件腳本編寫方法米绕,主要有以下幾大步驟:

  1. 在Android Studio中新建一個(gè)project瑟捣,然后建立一個(gè) Android Module,然后刪除掉目錄下除了 src/mainbuild.gradle 之外的其他內(nèi)容栅干,把 build.gradle 內(nèi)容清空迈套。
  2. src/main/ 目錄下創(chuàng)建一個(gè) groovy 目錄,用于存放 Gradle 插件代碼碱鳞。
  3. build.gradle 中添加 gradle sdkgroovy 語(yǔ)言支持
apply plugin: 'groovy'

dependencies {
    //gradle sdk
    compile gradleApi()
    //groovy sdk
    compile localGroovy()
}
  1. 現(xiàn)在桑李,我們就可以進(jìn)行 Gradle 插件代碼的具體編寫了,編寫方法跟java 基本一致,這里贵白,我就給出一個(gè)簡(jiǎn)單的 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'
}

這里率拒,我們提供了擴(kuò)展屬性的功能,方便我們?cè)谄渌胤绞褂脭U(kuò)展屬性禁荒,讓我們的插件能夠接收傳遞信息猬膨。

  1. 代碼寫完后,為了讓 Gradle 能夠找到我們插件的實(shí)現(xiàn)類呛伴,我們還需要提供一個(gè)properties文件勃痴,具體做法如下:
    main 目錄下新建 resources 目錄,然后在 resources 目錄里面再新建 META-INF 目錄磷蜀,再在 META-INF 里面新建 gradle-plugins目錄召耘,最后在 gradle-plugins 里面新建一個(gè) properties 文件(注:該 properties 的命名就是最后別人 apply plugin:時(shí)使用的名稱)百炬,最后在該 properties 文件內(nèi)寫入插件完整包名:implementation-class=com.yn.test.StandAlonePlugin褐隆。
    最后的目錄結(jié)構(gòu)如下圖所示:
StandAlone project
  1. 最后,Standalone project 創(chuàng)建的插件需要先進(jìn)行發(fā)布:Publish剖踊,才能被其他工程所使用庶弃。
    發(fā)布方法如下:
  • build.gradle 中添加如下內(nèi)容:
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')
        }
    }
}

從代碼中可以看到,我這里是把插件發(fā)布到我本地路徑: D:/Android/repos 中德澈,如果把這個(gè)路徑換成網(wǎng)絡(luò)地址歇攻,那就是發(fā)布到網(wǎng)絡(luò)上。

  • 現(xiàn)在就可以打開(kāi)控制臺(tái)窗口梆造,輸入 gradlew publish 進(jìn)行插件發(fā)布缴守。
    發(fā)布成功后,你就可以在本地路徑中看到如下結(jié)果:

publish local

更多插件發(fā)布內(nèi)容镇辉,請(qǐng)查看官網(wǎng):Maven Publishing

  1. 到此屡穗,我們自定義的插件已經(jīng)完成了編寫和發(fā)布過(guò)程了,最后要做的就是忽肛,在其他功能模塊中使用我們這個(gè)插件村砂,具體方法如下:
  • 在工程的根目錄的 build.gradle 中添加如下內(nèi)容:
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 這個(gè)插件:
//app build.gradle
apply plugin: 'com.whyn.plugin.StandAlone'

sync 一下屹逛,然后在控制臺(tái)輸入 gradlew whyn础废,你就可以看到以下輸出:

whyn_plugin_default_extension

可以看到,我們成功地輸出了插件中 description 的默認(rèn)值罕模,如果我們想改變這個(gè)值评腺,那就再加載這個(gè)插件的 build.gradle 中配置一下我們插件提供的 extension

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

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

然后再 sync,再執(zhí)行 gradlew whyn淑掌,就可以看到我們輸出了自定義配置的內(nèi)容了:

whyn_plugin_custom_extension

順便在說(shuō)一下蒿讥,插件中 apply() 執(zhí)行的時(shí)序是在我們 apply plugin: 的時(shí)候就會(huì)被調(diào)用執(zhí)行的,也就是說(shuō),我們的 build.gradle 中錄入 apply plugin:'com.whyn.plugin.StandAlone'后诈悍,sycn 的時(shí)候祸轮,apply plugin:'com.whyn.plugin.StandAlone' 就會(huì)被執(zhí)行,從而插件的 apply(Project project) 就會(huì)被調(diào)用執(zhí)行侥钳,所以我們每次在 sync 的時(shí)候适袜,都可以在 Gradle Console 窗口中看到 apply(Project project) 中的輸出信息:

sync

更多的自定義插件編寫詳情,請(qǐng)查看官網(wǎng):Writing Custom Plugins

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末舷夺,一起剝皮案震驚了整個(gè)濱河市苦酱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌给猾,老刑警劉巖疫萤,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異敢伸,居然都是意外死亡扯饶,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門池颈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)尾序,“玉大人,你說(shuō)我怎么就攤上這事躯砰∶勘遥” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵琢歇,是天一觀的道長(zhǎng)兰怠。 經(jīng)常有香客問(wèn)我,道長(zhǎng)李茫,這世上最難降的妖魔是什么揭保? 我笑而不...
    開(kāi)封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮涌矢,結(jié)果婚禮上掖举,老公的妹妹穿的比我還像新娘。我一直安慰自己娜庇,他們只是感情好塔次,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著名秀,像睡著了一般励负。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匕得,一...
    開(kāi)封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天继榆,我揣著相機(jī)與錄音巾表,去河邊找鬼。 笑死略吨,一個(gè)胖子當(dāng)著我的面吹牛集币,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播翠忠,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鞠苟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了秽之?” 一聲冷哼從身側(cè)響起当娱,我...
    開(kāi)封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎考榨,沒(méi)想到半個(gè)月后跨细,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡河质,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年冀惭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愤诱。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡云头,死狀恐怖捐友,靈堂內(nèi)的尸體忽然破棺而出淫半,到底是詐尸還是另有隱情,我是刑警寧澤匣砖,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布科吭,位于F島的核電站,受9級(jí)特大地震影響猴鲫,放射性物質(zhì)發(fā)生泄漏对人。R本人自食惡果不足惜拂共,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一牺弄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宜狐,春花似錦势告、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至俭驮,卻和暖如春回溺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工遗遵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萍恕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓车要,卻偏偏與公主長(zhǎng)得像雄坪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子屯蹦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,085評(píng)論 25 707
  • afinalAfinal是一個(gè)android的ioc维哈,orm框架 https://github.com/yangf...
    passiontim閱讀 15,429評(píng)論 2 45
  • 轉(zhuǎn)載注明出處:http://www.reibang.com/p/5255b100930e 0. 前言 完全由個(gè)人翻...
    王三的貓阿德閱讀 2,515評(píng)論 0 4
  • 羅輯思維--灰犀牛 “房間里的大象”是人人都看見(jiàn)了,可是出于各種“社會(huì)性誤會(huì)”和心理需要登澜,大家都不說(shuō)阔挠,是心照不宣的...
    danielyu小于閱讀 284評(píng)論 0 0
  • 本能上的確是想說(shuō):是购撼! 人的慣性思維本來(lái)就是如此,經(jīng)常聽(tīng)到身邊的人說(shuō): 等我有了錢谴仙,我就買兩臺(tái)電腦迂求,一臺(tái)玩游戲,一...
    StudentDylan閱讀 506評(píng)論 0 1