IntelliJ IDEA插件开发教程

我们在使用Android Studio开发的时候都会使用一些插件,来方便我们的开发工作,提升工作效率。IntelliJ IDEA 可能有的人已经很熟悉,强大的开源IDE。Android Studio 就是基于IDEA社区版开发的。下载安装后打开软件我们就会发现,IntelliJ IDEA的界面、菜单、状态栏以及Preference 和 安卓开发ide android studio 几乎是一模一样的。

IntelliJ IDEA 简称 IDEA,是 Jetbrains 公司旗下的一款 JAVA 开发工具,支持 Java、Scala、Groovy、kotlin 等语言的开发,同时具备支持目前主流的技术和框架,擅长于企业应用、移动应用和 Web 应用的开发,提供了丰富的功能,智能代码助手、代码自动提示、重构、J2EE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等。

IntelliJ IDEA插件类型

在介绍IDEA插件开发流程之前,先了解下idea插件有哪些类型及其作用。

从官方文档可以看出,idea开发的插件最常见的有5种类型。分别是

1、UI主题

UI主题使设计人员能够自定义内置IDE UI元素的外观。自定义UI主题可以:

  • 替代图标,
  • 更改图标和UI控件的颜色,
  • 更改UI控件的边框和插图,
  • 提供自定义编辑器方案,
  • 添加背景图像。

可供下载的UI主题 说明创造的可能性。

2、自定义语言支持

自定义语言支持提供了使用特定编程语言的基本功能。包括:

  • 文件类型识别(File type recognition)
  • 词法分析(Lexical analysis)
  • 词法高亮显示(Syntax highlighting)
  • 格式化(Formatting)
  • 代码洞察和代码完成(Code insight and code completion)
  • 检查和快速修复(Inspections and quick-fixes)
  • 意图行动(Intention actions)

详情点击:自定义语言支持插件开发

3、框架集成(Framework Integration)

框架集成由改进的代码洞察特性组成,这些特性是给定框架的典型特征,以及直接从IDE使用特定于框架的功能的选项。有时它还包括自定义语法或DSL的语言支持元素

  • 具体代码的洞察力(Specific code insight)
  • 直接访问特定于框架的功能(Direct access to framework-specific functionality)

参考案例: Struts 2 plugin开发

4、工具继承(Tool Integration)

工具集成使直接从IDE操作第三方工具和组件成为可能,而无需切换上下文

这就意味着:

  • 额外行动的实施(Implementation of additional actions)
  • 相关的UI组件(Related UI components)
  • 访问外部资源(Access to external resources)

参考案例: Gerrit integration

5、用户界面插件(User interface add-ons)

此类别中的插件对IDE的标准用户界面应用各种更改. 一些新添加的组件是交互式的,并且提供了新的功能,而另一些则仅限于可视化修改.

插件开发方式

Mac IDEA配置阿里云国内镜像

  • 1. 下载maven
  • 2. 打开IDEA配置Maven
  • 3. 编辑镜像地址
  • 4. 重启IDEA

IDEA会自动装配IDEA版本的maven,所以只需要配置settings.xml就可以实现变更国内镜像。

IDEA插件有两种开发方式:1、DevKit方式 2、Gradle方式

一、DevKit方式

Plugin DevKit_是一个捆绑的IntelliJ IDEA插件,用于使用IntelliJ IDEA为IntelliJ平台开发插件自己的构建系统. 它提供了自定义SDK类型和一组用于在IDE中构建插件的操作.早期的插件项目都是DevKit方式。

DevKit的plugin项目,项目工程的配置文件是imi文件。

Sandbox

IntelliJ IDEA 插件以 Debug/Run 模式运行时是在 SandBox 中进行的,不会影响当前的 IntelliJ IDEA;但是同一台机器同时开发多个插件时默认使用的同一个 sandbox,即在创建 IntelliJ Platform SDK 时默认指定的 Sandbox Home.

如果需要每个插件的开发环境是相互独立的,可以创建多个 IntelliJ Platform SDK,为 Sandbox Home 指定不同的目录 。

Run/Debug

