IntelliJ IDEA插件开发教程
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>
注意:
- 一个 interface-class 不能有多个 implementation-class。
- 若组件没有创建 interface 类,而是直接实现了 ApplicationComponent 等接口,interface 和 implementation 可以指定为同一个类。
- 每一个组件都应该有一个唯一的名字,通过
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 在项目启动时共同加载。
一个组件加载过程:
- 创建:调用构造方法
- 初始化:调用
initComponent()
方法 - 如果是 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 卸载
一个组件卸载过程:
- 如果是 Project 或 Module 组件,调用
projectClosed()
- 接下来
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插件开发教程相关推荐
- [原创插件] [服务端插件] [新手开发者必看]优秀插件开发教程列表 欢迎回复讨论
插件开发者专享套餐 声明:此集锦意在提升插件开发者的姿势水平, 插件版版主邀请编程版的海螺编写的,并非错版,请勿举报. 入门以前 在开始写插件之前,你需要知道插件基于 Java,所以请先学习 Java ...
- IntelliJ IDEA 使用教程(2019图文版) -- 从入门到上瘾
作者:yizhiwazi(一只袜子) 来源:https://www.jianshu.com/p/9c65b7613c30 前言:IntelliJ IDEA 如果说IntelliJ IDEA是一款现代化 ...
- java定义语法解析器,java开发工具intellij idea使用教程:定义语法和解析器.pdf
java开发工具intellij idea使用教程:定义语法和解析器.pdf 还剩 3页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,喜欢就下载吧,价低环保! 内容要点: 慧都 科技 -- ...
- 我的世界Bukkit服务器插件开发教程(十一)粒子、药水效果与音效
十一.粒子.药水效果与音效 太简单了吧! 1.粒子效果 1.1.基本操作 播放粒子,首先需要确定粒子需要播放的位置.需要注意,我们一次只能播放一个粒子,如果需要播放多个粒子的话--也不麻烦. 播放粒子 ...
- WordPress插件开发教程1:开发第一个WordPress插件
一.创建一个插件 第一步:在 wp-content \ plugins 目录新建一个目录,随便起个名字,比如:my-first-plugin. 第二步:进入 my-first-plug ...
- Intellij IDEA的教程资料
Intellij IDEA的教程资料 官方文档(英文) 菜鸟教程-Intellij IDEA 使用教程 CSDN-史上最简单的 IntelliJ IDEA 教程(作者很用心,赞) 极客学院-Intel ...
- 我的世界Bukkit服务器插件开发教程(七)计分板
七.计分板 写在前面 对于计分板,相信大部分人会认为这是一个计分的玩意.但不然,它的用处远远不止计分那样简单,计分板在服务器中起着重要的作用,在大部分插件中都有着它的身影. 另注:本章节有大量干货,请 ...
- java开发工具IntelliJ IDEA全面教程合集
IntelliJ IDEA在业界被公认为优秀的Java开发平台之一,在智能代码助手.代码自动提示.重构.J2EE支持.Ant.JUnit.CVS整合.代码审查. 创新的GUI设计等方面表现突出,并支持 ...
- 我的世界Bukkit服务器插件开发教程(五)方块Blocks
五.方块Blocks 我怕不更新会被骂,所以更了. 坐标系 小伙纸,求一下∑i=0∞i2\sum_{i=0}^\infty i^2∑i=0∞i2(bushi 是的,你没猜错,我们要涉及到史上最NB超 ...
- 我的世界Bukkit服务器插件开发教程(十五)世界生成器
十五.世界生成器 如果你仔细观察,会发现有个叫saves的文件夹,这个文件夹是用来存放存档的,即我们平常说的世界. 显然,服务器承担了创建世界.加载世界的任务.Bukkit 中也有专门生成世界的生成器 ...
最新文章
- ASP.NET Core 中文文档 第四章 MVC(2.2)模型验证
- linux设置默认时区,关于linux:如何修改-Linux-默认时区
- Spring MVC 验证码
- php数组函数序列之array_unshift() 在数组开头插入一个或多个元素
- vmware view由哪些组件组成?
- Light OJ 1078
- 【转】flash不建议设置wmode及wmode解释
- 安装vbb的一些经验(包括mysql,apache)
- CharSequence接口
- 选择易优cms建站的十大理由
- 快递查询网站php源码,全国快递查询PHP源码单号自动识别支持国内上百家快递
- h5显示微信公众号文章
- 资产初探:理财直接融资工具
- 【一文学会】vue.js入门到放弃
- SharePoint 常用开发工具
- java经纬度凸包graham_凸包算法(Graham扫描法)详解
- 当面试问到自己有哪些缺点应该怎么回答
- 校准曲线、标准曲线、工作曲线区别:点个数、曲线评价、有效期、模型
- 【高等数学】常用的三角函数与反三角函数
- 应用实践 | 海量数据,秒级分析!Flink+Doris 构建实时数仓方案