自定義Gradle插件相關(guān)知識

插件

Gradle內(nèi)核本身提供的自動化構(gòu)建功能十分有限,所有實際的功能都是通過插件的形勢提供的,如編譯Java代碼的功能。通過插件可以:
1. 添加新的Tasks,比如JavaCompile Task
2. 在Gradle中添加新的對象,比如SourceSet對象,該對象用于添加一些約定的規(guī)則,像是Java源碼放在src/main/java路徑下
3. 擴展Gradle內(nèi)核對象
4. 擴展其他插件的對象

一個工程需要首先apply Gradle插件,然后才能使用該插件。使用方法很簡單,直接通過task名稱執(zhí)行這個task就行了。

可以直接在項目的構(gòu)建腳本中添加邏輯,也可以通過插件的方式封裝構(gòu)建邏輯并應(yīng)用。

相比于直接在項目的構(gòu)建腳本中添加邏輯,通過apply插件的方式提供了更多的優(yōu)點:

  1. 復(fù)用性強,可以把相似的邏輯通過插件的方式應(yīng)用于多個工程
  2. 模塊化的方式易于理解和管理
  3. 簡化工程的構(gòu)建腳本

下面來講解通過插件的方式封裝構(gòu)建邏輯并使用的方式。

插件可以通過源碼的方式使用,也可以打包成jar包使用。

一個Gradle插件打包了一系列的構(gòu)建邏輯,可以應(yīng)用在不同工程的構(gòu)建中??梢允褂貌煌恼Z言(Groovy,Java或Scala等)來編寫一個Gradle插件,并編譯成二進制文件使用。

插件代碼可以放在不同的位置,如Build Script中,buildSrc文件夾下,或者放在一個單獨的工程中。

  1. 放在Build Script中
    好處是插件代碼會被自動編譯并添加到classPath中,無需其他操作就能使用了。缺點是該插件只能在當前構(gòu)建腳本中使用,無法在腳本之外使用

  2. 放在buildSrc文件夾(rootProjectDir/buildSrc/src/main/groovy)下
    優(yōu)點是Gradle會自動編譯并且添加到classPath中,當前工程里的構(gòu)建腳本都可以使用該插件,缺點是插件不能被其他工程使用。

  3. 放在一個單獨的工程中
    可以打包成一個jar包在任何工程里使用。該jar包可以包含一個或多個plugin,或者包含幾個tasks,或者兩者都有。

實現(xiàn)一個plugin很簡單,只需要實現(xiàn)Plugin接口:

public interface Plugin<T> {
    void apply(T var1);
}

使用Gradle插件需要兩步,第一步解析(resolve)插件,第二步應(yīng)用(apply)插件到一個工程上。

解析插件是說找到指定版本的插件jar包并添加到構(gòu)建腳本的classpath中,這個步驟完成后,插件的API就能在構(gòu)建腳本中調(diào)用。只有通過jar包方式提供的插件才需要解析的過程,而通過腳本提供的插件自動完成解析。

應(yīng)用插件就是在工程構(gòu)建腳本中調(diào)用插件的apply方法,并傳入當前project作為參數(shù),這樣插件可以通過傳入的project參數(shù)修改project配置。解析和應(yīng)用通過plugin DSL語法可以一步完成:

// 應(yīng)用Gradle內(nèi)核plugin可以使用短名稱:
plugins { 
  id 'java'
}
// 應(yīng)用社區(qū)plugin必須使用全名:
plugins {
  id "com.jfrog.bintray" version "0.4.1"
}

或者通過歷史遺留方法分兩步分別完成解析和應(yīng)用:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:0.4.1"
    }
}

apply plugin: "com.jfrog.bintray"

構(gòu)建腳本通過調(diào)用插件的apply方法來實例化一個插件對象,apply方法傳入的參數(shù)就是當前的project對象。插件類可以通過這個project對象對project進行配置,比如添加一個task,下面的代碼中插件在實例化時向project中添加了一個名為hello的task,該task會打印一句話:

apply plugin: GreetingPlugin

class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('hello') {
            doLast {
                println "Hello from the GreetingPlugin"
            }
        }
    }
}

通過gradle -q命令可以執(zhí)行添加的hello task:

> gradle -q hello
Hello from the GreetingPlugin

