一起入門gradle自定義插件編寫(一)

相信現(xiàn)在的安卓程序員對(duì)gradle腳本的配置應(yīng)該都或多或少有些了解,例如applicationId、version幔戏、混淆等的基本配置應(yīng)該都是比較熟悉的了,像比較高級(jí)的自定義buildTypes缩挑、productFlavors可能也多多少少了解一些.

但是對(duì)于groovy語言和如何自定義gradle插件,相信很多同學(xué)還是比較陌生的.

作為一個(gè)有理想的安卓程序員,我覺得這種高階的技能還是需要懂的.像一些熱更新弹渔、插件化等高級(jí)技能都會(huì)涉及到groovy代碼的編寫甚至自定義gradle插件.

project.apply方法

我們新建一個(gè)Android Studio項(xiàng)目,得到兩個(gè)build.gradle文件,一個(gè)是項(xiàng)目根目錄下的,一個(gè)是模塊目錄(如app目錄)下的.我們只看模塊目錄下的:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "me.linjw.demo"
        minSdkVersion 24
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

這里的第一行代碼指定了com.android.application這個(gè)插件的使用,這個(gè)插件用來構(gòu)建apk項(xiàng)目.

apply plugin: 'com.android.application'

另外比較常見的插件有用于構(gòu)建aar包的com.android.library插件

apply plugin: 'com.android.library'

和用于構(gòu)建jar包的java-library插件

apply plugin: 'java-library'

我們都知道build.gradle使用的是groovy語法,那這個(gè)使用插件的代碼的語法含義又是怎樣的呢?讓我們一起來看看.

第一個(gè)知識(shí)點(diǎn)是我們?cè)趃radle文件里面默認(rèn)使用的都是project這個(gè)對(duì)象的方法或者屬性,也就是說我們的插件配置代碼等價(jià)于:

project.apply plugin: 'com.android.application'

groovy基本語法

接下來我們就要開始學(xué)一些groovy的基本語法了.

我們可以像一般的強(qiáng)類型語言一樣去定義方法,也可以選擇像一些動(dòng)態(tài)語言一樣忽略參數(shù)和返回值類型:

int foo(int x, int y) {
    return x + y
}

def foo2(def x, def y) {
    return x + y
}

在調(diào)用方法的時(shí)候?yàn)榱撕?jiǎn)潔,你可以選擇省略括號(hào),比如下面的兩行代碼是效果是一樣的,而且我們可以看到,在定義變量的時(shí)候也可以選擇忽略變量的類型:

def x = foo(1,2)
int y = foo 1,2

接下來看看groovy中l(wèi)ist和map的定義方式:

def list = [1, 2, 3, 4]
def map = ['key1': 'val1', key2: 'val2', 3: 'val3', 1.23: 312]

可以看到,map很靈活,key/value都可以是任意的類型,然后在key是字符串的時(shí)候甚至可以直接省略引號(hào).

甚至,在當(dāng)作方法參數(shù)的時(shí)候,我們連map的中括號(hào)也是可以省略的,讓我們來看看groovy代碼是怎樣一步步省略到極致的:

//下面的四行方法是完全等價(jià)的

//不做任何省略
func(['key1': 1, 'key2': 'val2'])

//省略key的雙引號(hào)
func([key1: 1, key2: 'val2'])

//省略map中括號(hào)
func(key1: 1, key2: 'val2')

//省略方法調(diào)用的小括號(hào)
func key1: 1, key2: 'val2'

現(xiàn)在讓我們回過頭來看這行代碼,是不是感覺突然好像有點(diǎn)理解了?

apply plugin: 'com.android.application'

首先它省略了調(diào)用apply的project對(duì)象,然后它省略了key的雙引號(hào),接著又省略了map里面的中括號(hào),最后還省略了方法調(diào)用的小括號(hào)

如果不做任何省略的話,它的完整形式應(yīng)該是:

project.apply(['plugin': 'com.android.application'])

其實(shí)我們也按住ctrl鍵然后用鼠標(biāo)點(diǎn)擊apply,查看方法的聲明:

public interface PluginAware {
  ...
  void apply(Map<String, ?> options);
  ...
}

可以看到它跳轉(zhuǎn)到了一個(gè)java接口里面,這個(gè)apply其實(shí)是PluginAware這個(gè)接口中的一個(gè)方法,參數(shù)為Map類型.

groovy其實(shí)是一種基于jvm的腳本,它可以直接使用java的代碼.

所以我們可以選擇直接用java編寫插件,也可以選擇使用groovy語言編寫,不過最后groovy也是會(huì)被編譯器編譯成java字節(jié)碼的.

