阅读 802

Gradle插件开发

一、Gradle插件的概念

Gradle是一个构建工具,让工程构建更加自动化,不过它只是一个执行环境,提供了基本的框架,真正的构建行为不是Gradle提供,Gradle负责在运行时,找到所有需要执行的任务一一去执行。

上面提到的任务有两种方式创建,一是手动创建,如在自定义任务里编译工程的java代码;二是通过插件,将相似的代码进行封装,几乎所有的功能都是以插件的形式提供。插件负责封装或者提供Gradle运行期间需要的Task,在工程中依赖某个插件后,就能复用这个插件提供的构建行为。

Android Gradle插件就是基于java插件扩展的,在编译java代码的基础上,添加了编译资源、打包APK的功能。

本文主要内容如图,

image.png

二、Gradle插件的分类

Gradle插件分为两种:二进制插件和脚本插件。

脚本插件:轻量级,独立的Gradle脚本。脚本中可以对工程的build.gradle脚本中的配置进行进一步配置或补充,既可存在于工程的目录里,又可存在于某远程服务器的地址中。

二进制插件:实现了plugin接口,可存在于独立的编译脚本里,也可作为独立的工程去维护,对外发布成插件Jar包,如Android插件。

插件最开始的形式是脚本插件,当脚本中的代码需要复用时,可将脚本插件包装成一个二进制插件,方便在不同的团队或工程进行共享。

2.1 二进制插件的用法

二进制插件的用法分为三部:声明插件的ID与版本号

1)声明插件的ID与版本号

进入根目录build.gradle,在buildscript内dependencies中通过classpath声明需要使用的插件的ID与版本号,如

classpath "com.android.tools.build:gradle:4.1.3"
复制代码

然后Gradle将这个插件下载到本地。

2)应用插件

在子工程的build.gradle,通过apply应用插件,绑定插件与工程,如

apply plugin:'com.android.application'
复制代码

apply plugin后面引用的名称由发布插件方在说明中给出。

3)插件参数配置(可选)

插件自定义是否需要配置,有些插件无需配置参数。如

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        applicationId "com.example.router"
        minSdkVersion 29
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
复制代码

2.2 脚本插件的用法

在工程的根目录新建文件other.gradle,写上调试代码如

println("我是脚本插件的代码")
复制代码

在子工程build.gradle应用脚本插件

apply from: project.rootProject.file("other.gradle")
复制代码

三、Gradle二进制插件自定义

插件自定义包括三个步骤:建立插件工程、配置参数、发布插件与使用插件。

3.1 建立插件工程

复杂的或者需要被复用的构建逻辑可以被实现成为二进制插件,二进制插件开发形式可以有两种,一是实现成为普通的独立工程,调试时需要手动发布成Jar包给其他工程引用进行测试;二是实现成buildSrc工程,属于子工程,如果把插件的逻辑写在里面,在构建时Gradle会自动将它打包成一个二进制插件Jar包,更方便。

1)建立buildSrc子工程

建立普通工程如Router,在根目录下建立子工程buildSrc(Gradle约定必须以该名字命名),在该工程添加build.gradle文件来配置该工程。

用Gradle里面的groovy语言来实现该插件,需要依赖groovy插件编译groovy代码。声明将使用到的第三方包所属仓库。指定需要的第三方包。代码如下

//引用groovy插件,编译插件工程中的代码
apply plugin:'groovy'

//声明仓库的地址
repositories {
    jcenter()
}

//声明依赖的包
dependencies {
    implementation gradleApi()
    implementation localGroovy()
}
复制代码

2)建立插件运行入口

在buildSrc中建立源码目录,新建文件RouterPlugin.groovy,该类需要实现Plugin接口并实现apply方法,当我们采用apply关键字在工程中引用插件时,apply方法里的逻辑会被执行,可以在apply方法里注入插件的逻辑,如往工程里动态添加一个Task。代码如

package com.immoc.router.gradle

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

class RouterPlugin implements Plugin<Project> {
    //实现apply方法,注入插件的逻辑
    void apply(Project project) {
        println("I am from RouterPlugin, apply from ${project.name}")
    }
}
复制代码

在META-INF.gradle-plugins文件夹下新建properties文件,添加代码

implementation-class=com.immoc.router.gradle.RouterPlugin
复制代码

在app工程build.gradle应用插件如

apply plugin:'com.imooc.router'
复制代码

