从零开始开发一款IDEA Plugin插件

1.安装 Plugin DevKit 插件

这个插件的目的是让我们能够在新建项目的时候选择IDE插件这个选项。否则在新建项目的时候就选不了IDE插件。

2.IDEA 开启内部模式

在idea安装路径bin/idea.properties 新增以下内容开启内部模式,重启后生效

# 开启内部模式
idea.is.internal=true

这一步的目的是: 开发一款插件得要知道把它放在哪里,比如放在工具栏、菜单栏里面,而这些在IDEA中都有唯一的key, 比如放在Tools下面, 就先把鼠标放在Tools上, 然后ctrl+alt+鼠标左键就会出现弹框。

3.创建 IDE Plugin 插件项目,这里用的 jdk21

4.修改构建文件 build.gradle.kts

创建完插件项目后,会得到一个 build.gradle.kts 文件,下面是我修改后的 build.gradle.kts :

plugins {
    id("java")
    id("org.jetbrains.intellij.platform") version "2.10.2"
}

// 这是插件 group 和版本号
group = "com.cxj.plugin"
version = "1.0.0"

repositories {
    mavenCentral()
    maven {
        url = uri("https://maven.aliyun.com/repository/public")
    }
    intellijPlatform {
        defaultRepositories()
    }
}

// Read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin.html
dependencies {
    intellijPlatform {
        intellijIdea("2025.2.4")
        testFramework(org.jetbrains.intellij.platform.gradle.TestFrameworkType.Platform)

        // Add plugin dependencies for compilation here, example:
        // bundledPlugin("com.intellij.java")
    }
}

intellijPlatform {
    pluginConfiguration {
        ideaVersion {
            sinceBuild = "252.25557"
        }

        changeNotes = """
            <h2><b>1.0.0</b></h2>
            <ul>
                <li>打开当前文件位置小工具的初始版本, 添加了一个工具栏操作, 点击即可在系统文件资源管理器中显示当前文件</li>
            </ul>
        """.trimIndent()
    }
}

tasks {
    // 设置插件打包后的 jar 文件名
    withType<Jar> {
        archiveBaseName.set("ShowInExplorer")
        archiveVersion.set(project.version.toString())
    }

    // Set the JVM compatibility versions
    withType<JavaCompile> {
        sourceCompatibility = "21"
        targetCompatibility = "21"
    }
}

5.构建 Gradle

点击 Gradle 图标重新加载一次,首次构建比较慢,大约 10 分钟

6.编写插件代码

编写 AnAction 插件类文件, 比如我要做一个打开当前文件资源管理器位置的插件,项目结构和代码如下:

动作类:

package com.cxj.plugin.showinexplorer.action;

import com.cxj.plugin.showinexplorer.service.ShowInExplorerService;
import com.cxj.plugin.showinexplorer.util.ActionDataUtil;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;

/**
 * 打开当前文件所在资源管理器位置动作
 *
 * @author chenxj
 * @date 2026/6/22 11:38
 */
public class ShowInExplorerAction extends AnAction {

    private static final Logger LOG = Logger.getInstance(ShowInExplorerAction.class);

    /**
     * 执行打开资源管理器动作
     *
     * @param event 当前动作事件
     */
    @Override
    public void actionPerformed(AnActionEvent event) {
        Project project = event.getProject();
        VirtualFile virtualFile = ActionDataUtil.getCurrentVirtualFile(event);
        if (virtualFile == null) {
            Messages.showMessageDialog(project, "请先打开一个本地文件", "无法打开资源管理器", Messages.getWarningIcon());
            return;
        }

        try {
            getShowInExplorerService().reveal(virtualFile);
            LOG.info("Opened current file in explorer, path=" + virtualFile.getPath());
        } catch (IllegalArgumentException exception) {
            Messages.showMessageDialog(project, exception.getMessage(), "无法打开资源管理器", Messages.getWarningIcon());
            LOG.warn("Failed to open current file in explorer, path=" + virtualFile.getPath(), exception);
        }
    }

    /**
     * 更新动作可用状态
     *
     * @param event 当前动作事件
     */
    @Override
    public void update(AnActionEvent event) {
        event.getPresentation().setEnabled(ActionDataUtil.getCurrentVirtualFile(event) != null);
    }

    /**
     * 获取文件定位服务
     *
     * @return 文件定位服务
     */
    private ShowInExplorerService getShowInExplorerService() {
        return ApplicationManager.getApplication().getService(ShowInExplorerService.class);
    }
}

服务类:

package com.cxj.plugin.showinexplorer.service;

import com.intellij.ide.actions.RevealFileAction;
import com.intellij.openapi.components.Service;
import com.intellij.openapi.vfs.VirtualFile;

import java.io.File;

/**
 * 当前文件资源管理器定位服务
 *
 * @author chenxj
 * @date 2026/6/22 11:38
 */
@Service(Service.Level.APP)
public final class ShowInExplorerService {

