Android Gradle插件开发

文章目录

    • 1. Gradle插件是什么
    • 2. 为什么需要插件
    • 3. 编写插件位置
    • 4. 编写插件
    • 5. 自定义插件扩展
      • 5.1 订阅扩展对象
      • 5.2 把扩展添加给Plugin并使用
      • 5.3 配置参数
      • 5.4 嵌套扩展
        • 5.4.1 定义扩展
        • 5.4.2 获取扩展属性
        • 5.4.3 使用
        • 5.4.4 执行
        • 5.4.5 输出
    • 6. 编写在单独项目里
      • 6.1 新建Module
      • 6.2 新建文件添加依赖
        • 6.2.1 添加依赖
        • 6.2.2 新建类
      • 6.3 本地发布
        • 6.3.1 Maven插件
        • 6.3.2 发布配置
        • 6.3.3 执行发布操作
      • 6.4 使用
      • 6.5 具体功能实现

1. Gradle插件是什么

Gradle插件(Plugin)是一种用于扩展和定制Gradle构建系统功能的机制。Gradle插件可以执行各种任务,包括编译代码、执行测试、打包文件、生成文档等等。插件可以访问和操作Gradle的构建模型,如项目、任务、依赖关系等等,从而实现对构建过程的控制和定制。
许多流行的工具和框架,例如Kotlin,Spring Boot,Android都有相应的Gradle插件。
比如熟悉的Android插件com.android.application

plugins {id 'com.android.application'
}

2. 为什么需要插件

  • 定制:如果需要在编译期做一些插桩,Hook之类的自定义操作,也需要用到编译插件
  • 封装:把具体的逻辑抽出去,只需运行插件,不需要写在某个build.gradle文件中
  • 复用:把通用的逻辑抽离出去,需要用的时候apply应用插件即可,不需要一遍遍的复制,也可以提供给别的项目使用

3. 编写插件位置

  • 写在build.gradle文件中,作用域当前project
  • 写在buildSrc里,作用域为当前项目所有
  • 写在单独项目里,发布后可提供给所有项目

4. 编写插件

编写一个插件Plugin,只需要实现Plugin接口,并实现唯一apply方法即可。
在build.gradle文件中

class YiRanPlugin implements Plugin<Project>{@Overridevoid apply(Project target) {println("this is plugin ${this.class.name}")}
}apply plugin: YiRanPlugin

apply方法是调用的PluginAware接口的apply()方法,参数是一个map,用来映射Plugin id

点击sync,输出结果
在这里插入图片描述
Task是Project里的方法,我们可以通过Project取创建一个Task,apply方法中提供了Project对象,可以通过Plugin去创建一个Task

class YiRanPlugin implements Plugin<Project>{@Overridevoid apply(Project target) {println("this is plugin ${this.class.name}")target.task("YiRanPluginTask"){task ->task.doLast{println("this is Plugin ${this.class.name},create a task ${task.name}")}}}
}apply plugin: YiRanPlugin

我们在Plugin里创建了一个Task,这时候sync是不会执行Task里面打印的东西,因为是doLast在 task 执⾏过程中被执⾏,发⽣在 execution 阶段。因此需要单独执行

./gradlew YiRanPluginTask    

输出

> Configure project :app
this is plugin YiRanPlugin> Task :app:YiRanPluginTask
this is Plugin YiRanPlugin,create a task YiRanPluginTask

当我们依赖YiRanPlugin插件的时候,这个apply就会把插件放到PluginContainer里,同时这个apply也是在编译阶段执行Plugin接口的apply()方法,所有sync同步后构建会有输出。

5. 自定义插件扩展

自定义插件的时候经常会有这种自定义配置的需求,通过自定义的配置可以让我们的插件提供更丰富的能力。这些配置就是通过扩展插件来的。

5.1 订阅扩展对象

可以是一个接口,也可以是一个类

interface YiRanPluginExtension{Property<String> getTitle()
}

5.2 把扩展添加给Plugin并使用

