Gradle自定义插件

Android Gradle

Android项目使用 Gradle 作为构建框架,Gradle 又是以Groovy为脚本语言。所以学习Gradle之前需要先熟悉Groovy脚本语言。

Groovy是基于Java语言的脚本语言,所以它的语法和Java非常相似,但是具有比java更好的灵活性。

Android Gradle 的 Project 和 Tasks

这个是Gradle中最重要的两个概念。每次构建(build)至少由一个project构成,一个project 由一到多个task构成。项目结构中的每个build.gradle文件代表一个project,在这编译脚本文件中可以定义一系列的task;task 本质上又是由一组被顺序执行的Action`对象构成,Action其实是一段代码块,类似于Java中的方法。

  • Android Gradle 构建生命周期

每次构建的执行本质上执行一系列的Task。某些Task可能依赖其他Task。那些没有依赖的Task总会被最先执行,而且每个Task只会被执行一遍。每次构建的依赖关系是在构建的配置阶段确定的。每次构建分为3个阶段:

  • Initialization: 初始化阶段

这是创建Project阶段,构建工具根据每个build.gradle文件创建出一个Project实例。初始化阶段会执行项目根目录下的settings.gradle文件,来分析哪些项目参与构建。

所以这个文件里面的内容经常是:

 include ':app'
 include ':libraries'

这是告诉Gradle这些项目需要编译,所以我们引入一些开源的项目的时候,需要在这里填上对应的项目名称,来告诉Gradle这些项目需要参与构建。

  • Configuration:配置阶段

这个阶段,通过执行构建脚本来为每个project创建并配置Task。配置阶段会去加载所有参与构建的项目的build.gradle文件,会将每个build.gradle文件实例化为一个Gradle的project对象。然后分析project 之间的依赖关系,下载依赖文件,分析project下的task之间的依赖关系。

  • Execution:执行阶段

这是Task真正被执行的阶段,Gradle会根据依赖关系决定哪些Task需要被执行,以及执行的先后顺序。

task是Gradle中的最小执行单元,我们所有的构建,编译,打包,debug,test等都是执行了某一个task,一个project可以有多个task,task之间可以互相依赖。例如我有两个task,taskA和taskB,指定taskA依赖taskB,然后执行taskA,这时会先去执行taskB,taskB执行完毕后在执行taskA。

你点击AndroidStudio右侧的一个Gradle按钮,会打开一个面板,内容差不多是这样的:
Gradle自定义插件_第1张图片
里面的每一个条目都是一个task,那这些task是哪来的呢?

一个是根目录下的 build.gradle 中的:

dependencies {
   classpath 'com.android.tools.build:gradle:3.2.1'
}

一个是 app 目录下的 build.gradle 中的:

apply plugin: 'com.android.application'

这两段代码决定的。也就是说,Gradle提供了一个框架,这个框架有一些运行的机制可以让你完成编译,但是至于怎么编译是由插件决定的。还好Google已经给我们写好了Android对应的Gradle工具,我们使用就可以了。

根目录下的build.gradle中 dependencies { classpath ‘com.android.tools.build:gradle:3.2.1 } 是Android Gradle编译插件的版本。

app目录下的build.gradle中的apply plugin: ‘com.android.application’ 是引入了Android的应用构建项目,还有com.android.library和com.android.application用来构建library和应用。

所有Android构建需要执行的task都封装在工具里,如果你有一些特殊需求的话,也可以自己写一些task。那么对于开发一个Android应用来说,最关键的部分就是如何来用Android Gradle的插件了。

认知Gradle Wrapper

Android Studio中默认会使用 Gradle Wrapper 而不是直接使用Gradle。命令也是使用gradlew而不是gradle。这是因为gradle针对特定的开发环境的构建脚本,新的gradle可能不能兼容旧版的构建环境。为了解决这个问题,使用Gradle Wrapper 来间接使用 gradle。相当于在外边包裹了一个中间层。对开发者来说,直接使用Gradlew 即可,不需要关心 gradle的版本变化。Gradle Wrapper 会负责下载合适的的gradle版本来构建项目。

Android 三个文件重要的 gradle 文件

Gradle项目有3个重要的文件需要深入理解:项目根目录的 build.gradle , settings.gradle 和模块目录的 build.gradle 。

  • settings.gradle 文件会在构建的 initialization 阶段被执行,它用于告诉构建系统哪些模块需要包含到构建过程中。对于单模块项目, settings.gradle 文件不是必需的。对于多模块项目,如果没有该文件,构建系统就不能知道该用到哪些模块。
  • 项目根目录的 build.gradle 文件用来配置针对所有模块的一些属性。它默认包含2个代码块:buildscript{…}和allprojects{…}。前者用于配置构建脚本所用到的代码库和依赖关系,后者用于定义所有模块需要用到的一些公共属性。
buildscript {
  repositories {
    jcenter()
  }
 
  dependencies {
     classpath 'com.android.tools.build:gradle:3.2.1'
  }
}
 
allprojects {
  repositories {
    jcenter()
  }
}
 
task clean(type: Delete) {
  delete rootProject.buildDir

(1) buildscript:定义了 Android 编译工具的类路径。repositories中, jCenter是一个著名的 Maven仓库。
(2)allprojects:定义的属性会被应用到所有 moudle中,但是为了保证每个项目的独立性,我们一般不会在这里面操作太多共有的东西。

  • 模块级配置文件 build.gradle 针对每个moudle 的配置,这里的定义的选项和顶层
    build.gradle定义的相同。它有3个重要的代码块:plugin,android 和 dependencies。

自定义gradle插件

编写Gradle插件主要有三种方法:

  • build.gradle脚本中直接使用。这种方式就是直接在Android Studio app moudle的build.gradle中进行插件的编写,优点是不用再上传插件到maven或者其它地方,项目就可以直接使用;缺点也很明显,就是只能在自己的项目中使用,不能复用,这个不是我们今天要说的。
  • buildSrc中使用。这种方式需要在项目中新建一个model命名为buildSrc,这个目录就用来存放自定义插件。然后在src/main中建立两个目录,一个就是存放代码的groovy目录,一个是存放自定义插件名称的resources目录。这种定义方式也是只能在我们项目中进行使用,不好复用。
  • 独立Module中使用。这种方式就是完全独立开发一个Module,可以随便用。

配置

AS中新建一个Module接着就是配置目录了,和上面说的第二种方式其实一样的,配置好的目录如下,其中groovy目录就是放置代码的地方,resources里面放置的是一个配置文件。在gradle-plugins文件夹下新建一个文件com.example.watson.plugin.properties,文件的名字com.example.watson.plugin就是在使用这个插件的地方需要的名字,比如

apply plugin:'com.example.watson.plugin'

Gradle自定义插件_第2张图片

上面配置文件内容, 其实就是一个映射关系,找到我们定义的插件NetworkPlugin,com.example.watson.plugin是NetworkPlugin这个插件类所在的包名。

implementation-class=com.example.watson.plugin.NetworkPlugin

插件实现

环境都配置好了,接下来就是实现NetworkPlugin这个插件了,在groovy文件夹下新建包名并在该名下新建文件NetworkPlugin.groovy。当然groovy也是完全兼容Java的,所以小伙伴们看起来完全无压力啊。

定义插件首先要实现Plugin接口,然后在apply方法中实现插件功能。

class NetworkPlugin implements Plugin{

    @Override
    void apply(Project project) {
        println "------network plugin begin-------"
        project.tasks.create("networkTest", NetworkTask) {
            doLast {
                println "doLast"

            }
        }
        println "------network plugin end-------"
    }

}

为了直观感受,我添加了一个task,也就是networkTest,这个Task就是请求百度首页的网页代码并打印出来。在相同目录下新建文件NetworkTest.groovy,Task的具体工作就是@TaskAction这个注解标注的方法中了。

class NetworkTask  extends DefaultTask {

    @TaskAction
    def testNetwork() {
        println "------NetworkTask begin-------"
        try {
            OkHttpClient mOkHttpClient = new OkHttpClient()
            Request request = new Request.Builder().url("http://www.baidu.com/").build()
            Call call = mOkHttpClient.newCall(request)
            Response mResponse = call.execute()
            if (mResponse.isSuccessful()) {
                println mResponse.body().string()
            }
        } catch (Exception e) {
            e.printStackTrace()
            println e.toString()
        }
        println "------NetworkTask end-------"
    }

}

到这里我们插件的代码工作基本就完成了,剩下最后一个问题,怎么用这个插件呢?当然就是上传Maven等等的仓库中了,这里为了方便我就上传到自己的本地了。

上传插件

上传插件就是在这个Module的build.gradle中写Task了,这里我就上传到本地D盘reponsitory目录下了。

apply plugin: 'groovy'
//使用该插件,才能使用uploadArchives
apply plugin: 'maven'

repositories {
    jcenter()
}

dependencies {
    //使用gradle sdk
    compile gradleApi()
    //使用groovy sdk
    compile localGroovy()
    compile 'com.android.tools.build:gradle:3.0.1'
    //网络请求框架
    compile 'com.squareup.okhttp3:okhttp:3.7.0'
    compile 'com.squareup.okio:okio:1.9.0'
}

sourceCompatibility = "1.8"
targetCompatibility = "1.8"

uploadArchives {
    repositories.mavenDeployer {
        pom.version = '1.0.0'
        pom.artifactId = 'watsonPlugin'
        pom.groupId = 'com.example.watson.plugin'
        repository(url: "file:///D:/repository/")
    }
}

点击下build就能在plugin模块看见我们定义的uploadArchives这个Task了。
Gradle自定义插件_第3张图片
点击下这个任务就能在对应的目录下生成这个插件。
Gradle自定义插件_第4张图片

使用插件

首先在工程的根目录下的build.gradle文件下添加如下代码。maven仓库就是我们上面的仓库地址,添加依赖,其中com.example.watson.plugin就是groupId,watsonPlugin就是artifactId,1.0.0就是版本号了。

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
        maven {
            url uri('D:/repository')  //add
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.2'
        classpath 'com.example.watson.plugin:watsonPlugin:1.0.0' //add
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

添加上面代码后Sync一下就能看见在引用Module的Tasks->other下面看到我们的Task了:
在这里插入图片描述
到这一步就是大功告成了,点击下这个Task就能执行请求网络和打印日志了。
Gradle自定义插件_第5张图片
DEMO下载地址

参考:
深入理解Android之Gradle
自定义gradle插件入门
一步步自定义Gradle插件

你可能感兴趣的:(进阶)