• Android-AGP之手写你的第一款自定义plugin插件


    何为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.applicationcom.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呢?

    1. 将src/main下的目录全删除
    2. 将build.gradle文件内容删除,并添加两行
    apply plugin: 'groovy'
    apply plugin: 'kotlin'
    

    这里常用的DSL 语言有groovy或者kotlin,若只想用groovy开发插件,可不添加kotlin。本文主要以kotlin方式介绍写法。

    1. 在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是一个框架,帮你快速开发插件,在编译过程中修改字节码,它底层基于ASMGradle 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

  • 相关阅读:
    Android Jetpack架构组件库:Hilt
    知识产权维权全流程
    nlp实战——使用IMDB数据集做情感分析
    C语言结构体应用-通讯录
    使用FastAPI部署Ultralytics YOLOv5模型
    SparkSQL入门
    vue将日期数据转换成字符串
    Casein-PEG-Rhodamine B 络蛋白-聚乙二醇-罗丹明B Casein-RB
    python3-算法刷题-数组-滑动窗口-更新中
    关于#开发语言#的问题:接入jao(相关搜索:信号发生器)
  • 原文地址:https://blog.csdn.net/LucasXu01/article/details/127042995