新建或修改运行/调试配置,选择使用的module后,可直接点击图标运行或调试。

Prepare Plugin For Deployment

如果项目中没有任何依赖,打出来的插件包是jar包

如果项目中有依赖其他插件或Library,则打出来的插件包是zip文件

插件的配置文件是plugin.xml,是整个插件的核心,见Gradle方式中的plugin.xml说明。

二、Gradle方式

Gradle插件是构建IntelliJ插件的推荐解决方案.该插件负责处理插件项目的依赖性 - 基本IDE和插件可能依赖的其他插件.  它还提供了使用插件运行IDE并将插件发布到JetBrains插件存储库的任务.对于新项目,官方推荐Gradle方式。

Gradle的plugin项目,项目工程的配置文件是build.gradle文件

gradle插件源码及版本信息

兼容性

如果依赖的插件版本和intellij版本不兼容,编译则会报如下图错误

关于兼容性,官方也作了说明

例如koltin插件,可以去JetBrains Plugins Repository查询各版本及其兼容的IDE版本

可以根据项目需要添加更多的配置

plugin.xml

plugin.xml是整个项目的核心配置文件,一些Action、Extension组件需要在这里先进行注册和声明,和Android 开发的AndroidManifest.xml注册组件类似。

<idea-plugin><!-- 插件名称,别人在官方插件库搜索你的插件时使用的名称 --><name>MyPlugin</name><!-- 插件唯一id,唯一性标识,上传到官方仓库如果如果有重复的ID是不能提交成功的,所以推荐使用com.xxx.xxx的格式 插件不同版本之间不能更改,若没有指定,则与插件名称相同 --><id>com.example.plugin.myplugin</id><!-- 插件的描述 --><description>my plugin description</description><!-- 插件版本变更信息,支持HTML标签;将展示在 settings | Plugins 对话框和插件仓库的Web页面 --><change-notes>Initial release of the plugin.</change-notes><!-- 插件版本 --><version>1.0</version><!-- 供应商主页和email--><vendor url="http://www.jetbrains.com" email="support@jetbrains.com" /><!-- 插件所依赖的其他插件的id --><depends>MyFirstPlugin</depends>
<!-- Targeting PhpStorm, so is dependent on the PHP plugin -->
<depends>com.jetbrains.php</depends>
<depends>com.intellij.modules.platform</depends><!-- 插件兼容IDEA的最大和最小 build 号,两个属性可以任选一个或者同时使用官网详细介绍:http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html--><idea-version since-build="3000" until-build="3999"/><!-- application components --><application-components><component><!-- 组件接口 --><interface-class>com.foo.Component1Interface</interface-class><!-- 组件的实现类 --><implementation-class>com.foo.impl.Component1Impl</implementation-class></component></application-components><!-- project components --><project-components><component><!-- 接口和实现类相同 --><interface-class>com.foo.Component2</interface-class></component></project-components><!-- module components --><module-components><component><interface-class>com.foo.Component3</interface-class></component></module-components><!-- Actions --><actions>...</actions><!-- 插件定义的扩展点,以供其他插件扩展该插件 --><extensionPoints>...</extensionPoints><!-- 声明该插件对IDEA core或其他插件的扩展 --><extensions xmlns="com.intellij">...</extensions>
</idea-plugin>

Action

概念

Action 用于描述一个动作、行为,可以通过快捷键、点选的方式进行触发。一个 Action 是一个 class,是 AnAction 的子类,actionPerformed 方法在菜单Item或者标题栏按钮被选中的时候会被调用。

Action 允许添加到右键菜单或者Toolbar菜单上面。Action也可以成组添加到具体的一个Group下面。

创建action

继承AnAction,并重写actionPerformed方法,此方法是action触发执行的入口。

注册action

  • Action ID: action 唯一 id,推荐使用全类名
  • Class Name: 要被创建的 action class 名称
  • Name: menu item 的文本
  • Description: action 描述,toolbar 上按钮的提示文本,可选
  • Add to Group:选择新 action 要被添加到的 action group(Groups, Actions)以及相对其他 actions 的位置(Anchor),比如 EditMenu 就是顶部菜单栏的 Edit 菜单。
  • Keyboard Shortcuts:指定 action 的第一和第二快捷键

