☰
IntelliJ IDEA插件开发实战:从源码demo到可运行工程
2026/9/25 9:54:53 网站建设 项目流程

简介:这是一份面向IntelliJ IDEA插件开发初学者与进阶者的详细源码示例,围绕插件结构、事件监听、Action机制、Dialog与Popup交互以及Swing组件应用等核心知识点展开,帮助开发者在较短时间内理解IDE扩展的完整实现路径。压缩包共16个文件,约10KB,以java源码与xml配置为主,辅以svg图标、iml模块文件及gitignore等工程辅助文件,分别承担功能实现、插件注册、界面资源与项目配置等职责,目录组织清晰,便于按模块对照阅读。目前已有785人学习下载。通过研究该示例,读者可以掌握菜单项注册、鼠标右键数据交互、弹出框定制等常见交互场景的落地写法,理解插件工程配置与资源引用方式,并借助内置工具完成测试与调试,从而提升对IDE增强与定制开发的整体认知。

1. 从 idea插件详细源码demo.zip 说起:一个压缩包里到底该有什么

拿到「idea插件详细源码demo.zip」这个标题,多数人第一反应是去找下载链接,但真正做过 IntelliJ 插件开发的人会先问一句:这个 demo 里有没有plugin.xml、有没有build.gradle.kts、有没有一个能跑起来的 Action。因为 IDEA 插件不是普通 Java 项目,它依赖 IntelliJ Platform SDK,脱离平台版本谈源码基本没有意义。这个标题背后对应的需求很具体:想学 IntelliJ 插件开发,但官方文档偏概念,网上零散代码又跑不起来,所以需要一个结构完整、能直接导入、能点出效果的 demo 工程。它适合三类人:写过 Java 想扩到 IDE 工具链的、想给团队做内部开发提效插件的、以及想读懂现有插件源码结构的。下面我按一个可复现 demo 工程该有的样子,把从环境到打包的路径拆开讲。

2. IntelliJ 插件工程的骨架:从 plugin.xml 到第一个 Action

2.1 为什么 demo 工程必须锁定平台版本

IntelliJ Platform 的 API 在不同大版本之间是有破坏性变更的,尤其是 2023.1 之后对ActionUpdateThread、Project生命周期、Disposer的调整。一个 demo 如果只写「基于 IDEA 2023」,导入到 2024.x 很可能编译不过。常见做法是在gradle.properties里显式声明platformVersion和pluginSinceBuild,让 Gradle IntelliJ Plugin 去拉对应版本的 SDK。

# gradle.properties platformType = IC platformVersion = 2023.3.6 pluginSinceBuild = 233 pluginUntilBuild = 241.*

platformType = IC表示社区版,IU是旗舰版;pluginSinceBuild = 233对应 2023.3,pluginUntilBuild = 241.*表示兼容到 2024.1 系列。这两个参数决定了插件在市场里的可见范围,写错会导致用户装了但 IDE 提示不兼容。我一般会把untilBuild留一个上限,避免新版本 API 变更后插件直接崩。

2.2 plugin.xml 里最少要写哪几段

plugin.xml是插件的入口描述文件,demo 工程里它至少要有<idea-version>、<depends>、<extensions>和<actions>四块。缺<depends>会导致运行时找不到平台类,缺<actions>则菜单里看不到任何东西。

<idea-plugin> <id>com.example.demo</id> <name>Demo Plugin</name> <vendor>example</vendor> <depends>com.intellij.modules.platform</depends> <extensions defaultExtensionNs="com.intellij"> <notificationGroup id="DemoNotify" displayType="BALLOON"/> </extensions> <actions> <action id="Demo.HelloAction" class="com.example.demo.HelloAction" text="Say Hello" description="Demo action"> <add-to-group group-id="ToolsMenu" anchor="first"/> <keyboard-shortcut keymap="$default" first-keystroke="ctrl alt H"/> </action> </actions> </idea-plugin>

<depends>com.intellij.modules.platform</depends>是最小依赖,只用到平台基础能力时写这一条就够;如果要用到 Java 相关 PSI,需要再加com.intellij.modules.java。<add-to-group>决定菜单位置,ToolsMenu是工具菜单,anchor="first"让它排在最前,方便 demo 演示时快速找到。

2.3 写一个能跑通的 AnAction

Action 是插件最常见的入口。下面这个类继承AnAction,点击后弹一个通知,用来验证工程是否真的被 IDE 加载。

