Android Gradle 插件基础

本章跟大家一起探讨下 Gradle 基础知识:Project、Task和插件,由于是作为插桩的铺垫,所以我们重点放在 Gradle 插件 上,其他基础知识自行查阅。

Project(项目)

以咱们熟悉的 Android 项目举例说明:

通过 Android Studio 创建项目会自动生成两个模块,一个就是以项目名来命名的根模块(ASMInjectDemo),另外一个就是 app 模块。这两个模块都有 build.gradle 文件,我们知道每个 build.gradle 文件都代表一个 Project,所以按照这个说法就是两个 Project。其中, ASMInjectDemo 称之为 rootProject,项目 app 称为 subProject。

每一个 Project 会包含了一个或多个 Task。而 Task 一般被定义在 build.gradle 中,它表示一个操作,比如:复制文件、打个 jar 包、上传文件等等。

Task(任务)

什么是 Task?

Task(任务)表示 Gradle 构建过程中的单个原子操作,例如 rootProject 的 clean Task。每个任务都属于某个 Project,在 Project 中我们可以通过任务名或者 TaskContainer 来访问任务。

Gradle 构建生命周期

执行一个 Gradle 构建最简单的形式是执行一个 Task,而这些 Task 可能会依赖其他的Task。 Gradle 为了管理这些 Task 会在任何一个 Task 执行前构建一个 DAG 图(Directed Acyclic Graph,有向无环图)。这也就意味着所有的 Task 都会是一个接一个的执行且只执行一次。那些没有依赖的 Task 通常会优先执行。

Gradle 构建的生命周期分为三个阶段:

Gradle 插件

Gradle 本身提供基本的核心框架,其他的场景逻辑都可以通过插件扩展的方式来实现。对于 Android 开发来说,常用的插件就是 Android Gradle 插件和 Java 插件了。

插件的作用: Gradle 插件通常用来封装一些可重用的编译逻辑,可以用来扩展项目的功能,帮助项目构建中处理一些特殊的逻辑。

接下来,咱们主要讨论 Gradle 插件的基本知识和如何编写自定义的插件。

脚本插件

所谓脚本插件就是我们自定义的以 .gradle 为后缀的脚本文件,严格意义上说它只是一个可执行的脚本。应用它就是把整个脚本加载到 build.gradle 脚本中。这种场景非常简单不再赘述。

自定义插件

自定义插件的关键点在于要实现 org.gradle.api.Plugin 接口,重写其 apply 方法来实现自己的业务逻辑。

接下来看一个示例:

在 app 的 build.gradle 中添加下面代码:

/**
 * 定义一个Extension类用来接收脚本传的参数
 */
class CustomExtensionA {
    String extensionArgs = ""
}
/**
 * 自定义插件示例
 */
class CustomPluginA implements Plugin<Project> {

    @Override
    void apply(Project target) {
        //将Extension注册给Plugin
        def extension = target.extensions.create('customA', CustomExtensionA)
        //定义一个任务
        target.task('CustomPluginTaskA') {
            doLast {
                println "接收外部参数:${extension.extensionArgs}"
            }
        }

    }
}

其中为了从外部传给插件某些参数,我们可以定义一个类,并使用 Project.extensions.create 进行注册,这样外部就可以通过 customA 传入参数。
为了验证插件生效,我们创建一个自定义的 Task(CustomPluginTaskA)。

在 app 的 build.gradle 中应用插件:

//应用插件
apply plugin: CustomPluginA
//传入参数
customA.extensionArgs = "我是外部传入的参数"

同步代码之后会在 Gradle 的工具栏中出现 CustomPluginTaskA 任务,我们执行它试试:

终端输出如我们所料:

buildSrc 模块

我们可以在工程新建一个名为 buildSrc 的模块来开发自定义插件,编写过程与写 Android Library 类似。buildSrc 模块中的代码会自动被 Gradle 加载。

该模块的结构非常简单,只需要 src/main/groovy 目录来存放源码:

注意:只能使用 buildSrc 命名该模块

另外需要在 build.gradle 文件中添加 gradleApi 和 groovy 插件依赖。

apply plugin: 'groovy'

dependencies {
    //gradle sdk
    implementation gradleApi()
    //groovy sdk
    implementation localGroovy()
}

创建两个Groovy 文件 CustomPluginB.groovy 和CustomExtensionB.groovy。

跟上面自定义插件写法一样,只不过将代码写在了 groovy 文件中。

/**
 * 自定义插件
 */
class CustomPluginB implements Plugin<Project> {

    @Override
    void apply(Project project) {
        println "CustomPluginB Hello"
        //将Extension注册给Plugin
        def extension = project.extensions.create("customB", CustomExtensionB)
        //定义一个任务
        project.task('CustomPluginTaskB') {
            doLast {
                println "接收外部参数:${extension.extensionArgs}"
            }
        }
    }
}

在 app 的 build.gradle 中依赖插件

import com.lulu.customplugin.CustomPluginB
apply plugin: CustomPluginB
customB.extensionArgs = "customB 外部传入参数"

同样在 Gradle 工具栏中执行 CustomPluginTaskB
结果正常输出:

独立项目的自定义插件

上面的自定义插件虽然独立了模块,但是在不同项目中是不可复用的。

对于可重用的插件,一般会独立项目并发布成一个 jar,在不同的项目中引用。

跟 buildSrc 模块类似,我们创建任意名称的模块,特殊的是多了一个 resources 目录。

CustomExtensionC 和 CustomPluginC 的内容与上面提到的代码类似,不再贴出。

着重看下这个 properties 文件中的内容,其实只有一句话,它指向了咱们编写的插件类。

implementation-class = com.lulu.customplugin.CustomPluginC

而文件名表示的就是 插件 ID(Plugin ID)。

为了可以将其发布为 jar 包,需要在其 build.grdle 文件中做以下修改,添加 uploadArchives Task 发布到根目录下的 repo 文件夹:

apply plugin: 'groovy'
apply plugin: 'maven'
apply plugin: 'java'
apply plugin : 'maven-publish'

repositories {
    mavenCentral()
}
dependencies {
    //gradle sdk
    implementation gradleApi()
    //groovy sdk
    implementation localGroovy()
    //添加 gradle
    implementation 'com.android.tools.build:gradle:3.6.1'
}

group = 'com.lulu.customplugin'
version = "1.0.0"

//打包上传到本地
uploadArchives {
    repositories {
        flatDir {
            dirs '../repo/'
        }
    }
}

代码同步后,在 Gradle 工具栏中执行 uploadArchives,发布 jar 包,此时在根目录下将会生成 repo 文件夹:


一切准备好后,就可以在根目录下的 build.gradle 中添加仓库依赖地址:

allprojects {
    repositories {
        google()
        jcenter()
        flatDir {
            dirs './repo/'
        }
    }
}

之后添加插件依赖:

dependencies {
    //引入自定义插件
    classpath "com.lulu.customplugin:asmplugin:1.0.0"
}

在 app 模块中的 build.gradle 应用插件并传入额外参数,其中 plugin id 即为上面 properties 的文件名:

apply plugin: 'custom-plugin-demo'
customC.extensionArgs = "customC 外部传入参数"

同步代码,执行 Task,结果输出正常:

Demo 工程

Android 工程:https://github.com/changer0/ASMInjectDemo

以上就是本节内容,欢迎大家关注👇👇👇

长按关注

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值