Components

插件组件是插件集成的基础概念,我们插件定义的每一个组件(component) 应该在配置文件中配置相关的接口(可选)和实现类。有三种组件:

Components 类型

Components 接口类型 描述
Application Component IDEA启动时会初始化,IDEA生命周期中仅存在一个实例。
Project Component IDEA 会为每一个 Project 实例创建一个 Project 级别的component
Module Component IDEA 会为每一个 Project 的加载过的Module实例Module级别的component

创建 Component

Application Component

public class TestApplication implements ApplicationComponent {public TestApplication() {}@Overridepublic void initComponent() {// TODO: insert component initialization logic here}@Overridepublic void disposeComponent() {// TODO: insert component disposal logic here}@Override@NotNullpublic String getComponentName() {return "TestApplication";}
}

Project Component

public class TestProject implements ProjectComponent {public TestProject(Project project) {}@Overridepublic void initComponent() {}@Overridepublic void disposeComponent() {}@Override@NotNullpublic String getComponentName() {return "TestProject";}@Overridepublic void projectOpened() {// called when project is opened}@Overridepublic void projectClosed() {// called when project is being closed}
}

Module Component

public class TestModule implements ModuleComponent {public TestModule(Module module) {}@Overridepublic void initComponent() {// TODO: insert component initialization logic here}@Overridepublic void disposeComponent() {// TODO: insert component disposal logic here}@Override@NotNullpublic String getComponentName() {return "TestModule";}@Overridepublic void moduleAdded() {// Invoked when the module corresponding to this component instance has been completely// loaded and added to the project.}
}

注册 Components

components 需要配置在 plugin.xml 中,并指定 interface 和 implementation,interface 类用于从其他组件中检索组件,implementation 类用于实例化组件。

Application Component

<application-components><component><implementation-class>com.example.test.TestApplication</implementation-class></component>
</application-components>

Project Component

<project-components><component><implementation-class>com.example.test.TestProject</implementation-class></component>
</project-components>

Module Component

<module-components><component><implementation-class>com.example.test.TestModule</implementation-class></component>
</module-components>

注意:

  1. 一个 interface-class 不能有多个 implementation-class。
  2. 若组件没有创建 interface 类,而是直接实现了 ApplicationComponent 等接口,interface 和 implementation 可以指定为同一个类。
  3. 每一个组件都应该有一个唯一的名字,通过 getComponentName() 返回,推荐使用 <plugin_name>.<component_name> 格式。

获取 Component 实例

获取 Application Component

通过 ApplicationManager获取

//获取application容器中的组件
TestApplication testApplication = ApplicationManager.getApplication().getComponent(TestApplication.class);

获取project

通过action获取

DataContext dataContext = anActionEvent.getDataContext();
// DataConstants 被标记为 @deprecated
mProject = (Project)dataContext.getData(DataConstants.PROJECT);Project project = anActionEvent.getData(PlatformDataKeys.PROJECT);

通过PsiElement获取

/*** The common base interface for all elements of the PSI tree.* <p/>* Please see <a href="https://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview.html">IntelliJ Platform Architectural Overview</a>* for high-level overview.*/
public interface PsiElement extends UserDataHolder, Iconable {/*** The empty array of PSI elements which can be reused to avoid unnecessary allocations.*/PsiElement[] EMPTY_ARRAY = new PsiElement[0];ArrayFactory<PsiElement> ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new PsiElement[count];/*** Returns the project to which the PSI element belongs.** @return the project instance.* @throws PsiInvalidElementAccessException if this element is invalid*/@NotNull@Contract(pure=true)Project getProject() throws PsiInvalidElementAccessException;
}

获取module

通过project获取

TestModule testModule = project.getComponent(TestModule.class);

通过action获取

DataContext dataContext = anActionEvent.getDataContext();
// DataConstants 被标记为 @deprecated
mModule =(Module)dataContext.getData(DataConstants.MODULE);Module module = anActionEvent.getData(LangDataKeys.MODULE);
@Deprecated
@SuppressWarnings({"JavadocReference"})
public interface DataConstants {/*** Returns {@link com.intellij.openapi.project.Project}** @deprecated use {@link PlatformDataKeys#PROJECT} instead*/@Deprecated String PROJECT = CommonDataKeys.PROJECT.getName();/*** Returns {@link com.intellij.openapi.module.Module}** @deprecated use {@link com.intellij.openapi.actionSystem.LangDataKeys#MODULE} instead*/@Deprecated @NonNls String MODULE = "module";
}

Component 生命周期

Component加载

Application 级别的 components 在 IDEA 启动时加载,Project 和 Module 级别的 components 在项目启动时共同加载。

一个组件加载过程:

