问题描述
引用一个本地开发的 gradle 插件时,一直找不到这个插件 ID,报错:
Caused by: org.gradle.api.plugins.UnknownPluginException: Plugin with id xxx found
前言
gradle 插件开发过程中,我们一般会先进行本地部署,通过本地依赖集成进行验证、调试。
其中一个很关键的环节就是,指定插件的 ID, 方便我们在使用插件的 module 中通过 apply plugin: '${}pluginId}' 的方式引入插件,比如我们平时见得比较多的插件 ID 有:com.android.application、com.android.library、java、maven、groovy 等。
如何声明 Gradle 插件 ID
那么这个插件 ID 是怎么指定的呢?
首先给出官方文档 Example: Wiring for a custom plugin
大意如下:
参考文件:src/main/resources/META-INF/gradle-plugins/org.samples.greeting.properties
implementation-class=org.gradle.GreetingPlugin
属性文件名(org.samples.greeting)与插件 ID(org.samples.greeting) 相匹配,放置在 resources 目录下,其中 implementation-class 属性指向插件的实现类(org.gradle.GreetingPlugin)
简单概括下来就是以下几步:
在 src/main 目录下新建resources/META-INF/gradle-plugins目录
目录里面创建一个${pluginId}.properties 文件(${pluginId} 为要指定的插件 ID)
文件内添加一行内容:implementation-class=xxx.xxx.xxx.xxxPlugin(其中 xxx.xxx.xxx.xxxPlugin 指向实际的插件实现类,即实现了Plugin<Project> 接口的类)
插件 ID 的命名
这个插件 ID 怎么命名呢?有些人喜欢用一个简单的单词,有些人喜欢用一个包名,当然这个是不受限制的,参考前面给的常见的 ID,个人觉得只要是一个合法的文件名应该都可以(此处未考究,欢迎大佬给出官方链接)吧,按个人喜好或者公司统一规定来定即可。
问题复现情景
插件写完了,配置也弄好了,开始本地部署与调试了。
正常情况下按照以上步骤来,应该问题不大。
复现背景
但有的时候,相信肯定有很多人和我一样,学习 gradle 插件开发并非从阅读官方文档开始的,要么从网上看到一篇文章就开始着手开发,要么从 GitHub 上找到一份有意思的 gradle 插件的代码,突发奇想,将其 clone 下来改造改造就成了自己的插件了…
问题复现
这么下来,我们就很容易遇到本文提到的这个坑了:应用插件时找不到我们部署好的插件,报错如下:Caused by: org.gradle.api.plugins.UnknownPluginException: Plugin with id xxx found(这里得 xxx 就是 apply plugin 后面给的插件 ID)
复现场景
比如我 clone 一份代码并打开后,显示如下:
没看过文档的我也知道这个 rcplugin 跟 app module 的 build.gradle 中 apply plugin: 'rcplugin' 里的 rcplugin是一一对应的
不假思索的在自己工程里面依次新建:resources/META-INF.gradle-plugins(踩坑点) 目录,新建一个 myplugin.properties 文件,添加一行内容…
在自己工程的 app module 的 build.gradle 中 apply plugin: ‘xxx’
点击 AS 的 Sync Now 后报错:Caused by: org.gradle.api.plugins.UnknownPluginException: Plugin with id xxx found
Why ?Wtf!!!
问题分析
遇到这个问题,你无论怎么比对两个地方的插件 ID 是否匹配,瞪大眼睛,放大 10 倍也找不出问题来。其实这个坑源自一个小小的细节问题,算是 AS 的一个坑吧,也可以说是个人的不细心导致。
要说是 AS 的坑,其实是 AS 的一个小功能:目录合并折叠(姑且这么叫吧)功能
描述:
AS Project 导航栏视图下,一些常见的目录,如:java、groovy、kotlin、resources 目录下的多级目录(一般包名居多),如果中间某个目录下只有文件夹、没有文件时,AS 会将其用 “.” 号分隔,合并显示,如com/android/library 三级目录显示成com.android.library,上面的META-INF/gradle-plugins显示成META-INF.gradle-plugins。
好处:
这么做自然有其好处,比如包名层级比较多的时候,多级目录显示成一级目录,一次点击就可以展开到包含文件或者包含多个目录的那一层,方便我们快速定位目标层级
坏处:
除了视觉上的误导之外,如果我想在一个多层包名中间新建一个文件,比如在com/android/library 这个目录上右键新建文件,我无法创建 com.android.MyClass 这个文件,常规做法要么去文件夹下新建一个空白文件然后重命名,要么在 library 目录下新建好文件后,使用 AS 的功能键Refactor>Move Class...来重命名操作,着实不方便
解决思路
所以遇到UnknownPluginException这个异常时,按照以下几步仔细检查一下
检查resources/META-INF/gradle-plugins目录 properties 文件名与 apply plugin 引用的插件 ID是否匹配
注意检查一下目录的层级是否正确,比如在本地文件管理器里面打开一下这个目录看看层级,或者用 tree 命令(附菜鸟教程Linux tree命令)试试
或者找一个正确的插件,将其 整个resources 目录拷贝到本项目的src/main目录下,对比看看有什么差异(笔者就是这个方式找到问题所在)
插件 ID 的配置(重复、详细)
这里再重复一下 插件 ID 的配置以加深印象
目录结构:resources\META-INF\gradle-plugins${pluginId}.properties
目录树如下:
└─resources
└─META-INF
└─gradle-plugins
${pluginId}.properties
注: META-INF 与 gradle-plugins 是两级目录,不是 META-INF.gradle-plugins 目录
示例如下:
看着是不是很奇怪,“两个完全一样的目录”为啥不合并呢?其实前者是两级目录META-INF/gradle-plugins,后者是一级目录META-INF.gradle-plugins,目录树如下:
└─resources
├─META-INF
│ └─gradle-plugins
│ hooklib.properties // √ 正确
└─META-INF.gradle-plugins
hooklib.properties // × 错误
————————————————
原文链接:https://blog.csdn.net/lxzh12345/article/details/114531089
关注我获取更多知识或者投稿