何为Android Gradle Plugin(AGP)
在 Android 项目中的 build.gradle 文件中,经常可以看见一些 plugin 声明如:
plugins {
id 'com.android.application'
id 'com.android.library'
}
// or
apply plugin: 'com.android.application'
apply plugin: 'com.android.library'
其实com.android.application
和com.android.library
就是两种常引用的 gradle 插件。com.android.application
是用来构建 apk 的 gradle 插件;com.android.library
是用来构建 Android Library 的 gradle 插件。
Gradle 作为 Android 官方推荐的构建工具,可以灵活的管理依赖与构建过程,同时提供了强大的插件体系,可以很方便的自定义插件以实现各种自定义的扩展功能。
何为Gradle
Gradle 是为多项目构建而设计的自动化构建工具。主要通过 groovy 或 kotlin 来编写构建脚本。
主要用来处理:
- 自动处理包依赖关系
- 自动处理部署问题
过去 Java 开发者常用 Maven 和 Ant 等工具进行封装布署的自动化,或是两者兼用,不过这两个包彼此有优缺点:
如果频繁改变相依包版本,使用 Ant 相当麻烦;如果琐碎工作很多,Maven 功能不足;而且两者都使用 XML 描述,相当不利于设计 if、switch 等判断式,即使写了可读性也不佳;而 Gradle 改良了过去 Maven、Ant 带给开发者的问题,成为 Android Studio 内置的构建工具。
官方文档:What is Gradle?
手写你的Gradle插件
新建plugin module
新建Gradle插件需要县新建一个普通的Android Library Module,再手动修改成gradle plugin module。
如何将Android Library修改成Gradle Plugin Library呢?
- 将src/main下的目录全删除
- 将build.gradle文件内容删除,并添加两行
apply plugin: 'groovy'
apply plugin: 'kotlin'
这里常用的DSL 语言有groovy或者kotlin,若只想用groovy开发插件,可不添加kotlin。本文主要以kotlin方式介绍写法。
- 在src/main下新建两个目录:kotlin和resources/META-INF/gradle-plugins
kotlin下放的是源代码,resources下是资源文件。(注意:采用groovy方式写plugin,此处第一个目录写成groovy)
这样就完成了module的改造。改造后的工程目录结构:
自定义Gradle Plugin
在pluginlib中的build.gradle中添加依赖:
//gradle 开发 sdk 依赖
dependencies {
implementation gradleApi()
implementation localGroovy()
//noinspection GradleDependency
implementation 'org.ow2.asm:asm:7.1'
//noinspection GradleDependency
implementation 'org.ow2.asm:asm-util:7.1'
//noinspection GradleDependency
implementation 'org.ow2.asm:asm-commons:7.1'
implementation 'com.android.tools.build:gradle:4.1.3'
implementation 'cn.quinnchen.hunter:hunter-transform:1.2.1'
}
重要的是gradleApi()
和localGroovy()
,下面的几行是该plugin项目中引用到的几个关于项目的依赖。
接着,在src/main/groovy下新建包名(比如com.lucas.networkviewer),至此,可以再该目录下写自己的plugin插件的相关逻辑代码了。
继承Plugin类
插件类必须实现Plugin接口,并重写apply方法:
groovy版本:
package com.lucas.networkviewer.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
public class MonitorPlugin implements Plugin<Project>{
void apply(Project project){
//这里写自定义插件实现逻辑
}
}
kotlin版本:
package com.lucas.networkviewer.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
class MonitorPlugin : Plugin<Project> {
override fun apply(project: Project) {
//这里写自定义插件实现逻辑
}
}
apply方法是在apply plugin: '插件名称'
这行脚本执行的时候调用。
插件实现代码如下:
package com.lucas.networkviewer.plugin
import com.android.build.gradle.AppExtension
import com.lucas.networkviewer.okhttp.OkHttpTransform
import org.gradle.api.Plugin
import org.gradle.api.Project
import java.util.*
class MonitorPlugin : Plugin<Project> {
override fun apply(project: Project) {
...
try {
val appException: AppExtension = project.extensions.getByName("android") as AppExtension
appException.registerTransform(OkHttpTransform(project))
} catch (e: Exception) {
e.printStackTrace()
}
}
}
这里利用registerTransform()
注册了一个transform方法,它基于hunter库,实现了对okhttp网络请求的获取打印,从而实现了我们插件无缝感知任意网络请求参数的功能;详细内容可参考**NetworkViewer**,本篇仅基于该库介绍AGP的写法。
Hunter是一个框架,帮你快速开发插件,在编译过程中修改字节码,它底层基于ASM 和 Gradle Transform API 实现。仓库地址:https://github.com/Leaking/Hunter
定义插件名称
在使用插件的module中,需要在build.gradle中添加
apply plugin: '插件名称'
因此需要给我们的自定义插件定义一个名称。如何定义插件名称?
在src/main/resources/META-INF/gradle-plugins下面新建一个properties文件,文件名称就是我们的插件名称,比如monitor-plugin.properties,插件名称就是"monitor-plugin"。
文件内容中指定插件类的路径:
implementation-class=com.lucas.networkviewer.plugin.MonitorPlugin
至此,自定义插件的过程就完了。
插件上传
将插件打包出来就需要写上传代码。可以上传到本地仓库,或者远程仓库。两种方式只是上传地址不同。最终形成的插件包是一个jar文件。
参考文章
https://blog.csdn.net/m0_56144365/article/details/125154748
https://juejin.cn/post/7119083753376317448