自定义Gradle插件相关知识

作者: JackMeGo | 来源:发表于2017-06-13 19:13 被阅读118次
    插件

    Gradle内核本身提供的自动化构建功能十分有限,所有实际的功能都是通过插件的形势提供的,如编译Java代码的功能。通过插件可以:
    1. 添加新的Tasks,比如JavaCompile Task
    2. 在Gradle中添加新的对象,比如SourceSet对象,该对象用于添加一些约定的规则,像是Java源码放在src/main/java路径下
    3. 扩展Gradle内核对象
    4. 扩展其他插件的对象

    一个工程需要首先apply Gradle插件,然后才能使用该插件。使用方法很简单,直接通过task名称执行这个task就行了。

    可以直接在项目的构建脚本中添加逻辑,也可以通过插件的方式封装构建逻辑并应用。

    相比于直接在项目的构建脚本中添加逻辑,通过apply插件的方式提供了更多的优点:

    1. 复用性强,可以把相似的逻辑通过插件的方式应用于多个工程
    2. 模块化的方式易于理解和管理
    3. 简化工程的构建脚本

    下面来讲解通过插件的方式封装构建逻辑并使用的方式。

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

    一个Gradle插件打包了一系列的构建逻辑,可以应用在不同工程的构建中。可以使用不同的语言(Groovy,Java或Scala等)来编写一个Gradle插件,并编译成二进制文件使用。

    插件代码可以放在不同的位置,如Build Script中,buildSrc文件夹下,或者放在一个单独的工程中。

    1. 放在Build Script中
      好处是插件代码会被自动编译并添加到classPath中,无需其他操作就能使用了。缺点是该插件只能在当前构建脚本中使用,无法在脚本之外使用

    2. 放在buildSrc文件夹(rootProjectDir/buildSrc/src/main/groovy)下
      优点是Gradle会自动编译并且添加到classPath中,当前工程里的构建脚本都可以使用该插件,缺点是插件不能被其他工程使用。

    3. 放在一个单独的工程中
      可以打包成一个jar包在任何工程里使用。该jar包可以包含一个或多个plugin,或者包含几个tasks,或者两者都有。

    实现一个plugin很简单,只需要实现Plugin接口:

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

    使用Gradle插件需要两步,第一步解析(resolve)插件,第二步应用(apply)插件到一个工程上。

    解析插件是说找到指定版本的插件jar包并添加到构建脚本的classpath中,这个步骤完成后,插件的API就能在构建脚本中调用。只有通过jar包方式提供的插件才需要解析的过程,而通过脚本提供的插件自动完成解析。

    应用插件就是在工程构建脚本中调用插件的apply方法,并传入当前project作为参数,这样插件可以通过传入的project参数修改project配置。解析和应用通过plugin DSL语法可以一步完成:

    // 应用Gradle内核plugin可以使用短名称:
    plugins { 
      id 'java'
    }
    // 应用社区plugin必须使用全名:
    plugins {
      id "com.jfrog.bintray" version "0.4.1"
    }
    

    或者通过历史遗留方法分两步分别完成解析和应用:

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

    构建脚本通过调用插件的apply方法来实例化一个插件对象,apply方法传入的参数就是当前的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命令可以执行添加的hello task:

    > gradle -q hello
    Hello from the GreetingPlugin
    

    需要注意的是,如果是在根目录的Build Script中apply了一个插件,那所有子项目中都会生成一个该插件的实例,可以控制在某些子项目中应用该插件,而另一些子项目中不应用。
    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'
      }
    }
    

    处理生命周期
    在经历生命周期的不同阶段时,构建脚本会接受到不同的通知消息(Notification),可以捕获这些消息并做一些相应的处理。
    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执行前后

    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?可以通过下面的方式实现:

    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"
                }
            }
        }
    }
    

    这样在执行project的assembleDebug Task时,就会首先执行自定义的CodeCheckPlugin里面的checkCodeAndSendEmail,完成一些自定义的检查或逻辑。比如我们可以使checkCodeAndSendEmail依赖findBug Task,配合Gitlab和Jenkins,可以实现对提交代码的自动检查,并将检查结果发送邮件给相关开发人员。

    参考:
    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/

    相关文章

      网友评论

        本文标题:自定义Gradle插件相关知识

        本文链接:https://www.haomeiwen.com/subject/afyuattx.html