ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Intellij IDEA插件开发实战:从零搭建工程到第一个Action

Intellij IDEA插件开发实战:从零搭建工程到第一个Action 简介面向 JetBrains IntelliJ 平台插件开发者的中文手册上册基于 17.0.9 Runtime 编写适配 IntelliJ IDEA 2023 及以上并兼容 2024 版本。内容聚焦插件开发基础与图形化插件开发两大模块前者覆盖术语解析、开发环境要求、插件功能与开发流程后者引导读者从零构建工程、配置界面元素、注册动作并完成本地测试适合有意编写框架集成、代码统计、效率工具等 UI 型插件的开发者系统入门。资源以单个 PDF 文档提供整体压缩包大小 15.82MB共 1 个文件。目前已有 382 人浏览学习。手册在官方指引、个人实践与社区资料基础上整理附有清晰的目录、参考网站与开发建议能帮助读者快速定位知识点同时规避常见的工程配置与调试问题本册作为系列上册后续下册与附录则进一步覆盖语言类插件与工具清单适合开发者按阶段选读。 写这篇东西之前先说句实在话市面上的 IDEA 插件开发资料要么是官方文档那种“信息密度极高但把人劝退”的英文原版要么是零散的技术博客讲 A 不讲 B看完还是一头雾水。我早年在做内部工具链的时候啃过不少官方源码和社区帖子后来自己也维护过两个公司内部插件踩了一堆坑才把整个开发链路摸顺。这份《Intellij Platform PlugIn 插件开发手册(上)》正是我整理的第一批内容面向刚接触 IDEA 插件开发的 Java 工程师和工具链开发者。它解决的核心问题是怎么从零搭建一个插件工程、理解插件运行模型、写出第一个能跑的 Action以及避开新手期最容易踩的坑。如果你之前看过官方文档但觉得入门有门槛或者准备给团队做效率工具但不知道从哪下手这篇内容应该能帮你省下不少时间。1. 为什么想不开要开发 IDEA 插件先搞懂这本手册到底在讲什么1.1 插件开发的价值与典型场景很多人一想到写插件第一反应是“我又不开发 IDE学这个干嘛”。但实际工作中插件开发的价值非常明确它能把你重复劳动一百遍的操作压缩成一次点击。我举几个实际场景。比如你们团队有统一的代码规范每次提交前要检查格式、跑静态扫描、生成文件头注释——如果没有插件这些步骤全靠人工记漏一步就得返工。再比如你们有一套内部框架对象之间有固定的依赖注入关系手写容易漏用插件一键生成模板代码错误率直接下降一个量级。还有更常见的每次新建模块要手动配一堆 XML 文件费时费力还容易配错写一个自定义 New Project Wizard 插件所有模板统一生成团队上手成本立刻降低。当然做 IDEA 插件不只能做内部工具。很多知名开源项目本身就是 IntelliJ 平台上的插件比如 Lombok 插件、MyBatis 插件、各种语言支持插件。它们解决的是泛化需求而内部插件解决的是团队专属需求。两者技术栈完全一样只是应用场景不同。1.2 手册(上)的知识覆盖范围这份手册为什么叫“上”因为完整的内容分成两部分。上册聚焦入门到能独立开发简单插件的全过程下册才深入到较底层的机制和大规模扩展点。具体来说上册覆盖这几块核心内容IDEA 插件的整体架构和插件运行模型——搞清楚插件到底运行在什么环境里哪些能力可以动哪些不能动。开发环境搭建从安装 IDEA 到配置 IntelliJ Platform SDK、Gradle 插件再到第一个工程的创建。插件描述文件 plugin.xml 的结构与扩展点注册方式。动作系统ActionSystem这是插件开发最基础也最常用的扩展点负责往菜单栏、工具栏、快捷键绑定里加功能。简单 UI 界面Tool Window、Dialog的创建方式。这套路线走完你能做出一个可以安装到 IDEA 里、带界面、有交互逻辑、能响应菜单点击的插件。下限是“能跑”上限是“能支撑一个真实需求”。2. 环境准备开发插件前必须搞定的三件事2.1 安装 IDEA 对应的 SDK 与插件开发环境做插件开发先明确一个大前提**你不是在写一个普通 Java 工程而是在写一个被 IntelliJ 平台加载的模块。**所以开发环境的配置和常规 Java 工程不太一样。第一件事安装 IntelliJ IDEA。社区版就能开发插件但如果你要调试插件在 IDE 内部的运行情况建议直接使用旗舰版Ultimate它自带的插件开发支持更完整。装好后进入Settings → Plugins搜索 “Plugin DevKit”把这个插件装上。它是官方提供的插件开发工具包能帮你识别模块类型、生成 plugin.xml 骨架、提供运行插件调试配置。这里有个容易忽略的细节**Plugin DevKit 不是一个普通意义上的功能插件它是 IDEA 开发插件时的“元工具”。**装好之后你新建项目时才会出现 “IntelliJ Platform Plugin” 这个模块类型。如果没有它后面所有步骤都无从谈起。2.2 配置 Gradle 构建插件早期插件开发用 DevKit 直接建工程但现在的官方推荐方式已经转向 Gradle。使用 Gradle 的好处是依赖管理更清晰构建产物可控还能方便地集成 CI 流程。新建项目时模块类型选择 “IntelliJ Platform Plugin”IDEA 会自动生成一个基于 Gradle 的插件工程里面带有官方维护的 Gradle 插件。这个插件会根据你在 build.gradle 中声明的配置拉取对应版本的 IntelliJ Platform 依赖并打包出可安装的 zip 包。build.gradle 里的核心配置长这样工程生成后可以对照着看plugins { id java id org.jetbrains.intellij version 1.17.3 } group com.example version 1.0.0 repositories { mavenCentral() } dependencies { testImplementation junit:junit:4.13.2 } // 配置 IntelliJ Platform 版本 intellij { version 2023.2.5 type IC // IC 表示社区版IU 表示旗舰版 plugins [] } patchPluginXml { sinceBuild 232 untilBuild 242.* }这段配置里的intellij扩展块是理解和调整的重点。version指定编译插件时依赖的 IDE 版本type指定是社区版还是旗舰版plugins里可以声明插件依赖。如果你要基于某个开源插件做二次开发那就在这个数组里加上对应插件 ID。第一次同步 Gradle 依赖时会比较慢因为需要下载 IntelliJ Platform 的完整依赖包大小可能有好几百兆。这属于正常现象耐心等就行。2.3 如何选择 IntelliJ Platform 版本版本选择这个坑我见太多人踩过。有人图新直接用 2024.1 的 SDK 开发结果打出来的插件装到客户机器的 2022.3 上直接报Incompatible Plugin。有人图稳一直用 2019 的版本结果新版 API 完全没有。正确逻辑是**先明确目标用户用的是什么版本的 IDEA再决定 SDK 版本。**比如你团队统一用的是 2023.2那插件开发就用 2023.2 版本sinceBuild和untilBuild也按这个范围设定。sinceBuild表示这个插件最低支持到哪个 IDE 版本untilBuild表示最高支持到哪个版本。如果untilBuild范围太窄用户升级 IDE 后插件可能无法加载。另外一个实用建议开发期间用一个主要版本来调发布前在旧版本和新版本的 IDE 里各装一次测试。API 兼容性不是靠嘴说而是靠实际验证的。高级一点的做法是用untilBuild *即不限制最高版本但这会让你承担未来 API 变更导致插件报错的风险我还是建议设一个明确的上限。3. 第一个插件从新建项目到跑通 Action3.1 创建插件工程的核心参数环境搞定后就开始创建工程。在新建项目界面选择 “IntelliJ Platform Plugin” 模块类型后有几个参数需要认真填写因为它们直接影响后续开发和调试。Project SDK选 JDK 17 或更高。新版 IntelliJ Platform 已经对 JDK 版本有硬性要求低版本的 JDK 编译插件会报错。IntelliJ Platform选你 IDE 自带的那份 SDK 即可也可以手动指定。Plugin name这是插件展示给用户的名字建议起得语义化比如 “Company Code Helper”。Plugin ID这是插件的唯一标识相当于身份证不能与其他插件冲突。官方推荐使用公司域名反写比如com.yourcompany.plugin。生成工程后你会看到一项看似无关紧要但其实很重要的文件META-INF/plugin.xml。这个文件是整个插件的“总纲”。3.2 理解 plugin.xml插件的地基插件开发里有一句老话**不懂 plugin.xml就不算入门。**这个文件描述了插件的元信息和所有扩展点声明。IDEA 启动时扫描插件包就是靠这个文件来决定加载哪些类、注册哪些功能。一个最小可用的 plugin.xml 长这样idea-plugin idcom.yourcompany.plugin/id nameCompany Code Helper/name vendor emaildevcompany.com urlhttps://company.comCompany Name/vendor description![CDATA[ This plugin helps developers generate boilerplate code quickly. ]]/description dependscom.intellij.modules.platform/depends extensions defaultExtensionNscom.intellij !-- 在这里声明插件扩展点 -- /extensions actions !-- 在这里注册动作 -- /actions /idea-plugin几个要点单拎出来说depends声明这个插件依赖哪些模块。最少要依赖com.intellij.modules.platform如果要支持 Java 开发还得加com.intellij.modules.java。漏掉这个依赖插件在某些 IDEA 发行版里可能无法加载。extensions声明这个插件向 IDE 注册的各种扩展点比如语言支持、代码检查、工具窗口等。actions声明菜单动作。plugin.xml的坑主要在命名空间上。你写扩展点时的defaultExtensionNs必须对应实际扩展点的命名空间否则运行时直接报 “Cannot find extension point” 的错误。我建议新手在刚接触时不要硬记扩展点名称而是多用官方提供的代码补全功能IDEA 会弹出合法的扩展点列表。3.3 编写并调试第一个 ActionAction 是大部分插件的入口它的作用就是“用户点了菜单里的一项我的代码开始执行”。创建 Action 的方式非常简单在代码目录中新建一个类继承AnAction重写actionPerformed方法。一个最简单的 Demo 可以这样写public class HelloAction extends AnAction { Override public void actionPerformed(NotNull AnActionEvent e) { Project project e.getProject(); if (project ! null) { Messages.showInfoMessage(project, Hello from my plugin!, Tip); } } }这段代码执行时会在当前项目窗口弹出一个信息提示框。看起来不起眼但它完整跑通了“用户触发动作 → 插件代码执行 → 与 IDE 交互”的链路。Action 写好后需要在 plugin.xml 中注册actions action idcom.yourcompany.plugin.HelloAction classcom.yourcompany.plugin.HelloAction textSay Hello descriptionShow a greeting message add-to-group group-idToolsMenu anchorlast/ /action /actions这里值得等下再解释的是add-to-group。它决定你的动作出现在哪个菜单里。IDEA 的菜单系统按组划分ToolsMenu是 “Tools” 菜单MainMenu是主菜单栏EditorPopupMenu是编辑器右键菜单。两者关系可以这样理解菜单栏是一栋楼每个菜单是一个房间Action 是房间里的一件家具。你不用重新盖楼只需要选好房间、摆好家具。调试插件的方法比较特别不是直接运行 main 方法而是通过runIde这个 Gradle 任务启动一个全新的 IDE 实例。这个实例会加载你的插件你可以在这个实例里点菜单、测功能、打断点调试。调试时建议用 IDEA 的Debug模式启动调试配置而不是Run否则无法命中断点。4. 核心 API 与界面扩展入门4.1 ActionSystem 使用要点Action 不只是往菜单里加个按钮那么简单它还承担着“感知 IDE 上下文状态”的任务。比如你要做一个“给当前打开的文件生成代码”的功能那你就得知道用户当前打开了哪个文件这个信息都在AnActionEvent里。获取当前上下文的标准写法是Override public void actionPerformed(NotNull AnActionEvent e) { Editor editor e.getData(CommonDataKeys.EDITOR); if (editor ! null) { CaretModel caretModel editor.getCaretModel(); String selectedText caretModel.getSelectedText(); if (selectedText ! null) { // 对选中的文本做处理 } } }这里的关键在e.getData()。AnActionEvent的内部数据是理解 IDE 上下文的钥匙你可以拿到编辑器实例、文件对象、项目对象等。CommonDataKeys类中定义了常用的数据键拿到哪个键取决于当前的环境。另外还有个新手容易忽略的点Action 最好重写update方法来控制可用状态。比如你的动作只在选中文本时才有意义那在update里根据是否有选中文本调用e.getPresentation().setEnabled(...)或setVisible(...)这样用户在菜单里看到的就是灰色不可点击状态体验更好。我刚接触 Action 时踩过一个坑以为setEnabled一次就行了结果发现菜单重复启用禁用需要每次更新。后来才明白update方法在菜单展示前会被反复调用这就是它的设计目的。4.2 搭建一个简单的 Tool WindowTool Window 就是 IDEA 左侧/右侧/底部的工具面板比如自带的 “Project”、“Structure”、“Terminal” 面板。做插件时如果功能需要持续展示数据或随时操作通常就要做一个 Tool Window。注册 Tool Window 的方式有两种写代码和声明扩展点。**声明扩展点是最简单的路径**在 plugin.xml 里添加extensions defaultExtensionNscom.intellij toolWindow idMyToolWindow icon/icons/logo.svg anchorright factoryClasscom.yourcompany.plugin.MyToolWindowFactory/ /extensions接着实现ToolWindowFactory接口public class MyToolWindowFactory implements ToolWindowFactory { Override public void createToolWindowContent(NotNull Project project, NotNull ToolWindow toolWindow) { JBPanel panel new JBPanel(new BorderLayout()); JLabel label new JLabel(This is my tool window content.); panel.add(label, BorderLayout.CENTER); toolWindow.getContentManager().addContent( ContentFactory.getInstance().createContent(panel, My Tab, false) ); } }这里有两个容易出错的点。一个是createToolWindowContent方法里创建的 UI 组件必须是 Swing 组件不能用 JavaFX 或其他 UI 框架。另一个是ContentManager和ContentFactory的概念——ToolWindow 可以包含多个 Tab每个 Tab 是一个 Content你需要把内容包成 Content 再添加进去。Tool Window 开发时还有一个小技巧可以继承ToolWindowFactory接口的可选方法init在窗口打开前做初始化工作比如加载配置、检查环境。4.3 持久化配置的三种方式插件如果有设置项比如用户可以选择插件启动时做什么、颜色是什么就需要持久化。IntelliJ 平台上做配置持久化主要有三种方式每种适用的场景不同我建议按需选择。第一种是PropertiesComponent适合保存少量键值对。它只能存字符串用起来最糙但也最直接PropertiesComponent.getInstance().setValue(myKey, myValue); String value PropertiesComponent.getInstance().getValue(myKey);注意这个类有两种绑定方式绑定到项目或绑定到全局。开发时最好想清楚你要存的是项目级别的数据比如每个项目不同还是全局级别的数据比如用户偏好。第二种是实现PersistentStateComponent接口适合保存结构化数据比如一个包含多个字段的配置对象public class MySettings implements PersistentStateComponentMySettings.State { public static class State { public String serverUrl http://localhost:8080; public boolean enableCache true; } private State state new State(); Override public State getState() { return state; } Override public void loadState(NotNull State state) { this.state state; } }PersistentStateComponent是官方推荐的配置持久化方式数据会被序列化成 XML 存到工程或全局配置目录中。它支持自定义序列化器但多数场景下默认的 XML 序列化就够用了。第三种是官方提供的Settings UI集成即你在Settings里创建一个配置页。这种方式和二配合使用用户在设置界面改配置插件程序读配置体验最完整但写起来最繁琐下册再展开讲。5. 常见问题与排查技巧实录5.1 插件市场刷新不出来的处理思路“IDEA 的 Plugin 市场刷新不出来”是我在开发过程中听到最多的问题也困扰过我很多次。现象是打开Settings → Plugins → Marketplace页面一直转圈或提示丢失连接。如果是偶发情况最直接的办法就是重启 IDEA 再试。如果是长期现象就要检查网络环境了。我实测下来插件市场加载依赖的网络连接某些网络环境下确实会出现不稳定的情况。这时候可以试试切换网络环境比如从公司内网切到手机热点或者换个网络开关状态试试有时这样就能加载出来。IDEA 的 HTTP 代理设置也需要检查确认没有配置错误否则会影响插件仓库的连接。还有一个思路值得提一下如果插件市场始终加载不了你又确实需要某个插件可以手动到插件官网下载对应版本的 zip 包然后通过本地安装的方式安装。这招虽然麻烦点但是不依赖插件市场的加载状态属于稳定的备用方案。5.2 Gradle 同步失败与依赖下载异常新建插件工程后Gradle 同步失败是第二个高频坑。常见报错是下载依赖超时因为 IntelliJ Platform 依赖包体积很大网络慢时很容易超时中断。处理思路分几步。第一步检查仓库地址是否能访问最好在浏览器里把依赖包地址贴出来试一下。第二步确认 Gradle 配置了合适的 JVM 参数给足内存比如在gradle.properties里添加org.gradle.jvmargs-Xmx2048m -XX:MaxMetaspaceSize512m org.gradle.daemontrue第三步如果是持续性的下载失败考虑使用国内或单位内的 Maven 镜像仓库来加速。这个办法对大部分依赖下载问题都有效。另外一个很隐蔽的问题**本机 JDK 版本与 Gradle 插件要求的 JDK 版本不一致。**比如 Gradle 8 起要求 JDK 17如果你还在用 JDK 11同步必然失败。排查时可以看 Gradle 输出信息里关于 Java 版本的提示这两个版本对应上问题就解决了。5.3 调试时插件加载失败的排查路径写好了插件点运行弹出的新 IDE 里却看不到自己的菜单项。这种情况的排查路径有讲究不能瞎猜。优先看 IDEA 的日志。调试模式下新实例的日志在Help → Show Log in Files里查看重点搜索关键字 “plugin”、“error”。如果插件加载失败日志里通常会打出原因比如Plugin xxx failed to initialize或者类加载异常。一种很常见的原因是plugin.xml里声明的类名包名错了类找不到了。这时候日志会提示ClassNotFound导致插件被禁用。解决方法是检查plugin.xml里的class属性是否和实际类全限定名一致。另外一个常见原因是版本范围兼容性问题。如果你的sinceBuild设置过高或者untilBuild设置过底低版本 IDEA 根本不会加载你这个插件。在调试时尤其要注意调试用的 IDE 版本和你在intellij { version ... }里配置的版本差异过大会导致各种诡异问题。我自己的经验是调试环境尽量和配置的版本保持一致发布前再把untilBuild放宽测试。6. 踩坑记录与几个建议写插件开发手册时我把自己的踩坑记录也整理了出来这些内容是文档里很少写的。第一个坑是关于UI 刷新的线程问题。IntelliJ 平台的 UI 操作必须在 EDT事件分发线程上执行如果你在工作线程里直接操作 UI 组件轻则控件不刷新重则直接抛异常。正确做法是用ApplicationManager.getApplication().invokeLater()把 UI 操作切换到 EDT 上。我早期写的插件就是没注意这一点导致 Tool Window 里的按钮时灵时不灵。第二个坑是关于类加载器的隔离。插件运行在独立的类加载器中不要试图通过静态变量共享代码到 IDE 其他部分。这会导致内存泄漏或者变量访问异常。如果你要实现插件内的全局共享建议用官方提供的Service机制而不是自己写单例。第三个坑是调试时的缓存问题。频繁修改代码后如果调试实例没清缓存会导致旧的代码还生效你改了但看不到效果。遇到这种“改了没用”的情况先做一次Build → Rebuild Project再清一下调试实例的缓存目录往往就好了。给新手的建议是不要一上来就追求大而全的功能先从小 Action 做起跑通一个完整闭环再逐步尝试 Tool Window、配置持久化、语言支持这些高级功能。插件开发的高度开放性意味着坑很多但每一个坑填平之后你都能收获一个相当有成就感的工具。这本手册(上)的后续部分我会继续往下填空。本文还有配套的精品资源点击获取
返回列表