class YiRanPlugin implements Plugin<Project>{@Overridevoid apply(Project target) {println("this is plugin ${this.class.name}")def extension = target.extensions.create("YiRan",YiRanPluginExtension)target.task("YiRanPluginTask"){task ->task.doLast{println("this is Plugin ${this.class.name},create a task ${task.name}")println("-------")println(extension.title.get())}}}
}

target.extensions.create方法接收两个参数:

  • 1.名字,比如android,YiRan
  • 2.扩展对象,然后返回这个扩展对象,通过这个扩展对象的方法可以获取自定义的配置参数

5.3 配置参数

有两种方式可以写

YiRan.title = "YiRan"
YiRan{title = "YiRan"
}

如果没有设置配置参数的话,Gradle也提供了默认值的配置

extension.title.convention("YiRan")

5.4 嵌套扩展

向我们app目录下的build.gradle文件中,android{}里面还有defaultConfig{}

android {namespace 'com.example.gradlestudy'compileSdk 35defaultConfig {applicationId "com.example.gradlestudy"minSdk 24targetSdk 34versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}
}

嵌套扩展其实就是套娃

5.4.1 定义扩展
class YiRanPluginExtension{String titleint chapterNumSubExtension subExtensionYiRanPluginExtension(Project project){subExtension = project.extensions.create("sub",SubExtension.class)}
}class SubExtension{String author
}

增加定义了一个SubExtension类,然后在YiRanPluginExtension实例化的时候加到ExtensionContainer中。
类嵌套的话,不能写成内部类,不然编译识别不过。

5.4.2 获取扩展属性
class YiRanPlugin implements Plugin<Project>{@Overridevoid apply(Project target) {println("this is Plugin:${this.class.name}")def extension = target.extensions.create("YiRan",YiRanPluginExtension)target.task("YiRanTaskPluginTask"){ task ->task.doLast{println("this is Plugin ${this.class.name},create a task ${task.name}")println("title = ${extension.title}")println("chapter = ${extension.chapterNum}")println("author = ${extension.subExtension.author}")}}}
}

可以看到和上面的例子,少了Property对象的.get()方法,如果需要的话,在类对象定义即可,例如
增加setter/getter方法

class YiRanPluginExtension{String titleint chapterNumSubExtension subExtensionYiRanPluginExtension(Project project){subExtension = project.extensions.create("sub",SubExtension.class)}void setTitle(String name){title = name}String getTitle(){return title}
}

使用的时候

extension.setTitle("调用get方法")
extension.getTitle()
5.4.3 使用
YiRan{title = "测试一下"chapterNum = 100sub{author = "YiRan"}
}

闭包配置中多了一个sub{}的闭包,就是在YiRanPluginExtension类中定义的

5.4.4 执行
./gradlew YiRanTaskPluginTask       
5.4.5 输出

在这里插入图片描述

6. 编写在单独项目里

上面的例子,我们的Plugin是写在build.gradle文件中,而在实际项目中,为了复用,一般都是写在buildSrc或者单独项目中。
测试写一个打印项目中所有依赖的插件

6.1 新建Module

类型选择Library,或下面的Java or Kotlin Library
在这里插入图片描述

6.2 新建文件添加依赖

6.2.1 添加依赖

在plugin>build.gradle文件中依赖插件:

//java、gradleApi()依赖
apply plugin:'java-gradle-plugin'
//kotlin
apply plugin: 'org.jetbrains.kotlin.jvm'
6.2.2 新建类

新建一个DependenciesPlugin类
在这里插入图片描述

6.3 本地发布

6.3.1 Maven插件

在plugin>build.gradle文件中先依赖一个maven发布的插件’maven-publish’

apply plugin: 'maven-publish'dependencies {implementation 'com.android.tools.build:gradle:8.6.1'}
6.3.2 发布配置

添加发布配置