編寫自定義gradle代碼

在gradle中編寫代碼有三種方式

最簡(jiǎn)單的一種是直接在build.gradle文件里面添加我們的代碼

第二種是新建一個(gè)gradle文件,在里面編寫我們的代碼,然后用apply from在build.gradle里面導(dǎo)入我們的代碼

第三中就是編寫我們自己的插件了

第一種方法我們就不說了,直接講第二種.

apply from操作

首先我們需要?jiǎng)?chuàng)建一個(gè)gradle文件,然后在里面寫我們的方法.

例如我在項(xiàng)目根目錄下面新建了一個(gè)mycode.gradle文件,然后寫好代碼:

def add(def x, def y) {
    return x + y
}
println('=================')
println(add(1, 2))
println('=================')

然后在app目錄下的build.gradle里面使用apply from操作導(dǎo)入這個(gè)文件:

apply plugin: 'com.android.application'
apply from: '../mycode.gradle'

然后點(diǎn)擊build,就可以看到輸出了:

Executing tasks: [build]

NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory.  It is currently set to /home/linjw/android/sdk/ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.

=================
3
=================
NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory.  It is currently set to /home/linjw/android/sdk/ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.
...

當(dāng)然我們知道apply是一個(gè)接收Map的方法,我們不用調(diào)用兩次apply方法,也可以直接這么寫,直接在一次調(diào)用中com.android.application插件和mycode.gradle的導(dǎo)入

apply plugin: 'com.android.application', from: '../mycode.gradle'

自定義gradle插件

最高級(jí)的方法就是直接編寫自定義插件了,編寫好的插件可以發(fā)布到j(luò)center或者maven上給人使用.

創(chuàng)建Gradle Module

首先我們需要?jiǎng)?chuàng)建一個(gè)Gradle Module用于編寫gradle插件的代碼.但是Android Studio是沒有辦法直接創(chuàng)建Gradle Module的.

所以我們新建個(gè)普通的apk項(xiàng)目,或者新建個(gè)Android Library module然后再更改下配置將它改成Gradle Module就好

我這里就直接用新建出來的apk項(xiàng)目了.

第一步是進(jìn)入app目錄,將里面的東西全部都刪掉.

1.編寫build.gradle

然后新建一個(gè)在app目錄下新建一個(gè)build.gradle文件,寫入代碼:

apply plugin: 'groovy'

dependencies {
    compile gradleApi()
    compile localGroovy()
}

2.編寫代碼

接著在app目錄下面新建src目錄,然后進(jìn)入src目錄新建main目錄,然后再進(jìn)入main繼續(xù)新建groovy目錄

最后在groovy目錄中根據(jù)包名新建目錄層級(jí),并且新建MyPlugin.groovy文件用于編寫我們的插件代碼.

我的包名是me.linjw.plugin,所以目錄結(jié)構(gòu)如下:

1.png

插件都需要實(shí)現(xiàn)Plugin<Project>接口,然后編寫自己代碼.代碼如下:

package me.linjw.plugin

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

public class MyPlugin implements Plugin<Project> {
    def add(def x, def y) {
        return x + y
    }

    void apply(Project project) {
        println("=======MyPlugin========")
        println(add(1, 2))
        println("===============")
    }
}

3.注冊(cè)插件

上面我們已經(jīng)編寫好了我們的插件了,接下來的事情就是告訴gradle哪個(gè)是我們的插件類.

main目錄下新建resources目錄,然后在resources目錄里面再新建META-INF目錄,再在META-INF里面新建gradle-plugins目錄.最后在gradle-plugins目錄里面新建properties文件.

這個(gè)properties文件的名字就是你插件的名字了,例如之前看到的com.android.application媒熊、com.android.library

我這邊的名字為me.islinlw.plugin.demo.properties

接著在properties文件里面配置我們的插件類:

implementation-class=me.linjw.plugin.MyPlugin

5.png

發(fā)布插件到本地maven

這個(gè)時(shí)候其實(shí)點(diǎn)擊build已經(jīng)可以在app/build/libs目錄下看到我們的插件被編譯成app.jar了

但是需要先發(fā)布出去別人才能使用,一般可以發(fā)布到公司內(nèi)部或者公網(wǎng)的倉(cāng)庫(kù)如jcenter等.我們這邊由于是demo,可以先選擇發(fā)布到電腦的本地倉(cāng)庫(kù).

我們修改下build.gradle:

apply plugin: 'groovy'
apply plugin: 'maven'

dependencies {
    compile gradleApi()
    compile localGroovy()
}