  1. 创建:调用构造方法
  2. 初始化:调用 initComponent() 方法
  3. 如果是 Project 组件,会调用 projectOpened() 方法; 如果是 Module 组件,会依次调用 moduleAdded()projectOpened() 方法。

ModuleComponent 的生命周期方法中比 ProjectComponent 多一个 moduleAdded(),用于通知 module 已经被添加到 project 中。

如果 component 在加载时需要用到其他 component,我们只需在该 component 的构造方法的参数列表声明即可,在这种情况下,IntelliJ IDEA 会按正确的顺序实例化所依赖的 component。

示例:

public class MyComponent implements ApplicationComponent {private final MyOtherComponent otherComponent;public MyComponent(MyOtherComponent otherComponent) {this.otherComponent = otherComponent;}...
}

Component 卸载

一个组件卸载过程:

  1. 如果是 Project 或 Module 组件,调用 projectClosed()
  2. 接下来 disposeComponent() 将被调用

持久化

对于IDEA插件的一些配置,一般情况下都不会希望用户每次使用插件时都要配置一遍,所以 IntelliJ Platform 提供了一些 API,来做数据的持久化。

PropertiesComponent

对于简单的 key - value 数据结构,可以使用 PropertiesComponent,用于保存 application 和 project 级别的数据。用法如下:

//获取 application 级别的 PropertiesComponent
PropertiesComponent propertiesComponent = PropertiesComponent.getInstance();
//获取 project 级别的 PropertiesComponent,指定相应的 project
PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(Project);
// set & get
propertiesComponent.setValue(name, value)
propertiesComponent.getValue(name)

所有的 PropertiesComponent设置的键值对共用同一个namespance,所以需要避免key冲突。

PersistentStateComponent

对于复杂的数据结构,可以使用 PersistentStateComponent,PersistentStateComponent 可以指定持久化的存储位置。

  • 需要提供一个 PersistentStateComponent 的实现类,T代表需要持久化的数据结构类型,然后重写 getState() 和 loadState() 方法。T可以是任意的类,或者是实现类自身。
  • 若需要指定存储位置,则在实现类上增加 @State 注解
  • 若不希望其中的某个字段被持久化,可以在该字段上增加 @Transient 注解
@State(name = "PersistentStateComponentImpl", storages = {@Storage(value = "PersistentStateComponentImpl.xml")})
class PersistentStateComponentImpl implements PersistentStateComponent<State> {State myState;// 当组件被创建或 xml 文件被外部改变(比如git更新)时被调用public State getState() {return myState;}// 当 settings 被保存时,该方法会被调用并保存状态值。public void loadState(State state) {myState = state;}
}
class State {public State() {}// 支持基本的数据类型、Map、Collection、enumpublic String value;@Transientpublic String disableSave;
}
  • 若是 application 级别的组件

    • 运行调试时 xml 文件的位置: ~/IdeaICxxxx/system/plugins-sandbox/config/options
    • 正式安装时 xml 文件的位置: ~/IdeaICxxxx/config/options
  • 若是 project 级别的组件