package com.example.demo; import com.intellij.notification.NotificationGroupManager; import com.intellij.notification.NotificationType; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import org.jetbrains.annotations.NotNull; public class HelloAction extends AnAction { @Override public void actionPerformed(@NotNull AnActionEvent e) { // 通过 plugin.xml 中注册的 notificationGroup id 获取管理器 NotificationGroupManager.getInstance() .getNotificationGroup("DemoNotify") .createNotification("Hello from demo plugin", NotificationType.INFORMATION) .notify(e.getProject()); } @Override public void update(@NotNull AnActionEvent e) { // 只有打开项目时才启用该 Action e.getPresentation().setEnabledAndVisible(e.getProject() != null); } }

actionPerformed是点击后的逻辑,update控制按钮的可用状态。这里用e.getProject() != null判断是否在项目上下文中,避免在欢迎界面点击时报空指针。通知组 id 必须和plugin.xml里的notificationGroup一致,否则运行时会抛IllegalArgumentException,这是新手最容易翻车的地方之一。

3. 用 Gradle 把 demo 跑起来:runIde 与 sandbox 机制

3.1 build.gradle.kts 的关键配置

Gradle IntelliJ Plugin 提供了runIde任务,它会启动一个独立的 IDE 沙箱实例,不会污染你本机的正式 IDE。demo 工程的构建脚本核心是这几行:

plugins { id("java") id("org.jetbrains.intellij") version "1.17.2" } group = "com.example" version = "1.0.0" repositories { mavenCentral() } intellij { version.set("2023.3.6") type.set("IC") plugins.set(listOf()) } tasks { patchPluginXml { sinceBuild.set("233") untilBuild.set("241.*") } runIde { // 沙箱目录,默认在 build/idea-sandbox jvmArgs("-Xmx2g") } }

intellij块里的version和type必须和gradle.properties保持一致,否则会出现 SDK 版本冲突。runIde的jvmArgs给沙箱 IDE 分配 2G 堆,插件调试时如果加载大项目,内存不够会直接卡死。patchPluginXml负责把sinceBuild写进最终产物的plugin.xml,这一步在打包时自动执行。

3.2 启动沙箱 IDE 的完整命令

在工程根目录执行:

./gradlew runIde

第一次运行会下载对应版本的 IntelliJ Platform SDK,体积在 1G 左右,国内网络建议配置镜像。启动后你会看到一个全新的 IDEA 窗口,标题栏带沙箱标识。此时按Ctrl+Alt+H或从 Tools 菜单点「Say Hello」,应该能看到右下角弹出通知。如果没反应,先检查plugin.xml是否被正确识别,再看沙箱日志build/idea-sandbox/system/log/idea.log,里面会打印插件加载失败的具体原因。

3.3 调试插件的两种方式

第一种是直接在runIde启动的沙箱里用Debug模式运行,断点打在 Action 里即可。第二种是远程调试,适合沙箱已经启动、想动态附加的场景:

./gradlew runIde --debug-jvm

执行后 Gradle 会等待调试器连接,默认端口 5005。在 IDEA 里新建一个 Remote JVM Debug 配置,连上后就能断点。第二种方式的好处是沙箱启动过程不受调试器阻塞,适合排查启动期加载问题。我一般先用第一种快速验证逻辑,遇到插件初始化顺序问题时再切第二种。

4. 避坑与排查:demo 工程最容易卡住的五个地方

4.1 现象:runIde 启动后菜单里找不到 Action

原因通常是plugin.xml的<actions>没被合并进最终产物,或者add-to-group的 group-id 写错。解决方式是先执行./gradlew buildPlugin,解压build/distributions下的 zip,检查里面的plugin.xml是否包含你的 action 定义。如果产物里没有,说明源文件路径不对,Gradle 默认只扫描src/main/resources/META-INF/plugin.xml。

4.2 现象:编译报「cannot resolve symbol AnAction」

原因是build.gradle.kts里没有正确应用 IntelliJ 插件,或者intellij块配置缺失导致 SDK 没被加入 classpath。检查plugins块里是否有org.jetbrains.intellij,以及repositories是否能访问到平台仓库。如果用的是离线环境,需要提前把 SDK 缓存到本地。

4.3 现象:通知弹不出来,日志报 NotificationGroup not found

NotificationGroupManager.getInstance().getNotificationGroup("DemoNotify")里的 id 必须和plugin.xml中<notificationGroup id="DemoNotify">完全一致,大小写敏感。另一个常见原因是notificationGroup写在了错误的defaultExtensionNs下,必须是com.intellij。

4.4 现象:沙箱 IDE 启动极慢或卡在加载界面

多数是内存不足或插件依赖冲突。先确认runIde的jvmArgs给了足够堆,再检查plugins.set(listOf())是否为空。如果 demo 依赖了其他插件,需要在这里声明,否则沙箱不会自动加载。另外,首次启动要建索引,耐心等几分钟,别急着杀进程。

4.5 现象:打包后的插件在市场安装提示不兼容

检查patchPluginXml里的sinceBuild和untilBuild是否覆盖了目标 IDE 版本。sinceBuild写 233 表示最低 2023.3,如果用户用 2022.3 就会提示不兼容。untilBuild留空表示不设上限,但新版本 API 变更后可能运行时报错,所以建议显式写一个经过验证的上限。

5. 进阶:把 demo 改成可复用的插件模板

5.1 用模板变量减少重复配置

如果团队要批量做插件,可以把 demo 抽成模板,把id、name、vendor、package做成变量。Gradle 的expand或者 IntelliJ 自带的模板机制都能做,但最轻量的方式是在build.gradle.kts里读环境变量:

val pluginId: String by project val pluginName: String by project tasks.patchPluginXml { version.set(project.version.toString()) pluginDescription.set("Generated from demo template") }

配合gradle.properties里的pluginId=com.example.xxx,每次新建工程只改这一处。这样做的代价是plugin.xml里不能写死 id,需要用占位符并在构建时替换。

5.2 验证插件是否真的被加载

除了看菜单,还可以在 Action 里打印插件版本,确认运行时拿到的是最新构建:

String version = PluginManagerCore.getPlugin(PluginId.getId("com.example.demo")) .map(PluginDescriptor::getVersion) .orElse("unknown"); System.out.println("Demo plugin version: " + version);

PluginId.getId必须和plugin.xml里的<id>一致。如果返回unknown,说明插件没被加载,或者 id 写错了。这个技巧在排查「改了代码但沙箱里还是旧行为」时特别有用,因为沙箱缓存有时不会自动刷新。

5.3 一个我常犯的错误

早期做 demo 时,我总把plugin.xml放在src/main/java/META-INF下,结果runIde能跑,buildPlugin打出来的包却缺描述文件。后来固定放在src/main/resources/META-INF,再没出过这个问题。另外,沙箱目录build/idea-sandbox建议定期清理,尤其是切换平台版本后,残留的旧插件缓存会导致各种玄学加载失败。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询