repositories {
    mavenCentral()
}

group='me.islinjw.plugin'
version='1.0.0'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: uri('/home/linjw/workspace/LocalMaven'))
        }
    }
}

然后點(diǎn)擊uploadArchives,就可以將插件發(fā)布到/home/linjw/workspace/LocalMaven

2.png

使用插件

讓我們打開一個(gè)項(xiàng)目來驗(yàn)證下.

首先在項(xiàng)目根目錄的build.gradle的buildscript.repositories里面配置本地倉(cāng)庫(kù)的路徑,并且在buildscript.dependencies配置插件依賴:

3.png

最后在app目錄下的build.gradle里面使用我們的插件:

4.png

就可以點(diǎn)擊build看到輸出了

16:57:12: Executing task 'build'...

Executing tasks: [build]

NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory.  It is currently set to /home/linjw/android/sdk/ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.

=======MyPlugin========
3
===============
NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory.  It is currently set to /home/linjw/android/sdk/ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.

修改插件的ArtifactID

我們看到添加依賴的時(shí)候,插件的ArtifactID其實(shí)是app,這個(gè)又要怎么修改呢?

classpath 'me.islinjw.plugin:app:1.0.0'

回到我們的插件項(xiàng)目的根目錄,修改settings.gradle,將模塊名改成DemoPlugin:

//原來是include ':app'
include ':DemoPlugin'

然后將我們的app目錄改名成DemoPlugin

最后再發(fā)布一次,就修改完成了

于是依賴就變成了

classpath 'me.islinjw.plugin:DemoPlugin:1.0.0'
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末帽哑,一起剝皮案震驚了整個(gè)濱河市谜酒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌妻枕,老刑警劉巖僻族,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異屡谐,居然都是意外死亡述么,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門愕掏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來度秘,“玉大人,你說我怎么就攤上這事饵撑》蠹兀” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵肄梨,是天一觀的道長(zhǎng)阻荒。 經(jīng)常有香客問我,道長(zhǎng)众羡,這世上最難降的妖魔是什么侨赡? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮粱侣,結(jié)果婚禮上羊壹,老公的妹妹穿的比我還像新娘。我一直安慰自己齐婴,他們只是感情好油猫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著柠偶,像睡著了一般情妖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诱担,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天毡证,我揣著相機(jī)與錄音,去河邊找鬼蔫仙。 笑死料睛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播恤煞,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼屎勘,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了居扒?” 一聲冷哼從身側(cè)響起挑秉,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苔货,沒想到半個(gè)月后犀概,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夜惭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年姻灶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诈茧。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡产喉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出敢会,到底是詐尸還是另有隱情曾沈,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布鸥昏,位于F島的核電站塞俱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吏垮。R本人自食惡果不足惜障涯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望膳汪。 院中可真熱鬧唯蝶,春花似錦、人聲如沸遗嗽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痹换。三九已至征字,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晴音,已是汗流浹背柔纵。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锤躁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像系羞,于是被迫代替她去往敵國(guó)和親郭计。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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

  • 這篇文章講給大家?guī)韌radle打包系列中的高級(jí)用法-自己動(dòng)手編寫gradle插件椒振。我們平常在做安卓開發(fā)時(shí)昭伸,都會(huì)在...
    呆萌狗和求疵喵閱讀 15,985評(píng)論 22 80
  • 在 Android Studio 構(gòu)建的項(xiàng)目中,基于 Gradle 進(jìn)行項(xiàng)目的構(gòu)建澎迎,同時(shí)使用 Android DS...
    Ant_way閱讀 7,356評(píng)論 0 16
  • 探討Gradle插件的自定義有助更好的理解Gradle庐杨,本文綜合了userguide中的幾篇相關(guān)文檔,將不單獨(dú)給出...
    cntlb閱讀 2,492評(píng)論 0 7
  • 在冬日的下午,陽光正好哮洽,我尋思著抽出一個(gè)小時(shí)來看看書填渠。 于是,隨手拿起一本《烏合之眾》鸟辅,正當(dāng)準(zhǔn)備翻閱時(shí)氛什,突然手機(jī)響...
    九月說閱讀 292評(píng)論 0 0
  • 今天遇到運(yùn)行爬蟲時(shí)遇到需要批量填入文件夾名的問題,150+個(gè)文件夾匪凉,一個(gè)個(gè)復(fù)制名字簡(jiǎn)直叫人發(fā)狂枪眉。于是查了一下,網(wǎng)上...
    onlyHalfSoul閱讀 2,235評(píng)論 0 2