需要注意的是,如果是在根目錄的Build Script中apply了一個插件,那所有子項目中都會生成一個該插件的實例,可以控制在某些子項目中應(yīng)用該插件,而另一些子項目中不應(yīng)用。
settings.gradle

include 'helloA'
include 'helloB'
include 'goodbyeC'

build.gradle

plugins {
  id "org.gradle.sample.hello" version "1.0.0" apply false
  id "org.gradle.sample.goodbye" version "1.0.0" apply false
}

subprojects { subproject ->
  if (subproject.name.startsWith("hello")) {
    apply plugin: 'org.gradle.sample.hello'
  }
  if (subproject.name.startsWith("goodbye")) {
    apply plugin: 'org.gradle.sample.goodbye'
  }
}

處理生命周期
在經(jīng)歷生命周期的不同階段時,構(gòu)建腳本會接受到不同的通知消息(Notification),可以捕獲這些消息并做一些相應(yīng)的處理。
whenTaskAdded:當一個task被添加的時候

tasks.whenTaskAdded { task ->    
    switch (task.name) {        
        case 'bfd':            
            task.dependsOn 'assembleDebug'            
            break;        
        case 'bfr':            
            setAllConfig(app_version, online, version_name)            
            task.dependsOn 'assembleRelease'            
            break;    
    }
}

task bfd << {}

whenReady:配置完成后

gradle.taskGraph.whenReady { taskGraph -> 
    if (taskGraph.hasTask(release)) { 
        version = '1.0' 
    } else { 
        version = '1.0-SNAPSHOT' 
    }
}

beforeTask/afterTask:task執(zhí)行前后

gradle.taskGraph.afterTask { Task task, TaskState state -> 
    if (state.failure) { 
        println "FAILED" 
    } else { 
        println "done" 
    }
}

更詳細的流程可以看下面的代碼演示:

gradle.afterProject {project, projectState ->
    println "afterProject $project"
}

allprojects {
    afterEvaluate { project ->
        println "afterEvaluate 1"
    }
}

gradle.taskGraph.whenReady { taskGraph ->
    println 'whenReady 2'
}

gradle.taskGraph.beforeTask { Task task ->
    if (task.name.equals("SayHello")) {
        println "beforeTask SayHello 3"
    }
}

task SayHello {
    println 'SayHello task  0'
    doFirst {
        println 'first 4'
    }

    doLast {
        println 'last 5'
    }
}

gradle.taskGraph.afterTask { Task task, TaskState state ->
    if (task.name.equals("SayHello")) {
        println "afterTask SayHello 6"
    }
}

輸出如下:

SayHello task  0                                                                                                                                                                                                           
afterProject project ':app'                    
afterEvaluate 1             
afterProject project ':plugindemolib'
whenReady 2
beforeTask SayHello 3
first 4
last 5
afterTask SayHello 6

如何在插件中修改project中某個task的依賴,比如使check task依賴我們自定義的插件CodeCheckPlugin?可以通過下面的方式實現(xiàn):

public class CodeCheckPlugin implements Plugin<Project> {

    void apply(Project project) {
        project.task('checkCodeAndSendEmail') << {
            println "Hello world"
        }

        project.tasks.whenTaskAdded{ theTask ->   
            if(theTask.name.equals("assembleDebug")){
                theTask.dependsOn "helloTask"
            }
        }
    }
}

這樣在執(zhí)行project的assembleDebug Task時,就會首先執(zhí)行自定義的CodeCheckPlugin里面的checkCodeAndSendEmail,完成一些自定義的檢查或邏輯。比如我們可以使checkCodeAndSendEmail依賴findBug Task,配合Gitlab和Jenkins,可以實現(xiàn)對提交代碼的自動檢查,并將檢查結(jié)果發(fā)送郵件給相關(guān)開發(fā)人員。

參考:
http://blog.csdn.net/sbsujjbcy/article/details/50782830
https://docs.gradle.org/current/userguide/custom_plugins.html
http://blog.csdn.net/sbsujjbcy/article/details/50782830
https://neyoufan.github.io/2016/12/09/android/Jenkins-ci%E5%AE%B9%E5%99%A8%E5%8C%96%E5%9C%A8Android%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8%EF%BC%88%E5%85%AC%E4%BC%97%E5%8F%B7%E7%89%88%EF%BC%89/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容