    • 默认为项目的 .idea/misc.xml
    • 若指定为 StoragePathMacros.WORKSPACE_FILE,则会被保存在 .idea/worksapce.xml

注册持久化

持久化组件可以声明为 Service,也可以声明为 Component,声明为 Component 则与前面介绍注册与获取的方法一致,声明为Service如下:

获取方式为:

<extensions defaultExtensionNs="com.intellij">
<!-- application 级别-->
<applicationService serviceImplementation="com.yuyh.finder.PersistentStateComponentImpl1"/>
<!-- project 级别 -->
<projectService serviceImplementation="com.yuyh.finder.PersistentStateComponentImpl2"/>
</extensions>

扩展以及扩展点

Intellij 平台提供了允许一个插件与其他插件或者 IDE 交互的 extensions 以及 extension points 的概念。

extensions

如果你想要你的插件扩展其他插件或者 Intellij 平台,你必须声明一个或多个 extensions

extension points

如果你想要你的插件可以被其他插件使用,那么你必须在你的插件内声明一个或多个扩展点(extension points)。每个扩展点定义了允许访问这个点的类或者接口。

注册 extensions 以及 extension points

你可以在你的 plugin.xml 中的 <extensions> 和 <extensionPoints> 块中定义 extensions 以及 extension points。

    <extensions defaultExtensionNs="com.intellij"><checkinHandlerFactory implementation="org.example.untitled.CheckinHandlerFactory"/></extensions>

GUI

GUI 是 IntelliJ IDEA 提供的一个自动生成 java 布局代码的工具,它使用 JDK 中的 Swing 控件来实现 UI 界面。

面板编辑完成之后,点击Toolbar工具条那里的编译按钮。编译完成后,GUI的代码会生成在 对应的 Java文件里面。

Gradle Task

Gradle task 和 android studio的 类似,常用的也是打包、调试和发布task,只不过task 名不同。

更多说明和示例可见JetBrains/gradle-intellij-plugin

buildPlugin

buildPlugin  构建插件,常说的打包 插件包默认输出目录为build/distributions/插件名.zip

runIde

runIde 调试运行

现在双击runIde即可调出另外一个安装了这个插件的IDEA界面,然后可以看运行结果进行调试。 runIde还支持debug模式,不过运行时要右击选择:

如果setIdeDirectory设置为Android studio路径,则调试过程如下,会重新启动一个main(Android studio)

publishPlugin

publishPlugin 发布插件

上传插件市场

1、官方插件市场

官方文档:http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/publishing_plugin.html

2、自定义个人/公司插件存储服务器

Install

如果要安装的插件非JetBrains官方插件市场发布的插件,则需要配置插件存储服务器地址,才能在Marketplace搜索到然后install。

搜索但还未安装时,右侧会显示updatePlugins.xml文件中配置的插件信息;从硬盘选择安装或已安装的插件,会显示plugin.xml文件中配置的插件信息。

最后

到这里,一个IDE插件的的开发、配置、调试运行、发布、安装的基本流程就介绍完毕了。插件的应用非常广泛,可以应用所有基于IntelliJ Platform开发的IDE软件。如果想深入学习IDE插件开发,建议阅读官方文档。官方文档内容更加全面丰富,但是由于文档精炼、简洁,所以在学习过程中,很多地方需要我们去揣摩、整理和总结。

IntelliJ IDEA插件开发教程相关推荐

  1. [原创插件] [服务端插件] [新手开发者必看]优秀插件开发教程列表 欢迎回复讨论

    插件开发者专享套餐 声明:此集锦意在提升插件开发者的姿势水平, 插件版版主邀请编程版的海螺编写的,并非错版,请勿举报. 入门以前 在开始写插件之前,你需要知道插件基于 Java,所以请先学习 Java ...

  2. IntelliJ IDEA 使用教程(2019图文版) -- 从入门到上瘾

    作者:yizhiwazi(一只袜子) 来源:https://www.jianshu.com/p/9c65b7613c30 前言:IntelliJ IDEA 如果说IntelliJ IDEA是一款现代化 ...

  3. java定义语法解析器,java开发工具intellij idea使用教程:定义语法和解析器.pdf

    java开发工具intellij idea使用教程:定义语法和解析器.pdf 还剩 3页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,喜欢就下载吧,价低环保! 内容要点: 慧都 科技 -- ...