    /**
     * 在资源管理器中定位文件
     *
     * @param virtualFile 当前虚拟文件
     */
    public void reveal(VirtualFile virtualFile) {
        File file = new File(virtualFile.getPath());
        if (!file.exists()) {
            throw new IllegalArgumentException("当前文件不存在或不是本地文件: " + virtualFile.getPath());
        }
        RevealFileAction.openFile(file);
    }
}

工具类:

package com.cxj.plugin.showinexplorer.util;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.vfs.VirtualFile;

/**
 * Action 上下文数据工具
 *
 * @author chenxj
 * @date 2026/6/22 11:38
 */
public final class ActionDataUtil {

    private ActionDataUtil() {
    }

    /**
     * 获取当前编辑器
     *
     * @param event 当前动作事件
     * @return 当前编辑器
     */
    public static Editor getEditor(AnActionEvent event) {
        return event.getData(CommonDataKeys.EDITOR);
    }

    /**
     * 获取当前上下文中的文件
     *
     * @param event 当前动作事件
     * @return 当前文件
     */
    public static VirtualFile getCurrentVirtualFile(AnActionEvent event) {
        VirtualFile virtualFile = event.getData(CommonDataKeys.VIRTUAL_FILE);
        if (virtualFile != null && !virtualFile.isDirectory()) {
            return virtualFile;
        }

        Editor editor = getEditor(event);
        if (editor == null) {
            return null;
        }
        return FileDocumentManager.getInstance().getFile(editor.getDocument());
    }
}

把上一步创建的插件类注册到 plugin.xml 文件中:

注意:如果要将插件上传到市场,description 标签必须以英文开头

<!-- Plugin Configuration File: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html -->
<idea-plugin>
    <!-- 插件唯一标识, 发布后不要随意变更 -->
    <id>com.cxj.plugin.show-in-explorer</id>

    <!-- 插件在 IDE 中展示的名称 -->
    <name>Show in Explorer</name>

    <!-- 插件作者或组织信息 -->
    <vendor email="xxx@qq.com">chenxinjin</vendor>

    <!-- 插件描述, 用于插件管理页展示,要将插件上传到市场,description 标签必须以英文开头 -->
    <description><![CDATA[
        A small tool used to open the current file explorer location. After installation, there will be an icon on the right side of the menu bar. Click it, or use the shortcut keys ctrl+alt+F1.
        <br>
        一个用于打开当前文件资源管理器位置的小工具, 安装后在菜单栏右侧会有一个图标, 点击即可, 也可以使用快捷键 ctrl+alt+F1.
    ]]></description>

    <!-- 依赖 IntelliJ 平台基础模块 -->
    <depends>com.intellij.modules.platform</depends>

    <resource-bundle>messages.MyMessageBundle</resource-bundle>

    <extensions defaultExtensionNs="com.intellij">
    </extensions>

    <actions>
        <!-- action 标签用于注册打开当前文件所在资源管理器位置动作 -->
        <action id="com.cxj.plugin.showinexplorer.action.ShowInExplorerAction" class="com.cxj.plugin.showinexplorer.action.ShowInExplorerAction" text="打开当前文件位置" description="在资源管理器中定位当前文件" icon="/META-INF/pluginIcon.svg">
            <!-- 将插件动作放到主工具栏右侧, 以按钮形式展示 -->
            <add-to-group group-id="MainToolbarRight" anchor="first"/>
            <!-- 插件默认快捷键 -->
            <keyboard-shortcut keymap="$default" first-keystroke="ctrl alt F1"/>
        </action>
    </actions>
</idea-plugin>

7.启动插件

点击 Run IDE with Plugin 按钮运行插件,就会弹出一个新的IDEA页面出来,随便打开一个项目就可以看到我们的插件

8.打包生成插件zip安装包

Gradle -> 项目名 -> Tasks -> intellijPlatform -> buildPlugin,执行成功后,这个 .zip 包会被生成在 build/distributions/ 目录下

9.安装插件

IDEA-Settings-Plugins Install Plugin from Disk 离线安装插件,再选中这个zip包

10.发布插件

如果要让其他小伙伴体验我自己开发的插件,就要把插件发布到官网上去

插件官网:https://plugins.jetbrains.com/developers/intellij-platform

登录之后点击 Upload plugin, 填写基础信息、上传jar包、等待审核。

Vendor ID (供应商ID):这个字段主要是给系统用的,用来生成你专属的供应商页面链接,比如 plugins.jetbrains.com/vendor/你的ID,这个 ID 一旦创建就无法更改,并且不能包含空格和特殊字符。提交前请一定想清楚,因为之后改不了。
Public Vendor Name (公开供应商名称):这个字段就是用户能在插件市场直接看到的名字,是插件的“招牌”,如果是个人开发者官方文档建议填写你的真实姓名(如 Zhang San)。如果是组织或团队则填写你的品牌名或组织名

上传插件

11.插件市场搜索

官方审核通过后,就可以在插件市场上搜索了,欢迎大家体验

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值