IDEA 插件开发(一):菜单及气泡通知
开发工具
开发工具使用 Intellij IDEA,官网下载地址:https://www.jetbrains.com/idea/download/other.html
推荐使用 2020.3.4 社区版(Community),原因如下:
- 免费开源,在开发插件的时候,可以调试源代码;
- 自带 Plugin DevKit 插件(IDEA 的插件开发套件);
- 项目默认配置 IntelliJ Platform Plugin SDK;
- 该版本支持 M1 芯片(Apple Silicon)。
设置源码路径(可选)
-
查看 build 号:打开 IDEA,Help | About,查看 build 号
-
IDEA Community 源码:切换到与 build 号相同的分支,点击 Code 按钮,选择 Download ZIP
对于我们选择的 2020.3.4,源码地址为:https://github.com/JetBrains/intellij-community/tree/203.8084
File | Project Structure | Platform Settings | SDKs:
开发插件
创建插件工程
选择 File | New | Project,左侧栏中选择 IntelliJ Platform Plugin 工程类型:
点击 Next,设置工程名称及位置,点击 Finish 完成创建:
可以到 File | Project Structure 来自定义工程设置。
插件工程结构
插件工程内容:
├── .idea
│ ├── .gitignore // git 提交忽略文件
│ ├── encodings.xml // 编码配置
│ ├── misc.xml // 各种杂项
│ ├── modules.xml // 模块信息
│ ├── sonarlint // 代码扫描插件
│ ├── workspace.xml // 工作空间
├── FirstPlugin.iml // 项目标识文件(infomation of module)
├── resources
│ └── META-INF
│ ├── plugin.xml // ★插件配置:开发描述、版本信息、Action 事件入口、扩展信息(数据存放等)
│ ├── pluginIcon.svg // ★插件图标:名称固定,不可修改,自己放入
│ ├── pluginIcon_dark.svg // ★暗色系主题下的图标
└── src // ★具体的事件、UI 窗体、工程逻辑的 Java/Kotlin 代码
修改插件配置文件
下面示例描述了可在 plugin.xml 文件配置的主要元素:
<idea-plugin>
<!-- 插件唯一 id,不能和其他插件项目重复,所以推荐使用 com.xxx.xxx 的格式
插件不同版本之间不能更改,若没有指定,则与插件名称相同 -->
<id>com.ageovb.first</id>
<!-- 插件名称,别人在官方插件库搜索你的插件时使用的名称 -->
<name>First</name>
<!-- 插件版本号 -->
<version>1.0.0</version>
<!-- 供应商主页和email(不能使用默认值,必须修改成自己的)-->
<vendor email="ageovb.com" url="http://www.ageovb.com">ageovb</vendor>
<!-- 插件的描述,支持 HTML 标签;
不能使用默认值,必须修改成自己的。并且需要大于 40 个字符 -->
<description><![CDATA[
基于IDEA插件模板方式创建测试工程<br>
<em>1. 学习IDEA插件工程搭建</em>
<em>2. 验证插件基础功能实现</em>
]]></description>
<!-- 插件版本变更信息,支持 HTML 标签;
将展示在 settings | Plugins 对话框和插件仓库的 Web 页面 -->
<change-notes><![CDATA[
插件开发学习功能点<br>
<em>1. 工程搭建</em>
<em>2. 菜单读取</em>
<em>3. 添加菜单</em>
<em>4. 气泡通知</em>
]]>
</change-notes>
<!-- 以上信息会被抽取至插件市场主页展示 -->
<!-- 兼容最低版本 173,对应 2017.3 版本 -->
<idea-version since-build="173.0"/>
<!-- 插件所依赖的其他插件的 id -->
<depends>com.intellij.modules.platform</depends>
<!-- 声明该插件对 IDEA core 或其他插件的扩展 -->
<extensions defaultExtensionNs="com.intellij">
<!-- 2020.3 及以后的版本,注册通知服务 -->
<!--<notificationGroup id="Custom Notification Group" displayType="BALLOON" key="notification.group.name"/>-->
</extensions>
<!-- 编写插件动作 -->
<actions>
<action id="first" class="com.ageovb.first.FirstAction" text="Notification" description="Test notification">
<add-to-group group-id="ToolsMenu" anchor="first"/>
<keyboard-shortcut keymap="$default" first-keystroke="meta I"/>
</action>
</actions>
</idea-plugin>
创建 Action
一个 Action 表示 IDEA 菜单里的一个 menu item 或工具栏上的一个按钮,通过继承 AnAction
实现,当选择一个 menu item 或点击工具栏上的按钮时,就会调用 AnAction
类的 actionPerformed()
方法。
实现自定义 Action 分两步:
- 定义一个或多个 action;
- 注册 action,将 item 添加到菜单或工具栏上。
新建 Action 文件
新建一个 Package,如 com.ageovb.first,然后右击新建 Action 文件:
如果没有看到 Plugin DevKit 选项,说明项目没有配置 IntelliJ Platform Plugin SDK,推荐的 2020.3.4 不会出现该情况。
填写必要的信息:
编写 Action 代码
package com.ageovb.first;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationDisplayType;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.ui.MessageType;
import org.jetbrains.annotations.NotNull;
/**
* 通过 Plugin Devkit 创建的 Action 继承了 AnAction
*/
public class FirstAction extends AnAction {
/**
* 需要实现点击事件发生之后的抽象方法
*/
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
// 这是老版本的,NotificationGroup 已经过时
NotificationGroup notificationGroup = new NotificationGroup("Notification", NotificationDisplayType.BALLOON, false);
Notification notification = notificationGroup.createNotification("Test notification", MessageType.INFO);
Notifications.Bus.notify(notification);
// 2020.3 及以后的版本可以在 plugin.xml 中注册通知服务,并编写通知工具类 NotifyUtil
//NotifyUtil.notifyInfo(e.getProject(), "Test notification");
}
}
运行插件
与正常 Java 项目一样,直接点击右上角的 Run 按钮运行插件:
插件以 Debug/Run 模式运行时是在 SandBox(沙箱) 中进行的,不会影响当前的 IntelliJ IDEA,启动后选择 Tools | Notification:
即可看到右下角的气泡通知:
运行错误解决
找不到 Python
2022-10-03 14:20:52,094 [ 1141] WARN - .intellij.util.EnvironmentUtil - can't get shell environment
java.lang.RuntimeException: command [/bin/zsh, -l, -i, -c, '/Applications/IntelliJ IDEA CE.app/Contents/bin/printenv.py' '/var/folders/k2/b_96l4cx3hdfvybcbrwjvhw80000gn/T/intellij-shell-env.17742117045732721406.tmp']
exit code:127 text:0 out:(anon):setopt:7: can't change option: monitor
[ERROR]: gitstatus failed to initialize.
Add the following parameter to ~/.zshrc for extra diagnostics on error:
GITSTATUS_LOG_LEVEL=DEBUG
Restart Zsh to retry gitstatus initialization:
exec zsh
env: python: No such file or directory
at com.intellij.util.EnvironmentUtil$ShellEnvReader.runProcessAndReadOutputAndEnvs(EnvironmentUtil.java:353)
at com.intellij.util.EnvironmentUtil$ShellEnvReader.readShellEnv(EnvironmentUtil.java:254)
at com.intellij.util.EnvironmentUtil$ShellEnvReader.readShellEnv(EnvironmentUtil.java:269)
at com.intellij.util.EnvironmentUtil.getShellEnv(EnvironmentUtil.java:204)
at com.intellij.util.EnvironmentUtil.lambda$loadEnvironment$0(EnvironmentUtil.java:106)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:668)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:665)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:665)
at java.base/java.lang.Thread.run(Thread.java:834)
默认是使用 python
命令去获取 shell 环境变量的,即使我们使用 xcode-select --install
命令安装过开发者命令行工具,可以使用 ll /Library/Developer/CommandLineTools/usr/bin/python*
命令查看,并没有 python
命令,我们可以使用命令 sudo ln -s /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/bin/python3 /Library/Developer/CommandLineTools/usr/bin/python
创建一个软链接,让 python
实际调用 python3
。
找不到类 OpenURIHandler
2022-10-03 14:20:52,631 [ 1678] WARN - i.mac.MacOSApplicationProvider - com/apple/eawt/OpenURIHandler
java.lang.NoClassDefFoundError: com/apple/eawt/OpenURIHandler
at com.intellij.ui.mac.MacOSApplicationProvider.initApplication(MacOSApplicationProvider.java:57)
at com.intellij.idea.ApplicationLoader.startApp(ApplicationLoader.kt:152)
at com.intellij.idea.ApplicationLoader.executeInitAppInEdt(ApplicationLoader.kt:68)
at com.intellij.idea.ApplicationLoader.access$executeInitAppInEdt(ApplicationLoader.kt:1)
at com.intellij.idea.ApplicationLoader$initApplication$1$1.run(ApplicationLoader.kt:374)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.ClassNotFoundException: com.apple.eawt.OpenURIHandler
at com.intellij.util.lang.UrlClassLoader.findClass(UrlClassLoader.java:338)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 18 more
这篇文章里指出,从 JDK 9 开始,已经不提供包 com.apple.eawt 和 com.apple.eio,取而代之的是 java.awt.desktop。不知道哪里的代码用的还是 JDK 8,目前不影响,先不用管。
缺少 Times 字体
Warning: the fonts "Times" and "Times" are not available for the Java logical font "Serif", which may have unexpected appearance or behavior. Re-enable the "Times" font to remove this warning.
下载并安装 Times 字体。
仓库地址
项目已上传到 Gitee。
参考资料
你们要的Intellij IDEA 插件开发秘籍,来了!
Idea插件开发-开发自己的第一款idea插件
IntelliJ -IDEA插件开发教程-UI篇-编辑提示、消息通知(五)
https://plugins.jetbrains.com/docs/intellij/developing-plugins.html