group 'com.example.plugin'
version '1.0.1'publishing {//配置Plugin GAVpublications {maven(MavenPublication){groupId = groupartifactId = 'dependencies'version = version}}//配置仓库地址repositories {maven {url layout.buildDirectory.dir("maven-repo")}}
}
6.3.3 执行发布操作
./gradlew publish

build文件夹下生成有本地发布配置的maven-repo文件夹
在这里插入图片描述

6.4 使用

1.settings.gradle文件中配置仓库地址

pluginManagement {repositories {// ...maven {url './plugin/build/maven-repo'}
}
}
dependencyResolutionManagement {repositories {// ...maven {url './plugin/build/maven-repo'}}
}

libs.versions.toml中添加插件依赖

[plugins]
//-----
dependencies = { id = "com.example.plugin.dependencies", version.ref = "dependencies" }

app目录build.gradle引入

plugins {
//------alias(libs.plugins.dependencies)
}

本地依赖使用的时候,要先发布,再依赖插件,否则就会出现cannot found找不到依赖的情况。
编译查看效果

> Configure project :app
---> com.example.plugin.DependenciesPlugin

能够正确打印

6.5 具体功能实现

上面只是一个打印,继续实现我们的功能,把所有的依赖打印出来。
打印依赖的方式有很多,比如可以使用Gradle命令

./gradlew app:dependencies

改造Plugin

package com.example.pluginimport com.android.build.gradle.AppExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ModuleVersionIdentifierclass DependenciesPlugin:Plugin<Project> {companion object{const val TAG = "DependenciesPlugin  >>>>>"}override fun apply(target: Project) {println("---> ${this.javaClass.name}")//获取扩展对象val extension:DependenciesPluginExtension = target.extensions.create("printDependencies",DependenciesPluginExtension::class.java)//配置阶段完成才能读取参数,才能拿到所有依赖target.afterEvaluate {extension.getEnable.convention(false)if(extension.getEnable.get()){println("$TAG 已开启依赖打印")val androidExtension:AppExtension = target.extensions.getByType(AppExtension::class.java)androidExtension.applicationVariants.all { applicationVariant->println("$TAG >>>>>> applicationVariant.getName() = ${applicationVariant.name}")val configuration:Configuration = applicationVariant.compileConfigurationval allDependencies:Set<Dependency> = configuration.allDependenciesval androidLibs = ArrayList<String>()val otherLibs = ArrayList<String>()configuration.resolvedConfiguration.lenientConfiguration.allModuleDependencies.forEach {resolvedDependency ->val identifier: ModuleVersionIdentifier = resolvedDependency.module.idif(identifier.group.contains("androidx")||identifier.group.contains("com.google")||identifier.group.contains("org.jetbrains")){androidLibs.add(identifier.group+":"+identifier.name+":"+identifier.version)}else{otherLibs.add(identifier.group+":"+identifier.name+":"+identifier.version)}}println("--------------官方库 start--------------");androidLibs.forEach(System.out::println);println("--------------官方库 end--------------");println("--------------三方库 start--------------");otherLibs.forEach(System.out::println);println("--------------三方库 end--------------");}}else{println("$TAG 已关闭依赖打印")}}}
}

project.afterEvaluate方法中去获取扩展配置,因为apply plugin的执行时机早于扩展配置,否则获取不到扩展配置的值
扩展:

package com.example.pluginimport org.gradle.api.provider.Propertyinterface DependenciesPluginExtension {val getEnable:Property<Boolean>}

使用:

printDependencies {setGetEnable(true)
}

编译输出:
在这里插入图片描述
通过独立项目中定义插件,把所有依赖的区分打印出来了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/77946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PPIO X OWL:一键开启任务自动化的高效革命

2024年&#xff0c;仅凭一PPIO X OWL&#xff1a;一键开启任务自动化的高效革命篇技术论文&#xff0c;OWL的Github仓库便在24小时斩获了15k Star&#xff0c;成为2024年增速最快的多智能体协作框架&#xff0c;重新定义了任务自动化的效率边界。Camel AI团队开源全栈方案&…

分布式事务,事务失效,TC事务协调者

1. 概述 本方案书旨在解决分布式系统中事务一致性问题&#xff0c;重点阐述全局事务标识&#xff08;XID&#xff09;的传递与存储机制、事务协调者&#xff08;TC&#xff09;的设计与部署&#xff0c;以及分布式事务失效场景的应对策略。基于业界成熟框架&#xff08;如Seat…

2025年“深圳杯”数学建模挑战赛D题-法医物证多人身份鉴定问题

法医物证多人身份鉴定问题 小驴数模 犯罪现场法医物证鉴定是关系到国家安全、公共安全、人民生命财产安全和社会稳定的重大问题。目前法医物证鉴定依赖DNA分析技术不断提升。DNA检验的核心是STR&#xff08;Short Tandem Repeat&#xff0c;短串联重复序列&#xff09;分析技术…

Mysql查询异常【Truncated incorrect INTEGER value】

文章目录 异常原因分析1、数据类型不一致2、数据长度超长3、数据格式要正确 处理方案模拟案例创建表数据查询 异常 在执行MySQL的语句时&#xff0c;在控制台报错如下所示。 Data truncation: Truncated incorrect INTEGER value 原因分析 1、数据类型不一致 必须要保证数据…

WPF性能优化举例

WPF性能优化集锦 一、UI渲染性能优化 1. 虚拟化技术 ​​ListView/GridView虚拟化​​: <ListView VirtualizingStackPanel.IsVirtualizing="True"VirtualizingStackPanel.VirtualizationMode="Recycling"ScrollViewer.IsDeferredScrollingEnabled=…

C# 面向对象实例演示

C# 面向对象编程实例演示 一、基础概念回顾 面向对象编程(OOP)的四大基本特性&#xff1a; ​​封装​​ - 将数据和操作数据的方法绑定在一起​​继承​​ - 创建新类时重用现有类的属性和方法​​多态​​ - 同一操作作用于不同对象产生不同结果​​抽象​​ - 简化复杂系…

大连理工大学选修课——机器学习笔记(3):KNN原理及应用

KNN原理及应用 机器学习方法的分类 基于概率统计的方法 K-近邻&#xff08;KNN&#xff09;贝叶斯模型最小均值距离最大熵模型条件随机场&#xff08;CRF&#xff09;隐马尔可夫模型&#xff08;HMM&#xff09; 基于判别式的方法 决策树&#xff08;DT&#xff09;感知机…

蒋新松:中国机器人之父

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 蒋新松:中国机器人之父 一、生平简介 1. 早年经历与求学道路 蒋新松出生于1931年8月3日,江苏省江阴澄北镇一个靠近长江的小镇。他的名字来源于杜…

表征(Representations)、嵌入(Embeddings)及潜空间(Latent space)

文章目录 1. 表征 (Representations)2. 嵌入 (Embeddings)3. 潜空间 (Latent Space)4. 关系总结5. 学习思考 1. 表征 (Representations) 定义: 表征是指数据的一种编码或描述形式。在机器学习和深度学习中&#xff0c;它特指模型在处理数据时&#xff0c;将原始输入数据转换成…

【STM32实物】基于STM32的RFID多卡识别语音播报系统设计

演示视频: 基于STM32的RFID多卡识别语音播报系统设计 前言:本项目可实现多个电子标签IC卡RFID识别,刷卡识别后进行中文语音播报反馈,同时进行控制对应的灯光开关。以此也可扩展开发更多功能。 本项目所需主要硬件包括:STM32F103C8T6最小系统板、RFID-RC522模块、五个IC电…

全面了解CSS语法 ! ! !

CSS&#xff08;层叠样式表&#xff09;是网页设计的灵魂之一&#xff0c;它赋予了网页活力与美感。无论是为一个简单的个人博客增添色彩&#xff0c;还是为复杂的企业网站设计布局&#xff0c;CSS都是不可或缺的工具。那么&#xff0c;CSS语法到底是什么样的呢&#xff1f;它背…

青少年抑郁症患者亚群结构和功能连接耦合的重构

目录 1 研究背景及目的 2 研究方法 2.1 数据来源与参与者 2.1.1 MDD患者&#xff1a; 2.1.2 健康对照组&#xff1a; 2.2 神经影像分析流程 2.2.1 图像采集与预处理&#xff1a; 2.2.2 网络构建&#xff1a; 2.2.3 区域结构-功能耦合&#xff08;SC-FC耦合&#xff09…

【QT】编写第一个 QT 程序 对象树 Qt 编程事项 内存泄露问题

目录 1. 编写第一个 QT 程序 1.1 使用 标签 实现 1.2 纯代码形式实现 1.3 使用 按钮 实现 1.3.1 图形化界面实现 1.3.2 纯代码形式实现 1.4 使用 编辑框 实现 1.4.1 图形化界面实现 1.4.2 纯代码形式实现 1.4.3 内存泄露 2. 认识对象模型&#xff08;对象树&…

在pycharm中创建Django项目并启动

Django介绍 Django 是一个基于 Python 的开源 Web 应用框架&#xff0c;采用了 MTV&#xff08;Model - Template - View&#xff09;软件设计模式 &#xff0c;由许多功能强大的组件组成&#xff0c;能够帮助开发者快速、高效地创建复杂的数据库驱动的 Web 应用程序。它具有以…

在Carla中构建自动驾驶:使用PID控制和ROS2进行路径跟踪

机器人软件开发什么是 P、PI 和 PID 控制器&#xff1f;比例 &#xff08;P&#xff09; 控制器比例积分 &#xff08;PI&#xff09; 控制器比例-积分-微分 &#xff08;PID&#xff09; 控制器横向控制简介CARLA ROS2 集成纵向控制横向控制关键要点结论引用 机器人软件开发 …

【KWDB 创作者计划】_深度解析KWDB存储引擎

文章目录 每日一句正能量引言一、存储引擎核心模块结构二、写前日志 WAL&#xff08;Write-Ahead Log&#xff09;三、列式压缩存储&#xff08;Columnar Compression&#xff09;四、索引机制与混合查询调度五、分布式核心功能&#xff1a;租约管理实战六、时间序列数据处理&a…

Apache Tomcat 漏洞(CVE-2025-24813)导致服务器面临 RCE 风险

CVE-2025-24813Apache Tomcat 中发现了一个严重安全漏洞,标识为,该漏洞可能导致服务器面临远程代码执行 (RCE)、信息泄露和数据损坏的风险。 此缺陷影响以下版本: Apache Tomcat11.0.0-M1通过11.0.2Apache Tomcat10.1.0-M1通过10.1.34Apache Tomcat9.0.0-M1通过9.0.98了解 …

全面解析SimHash算法:原理、对比与Spring Boot实践指南

一、SimHash算法概述 SimHash是一种局部敏感哈希算法&#xff0c;由Google工程师Moses Charikar提出&#xff0c;主要用于海量文本的快速去重与相似度检测。其核心思想是将高维特征向量映射为固定长度的二进制指纹&#xff08;如64位&#xff09;&#xff0c;通过计算指纹间的…

临床回归分析及AI推理

在医疗保健决策越来越受数据驱动的时代&#xff0c;回归分析已成为临床医生和研究人员最强大的工具之一。无论是预测结果、调整混杂因素、建模生存时间还是理解诊断性能&#xff0c;回归模型都为将原始数据转化为临床洞察提供了统计学基础。 AI推理 然而&#xff0c;随着技术…

西门子PLC S7-1200 电动机的软启动控制

1 PWM 控制的基本概念 PWM 是 PulseWidth Modulation 的简称。 PWM 控制是一种脉冲宽度调制技术,通过对一系列脉冲的宽度进行调制来等效获得所需要的波形(含形状和幅值)。PWM 控制技术在逆变电路中应用比较广泛,所应用的逆变电路绝大部分是PWM 型。除此之外, PWM 控制技术…