3.2 实现参数配置

Android打包配置即参数配置,在Gradle中有特定名称叫Extension。输入我们想要配置的数据,在插件中使用,最终打出具有对应属性的apk。

实现参数配置需要4个步骤:定义Extension、注册Extension、使用Extension、获取Extension。

1)定义Extension

在Plugin同级目录新建Extension.groovy文件,添加文档保存路径参数,如

package com.immoc.router.gradle

class RouterExtension {
    String wikiDir
}
复制代码

2)注册Extension

在Plugin子类的apply方法中注册Extension,代码如

package com.immoc.router.gradle

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

class RouterPlugin implements Plugin<Project> {
    //实现apply方法,注入插件的逻辑
    void apply(Project project) {
    
        //注册Extension
        project.getExtensions().create("router", RouterExtension)
    }
}
复制代码

3)使用Extension

在应用该插件的build.gradle文件中,使用Extension的代码放在apply该插件的后面,如给wikiDir传参,

apply plugin:'com.imooc.router'

router {
    wikiDir getRootDir().absolutePath
}
复制代码

4)获取Extension

gradle的生命周期在配置阶段会把gradle脚本即build.gradle里所有配置代码执行一遍,在配置阶段结束后能获取到相关配置,当Project的afterEvaluate方法执行后代表配置阶段结束,在这里获取配置,如代码,

package com.immoc.router.gradle

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

class RouterPlugin implements Plugin<Project> {
    //实现apply方法,注入插件的逻辑
    void apply(Project project) {
    
        //注册Extension
        project.getExtensions().create("router", RouterExtension)

        //获取Extension
        project.afterEvaluate {
            RouterExtension extension = project["router"]
        }
    }
}
复制代码

3.3 发布插件

由于该插件使用buildSrc子工程的形式,该插件在当前工程中可以直接使用。如果要给其他团队的开发者使用,就要将插件发布成二进制Jar包,可以发布到本地仓库和远程仓库。

以发布到本地仓库为例,发布插件到Maven仓库,需要调用maven插件,并配置来自Maven插件名为uploadArchives的Task,uploadArchives是一个Upload Task,用于上传发布我们的构件。在buildSrc的build.gradle文件中如下配置,

//调用maven插件,用于发布
apply plugin: 'maven'

//配置maven插件中的uploadArchives任务
uploadArchives {
    repositories {
        mavenDeployer{
        
            //设置发布路径为 工程根目录下面的 repo文件夹
            repository(url:uri('../repo')) {
                
                //设置groupId,通常为包名
                pom.groupId = 'com.imooc.router'

                //设置artifactId,为当前插件的名称
                pom.artifactId = 'router-gradle-plugin'

                //设置 插件的版本号
                pom.version = '1.0.0'
            }
        }
    }
}
复制代码

由于不能在buildSrc中发布,需要将buildSrc目录拷贝一份,更改名称如router-gradle-plugin,新工程注册到settings.gradle,如,

include ':app',':router-gradle-plugin'
复制代码

调用命令“gradlew :router-gradle-plugin:uploadArchives”进行发布。

3.4 在工程中应用插件

在工程中应用发布好的二进制插件,在该工程根目录build.gradle文件中buildscript和allprojects的repositories包下配置maven仓库地址,如

/*
 *1、配置maven仓库地址
 *这里可以时相对路径,也可以时绝对路径
 */
maven {
            url uri("D:\\Android Studio\\AndroidStudioProjects\\Router\\repo")
        }
复制代码

buildscript里的仓库主要是为了Gradle脚本自身的执行,用于获取脚本依赖的Gradle插件,比如Android Gradle Plugin等;allprojects里的仓库主要是用于下载项目本身需要的依赖,比如用到的Glide/OkHttp等。

然后告诉Gradle需要用仓库里的哪些插件,在buildscript的dependencies包下配置

/*
 *2、声明依赖的插件
 *形式是: groupId : artifactId : version
 */
classpath 'com.imooc.router:router-gradle-plugin:1.0.0'
复制代码

在需要应用插件的工程的模块的build.gradle文件中应用插件,并把参数传递给插件,如

/*
 *3、应用插件
 */
apply plugin:'com.imooc.router'

/*
 *4、向插件传递参数
 */
router {
    wikiDir getRootDir().absolutePath
}
复制代码
文章分类
Android
文章标签