  4. 我的世界Bukkit服务器插件开发教程(十一)粒子、药水效果与音效

    十一.粒子.药水效果与音效 太简单了吧! 1.粒子效果 1.1.基本操作 播放粒子,首先需要确定粒子需要播放的位置.需要注意,我们一次只能播放一个粒子,如果需要播放多个粒子的话--也不麻烦. 播放粒子 ...

  5. WordPress插件开发教程1:开发第一个WordPress插件

    一.创建一个插件 第一步:在 wp-content \ plugins 目录新建一个目录,随便起个名字,比如:my-first-plugin.         第二步:进入 my-first-plug ...

  6. Intellij IDEA的教程资料

    Intellij IDEA的教程资料 官方文档(英文) 菜鸟教程-Intellij IDEA 使用教程 CSDN-史上最简单的 IntelliJ IDEA 教程(作者很用心,赞) 极客学院-Intel ...

  7. 我的世界Bukkit服务器插件开发教程(七)计分板

    七.计分板 写在前面 对于计分板,相信大部分人会认为这是一个计分的玩意.但不然,它的用处远远不止计分那样简单,计分板在服务器中起着重要的作用,在大部分插件中都有着它的身影. 另注:本章节有大量干货,请 ...

  8. java开发工具IntelliJ IDEA全面教程合集

    IntelliJ IDEA在业界被公认为优秀的Java开发平台之一,在智能代码助手.代码自动提示.重构.J2EE支持.Ant.JUnit.CVS整合.代码审查. 创新的GUI设计等方面表现突出,并支持 ...

  9. 我的世界Bukkit服务器插件开发教程(五)方块Blocks

    五.方块Blocks 我怕不更新会被骂,所以更了. 坐标系 小伙纸,求一下∑i=0∞i2\sum_{i=0}^\infty i^2∑i=0∞​i2(bushi 是的,你没猜错,我们要涉及到史上最NB超 ...

  10. 我的世界Bukkit服务器插件开发教程(十五)世界生成器

    十五.世界生成器 如果你仔细观察,会发现有个叫saves的文件夹,这个文件夹是用来存放存档的,即我们平常说的世界. 显然,服务器承担了创建世界.加载世界的任务.Bukkit 中也有专门生成世界的生成器 ...

最新文章

  1. ASP.NET Core 中文文档 第四章 MVC(2.2)模型验证
  2. linux设置默认时区,关于linux:如何修改-Linux-默认时区
  3. Spring MVC 验证码
  4. php数组函数序列之array_unshift() 在数组开头插入一个或多个元素
  5. vmware view由哪些组件组成?
  6. Light OJ 1078
  7. 【转】flash不建议设置wmode及wmode解释
  8. 安装vbb的一些经验(包括mysql,apache)
  9. CharSequence接口
  10. 选择易优cms建站的十大理由
  11. 快递查询网站php源码,全国快递查询PHP源码单号自动识别支持国内上百家快递
  12. h5显示微信公众号文章
  13. 资产初探:理财直接融资工具
  14. 【一文学会】vue.js入门到放弃
  15. SharePoint 常用开发工具
  16. java经纬度凸包graham_凸包算法(Graham扫描法)详解
  17. 当面试问到自己有哪些缺点应该怎么回答
  18. 校准曲线、标准曲线、工作曲线区别:点个数、曲线评价、有效期、模型
  19. 【高等数学】常用的三角函数与反三角函数
  20. 应用实践 | 海量数据,秒级分析!Flink+Doris 构建实时数仓方案

热门文章

  1. JavaScript入门思维导图
  2. 推荐 20 款 IDEA 主题!
  3. 计算机毕业设计的读书笔记,毕业设计之读书笔记
  4. 在android studio开发中,关于绘制GifView异常,硬件加速问题的解决办法
  5. 关于12306Bypass
  6. 马哥python开发培训
  7. NSSM通俗易懂介绍,安装与使用
  8. 【通信原理 入坑之路】 —— 详细理解傅里叶变换以及它在通信里面的应用
  9. si4438 的初始化
  10. ADS2017用分立电容电感匹配实例