gradle 插件开发踩坑记,应用插件时总是报 UnknownPluginException 异常

  • 问题描述
  • 前言
  • 如何声明 Gradle 插件 ID
  • 插件 ID 的命名
  • 问题复现情景
    • 复现背景
    • 问题复现
    • 复现场景
    • 问题分析
    • 解决思路
  • 插件 ID 的配置(重复、详细)

问题描述

引用一个本地开发的 gradle 插件时,一直找不到这个插件 ID,报错:

Caused by: org.gradle.api.plugins.UnknownPluginException: Plugin with id xxx found

前言

gradle 插件开发过程中,我们一般会先进行本地部署,通过本地依赖集成进行验证、调试。

其中一个很关键的环节就是,指定插件的 ID, 方便我们在使用插件的 module 中通过 apply plugin: '${}pluginId}' 的方式引入插件,比如我们平时见得比较多的插件 ID 有:com.android.applicationcom.android.libraryjavamavengroovy 等。

如何声明 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)

简单概括下来就是以下几步:

  1. 在 src/main 目录下新建resources/META-INF/gradle-plugins目录
  2. 目录里面创建一个${pluginId}.properties 文件(${pluginId} 为要指定的插件 ID)
  3. 文件内添加一行内容:implementation-class=xxx.xxx.xxx.xxxPlugin(其中 xxx.xxx.xxx.xxxPlugin 指向实际的插件实现类,即实现了Plugin 接口的类)

插件 ID 的命名

这个插件 ID 怎么命名呢?有些人喜欢用一个简单的单词,有些人喜欢用一个包名,当然这个是不受限制的,参考前面给的常见的 ID,个人觉得只要是一个合法的文件名应该都可以(此处未考究,欢迎大佬给出官方链接)吧,按个人喜好或者公司统一规定来定即可。

问题复现情景

插件写完了,配置也弄好了,开始本地部署与调试了。

正常情况下按照以上步骤来,应该问题不大。

复现背景

但有的时候,相信肯定有很多人和我一样,学习 gradle 插件开发并非从阅读官方文档开始的,要么从网上看到一篇文章就开始着手开发,要么从 GitHub 上找到一份有意思的 gradle 插件的代码,突发奇想,将其 clone 下来改造改造就成了自己的插件了…

问题复现

这么下来,我们就很容易遇到本文提到的这个坑了:应用插件时找不到我们部署好的插件,报错如下:Caused by: org.gradle.api.plugins.UnknownPluginException: Plugin with id xxx found(这里得 xxx 就是 apply plugin 后面给的插件 ID)

复现场景

  1. 比如我 clone 一份代码并打开后,显示如下:
    gradle 插件开发踩坑记,应用插件时总是报 UnknownPluginException 异常_第1张图片
  2. 没看过文档的我也知道这个 rcplugin 跟 app module 的 build.gradle 中 apply plugin: 'rcplugin' 里的 rcplugin是一一对应的
  3. 不假思索的在自己工程里面依次新建:resources/META-INF.gradle-plugins(踩坑点) 目录,新建一个 myplugin.properties 文件,添加一行内容…
  4. 在自己工程的 app module 的 build.gradle 中 apply plugin: ‘xxx’
  5. 点击 AS 的 Sync Now 后报错:Caused by: org.gradle.api.plugins.UnknownPluginException: Plugin with id xxx found

Why ?Wtf!!!

问题分析

遇到这个问题,你无论怎么比对两个地方的插件 ID 是否匹配,瞪大眼睛,放大 10 倍也找不出问题来。其实这个坑源自一个小小的细节问题,算是 AS 的一个坑吧,也可以说是个人的不细心导致。

要说是 AS 的坑,其实是 AS 的一个小功能: 目录合并折叠(姑且这么叫吧)功能

  • 描述:

AS Project 导航栏视图下,一些常见的目录,如:javagroovykotlinresources 目录下的多级目录(一般包名居多),如果中间某个目录下只有文件夹、没有文件时,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这个异常时,按照以下几步仔细检查一下

  1. 检查resources/META-INF/gradle-plugins目录 properties 文件名与 apply plugin 引用的插件 ID是否匹配
  2. 注意检查一下目录的层级是否正确,比如在本地文件管理器里面打开一下这个目录看看层级,或者用 tree 命令(附菜鸟教程Linux tree命令)试试
  3. 或者找一个正确的插件,将其 整个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 目录

  • 示例如下:
    gradle 插件开发踩坑记,应用插件时总是报 UnknownPluginException 异常_第2张图片
    看着是不是很奇怪,“两个完全一样的目录”为啥不合并呢?其实前者是两级目录META-INF/gradle-plugins,后者是一级目录META-INF.gradle-plugins,目录树如下:
└─resources
    ├─META-INF
    │  └─gradle-plugins
    │          hooklib.properties  // √ 正确
    └─META-INF.gradle-plugins
            hooklib.properties     // × 错误

你可能感兴趣的:(Android,Gradle-Plugin,gradle,gradle-plugin)