Alexey Efimov
IntelliJ IDEA插件开发基础
Note:
IntelliJ IDEA插件开发入门指南
这篇文章将帮助你了解IntelliJ IDEA插件开发的基础知识,快速开发自己的插件。它讲解了日常插件开发的基本原则、语
法描述和插件发布,同时包含了一个插件例子 ,一步步教你如何去开发插件。当你读完这篇文章后,你可以试用一下文
章中开发的插件:
你需要依据如何开始段落中的步骤1和2建立IntelliJ IDEA JDK.
SampleProject.zip (242 Kb)
内容
约束条件
介绍
获取插件
如何开始
步骤1
步骤2
步骤3
步骤4
插件是如何工作的?
IntelliJ IDEA的组件模型
加载组件
卸载组件
组件容器
HelloWorld 插件
创建组件
约束条件
创建 Action
第一个插件
添加配置
插件的结构描述
插件标识
插件间的依赖关系
版本和编译版本号
组件注册
本地化
插件发布
创建归档
上传插件至插件库
通报新插件
总结和常用链接
这篇文章假设你正在使用IntelliJ IDEA 5.1或更高版本, 或者是高于EAP#4121的版本。 文章中涉及到的一些IntelliJ IDEA
Open API 中特性或类可能在以前的版本中并不存在。
介绍
在IntelliJ IDEA中, 插件是独立的模块,它可以通过手动和内置工具的方式加载到IntelliJ IDEA中。
IntelliJ IDEA的插件依据他们的功能可以进行分组,主要包括:
代码审查和重构 (Inspection Gadgets, Intension Power Pack, Refactor-J, Refactor-X等等)
自定义编辑器 (例如 Images)和工具窗口 (SQLQuery, PsiViewer等)
其他语言支持 (Groovy, JavaScript等)
应用服务器整合(Resin, JBoss, Tomcat等)
版本控制系统整合 (CVS, Clearcase等)
框架和其他技术支持(Hibernate Tools, IdeaSpring, XPathView, Struts等)
外部应用整合 (Jira Browser, JFormdesigner等)
用户界面提升, 各种工具栏和菜单 (TabSwitch, CVS bar等)
自定义编译器 (Native2Ascii)
其他:包括各种工具插件和游戏(IdeaJad, simpleUML, Tetris, Sokoban等)
目前IntelliJ IDEA为插件开发人员提供了各种特性和功能,因此IDEA很多的特性都可以被扩展。在IntelliJ IDEA 5.0之前版本,
没有提供对其他语言的支持,现在IDEA可以以插件的方式支持各种语言,如JavaScript,CSS, Groovy, SQL等等. 渐渐地,通过
版本 更新,IntelliJ IDEA将为插件开发人员提供特性,这些将通过 IntelliJ IDEA Open API 呈现出来。
下面就是一些比较受欢迎的IntelliJ IDEA插件:
TabSwitch:小巧, 但非常实用。它允许你在打开的各个文件中进行切换,就象使用Alt+Table快捷键切换Windows应用一
样。
SQL Query:在IDE工具就可以编写并执行数据库查询语句,有时该工具就象呼吸一样非常必要。
Regex: 运行你在IDEA中校验各种正则表达式。
XPathView:在编辑窗口中提供了XML文件的XPath处理能力.
获取插件
已经在插件库中注册过的插件可以点击File->Settings->Plugins 菜单,插件管理器将会添加、更新和删除相关插件。如果你做
了相关的操作,需要你重新启动IDEA使其生效。
首先下载插件列表,只需点击Available标签。如果你是通过代理服务器联到Internet,请点击 HTTP Proxy Settings按钮,输
入正确的信息。 IntelliJ IDEA会向插件库(http://plugins.intellij.net)发出请求,列出适用当前版本IDEA的所有插件。你只需
在列表中选择该插件,然后点击下载图标,就可以安装该插件。以这种方式,你可以安装更多的插件。
如何开始插件开发?
假想你现在决定开发一个插件来满足你同事的强烈需求,行,让我们开始吧。
首先需要创建一个项目来包含你的插件。
步骤 1
如果你还没有下载Plugin Development Package,请先下载此开发包.
如果你使用EAP版本进行插件,你可以下载EAP的插件开发包,文件如idea4121-dev.zip,该文件位于IntelliJ IDEA EAP
Access页面(4121是EAP的编译版本号)。
如果你想下载发布版本的插件开发包,请访问IntelliJ IDEA Plugin Developers页面,点击Plugin Development链接去下载开发
包文件,
解压下载的开发包文件至IntelliJ IDEA的安装目录。
注意:
开发包仅包括插件源码和IntelliJ IDEA Open API 的Javadoc文档,所以及时没有该开发包你同样进行插件开发。然后我们
推荐你下载并安装该开发包,它会让你的开发更加便捷。
步骤 2
解压插件开发包以后,我们需要创建一个项目来编写我们的插件。
点击File->New Project菜单项,输入项目名称,如"idea-plugins",然后设定项目的存储路径,点击Next。
插件开发需要特定类型的JavaTM SDK (JDK): IntelliJ IDEA SDK,它是Jdk标准库和IntelliJ IDEA Open API库的整合体,你可以
设置该SDK的JavaDoc和Source Code,这些信息可以在插件开发包找到。
点击Configure按钮,将会弹处Jdk设置窗口,点击Add IntelliJ IDEA SDK按钮(包含IDEA 图标的那个按钮),该按钮如下所
示:
选择IntelliJ IDEA的安装目录(实际上IDEA会自动选择),然后点击OK按钮。
接着, 将该SDK的名称改为 "idea" , Sandbox Home是保存运行IDEA各种配置参数和缓存的目录,IDEA会将插件拷贝到该目
录下进行调试,如果可能的话,请更改目录的sandbox存储目录。
注意:
这里我们推荐你不要使用IntelliJ IDEA的SDK版本号,如果你使用EAP版本的话, 这可能引起混乱,如"IDEA 4121"名称可能
在更高版本的IDEA的插件开发中引起误解。
点击OK按钮, 你会看到IntelliJ IDEA SDK会被显示在项目可用JDK的列表中。设置JDK你只需做一次,今后你只需从列表中选
择即可。
点击Next按钮。
步骤 3
在下一个对话框中,选择Create single-module project选项,然后点击Next按钮。
这是我们需要设定module类型,这里需要选择Plugin Module。
接着我们需要设定module的名称和路径,如果我们是初学者,就让我们创建传统的HelloWorld插件,这里module名称最好能
表达插件所代表的含义。
点击Next 按下;在下一个对话框中点击Finish即可。
步骤 4
恭喜你!你已经完成了插件项目的创建,。
在Project工具窗口中展开项目菜单树,找到plugin.xml文件 (在 META-INF 目录下),这是插件的描述文件,包含插件的各
种信息,如插件名称、描述、适用的IDEA版本号等等,同时包含component和action描述信息,该描述文件是IntelliJ IDEA加
载插件的依据。如果你创建了一个component,而没有在该描述文件中声明的话,IDEA并不会加载该component,请注意这
点。
plugin.xml文件包含各种信息,请不要忘记设定。
解下来让我们设定插件的描述文件,让其工作起来。这里我们设定插件名称, 描述和其他信息。让我们看一下since-build
属性,在后面的我们会进行具体描述,现在我们只需设置为Help->About对话框中的编译版本号即可。
META-INF/plugin.xml文件内容如下:
HelloWorld
This plugin does nothing
1.0
JetBrains
现在我们可以开始编写我们第一个插件啦。
插件是如何工作的?
在进行Hello World插件开发之前,我们想向大家介绍一下插件工作的原理。所有的class和interface都来自于IntelliJ IDEA
Open API 开发包,你可以在插件开发包中找到。
IntelliJ IDEA component模型
IntelliJ IDEA 包含多种组件模型,这些组件模型都是基于PicoContainer,组件都包含在这些容器中,但容器有不同的级别。
有三种级别的容器: application, project, 和 module. 在application级别上可以包含多个project级别的容器;而project级
别包含多个module级别容器。
Application Component 在IntelliJ IDEA程序中,Application Conponent仅以一个实例存在。创建application component,
只需实现ApplicationComponent 接口, 然后在plugin.xml文件的application-components区域进行声明。
Project components. 在每一个打开项目中,仅包含一个project component实例,因此在IntelliJ IDEA中可能包含多个
Project component实例。创建一个project component,只需实现ProjectComponent 接口,然后在plugin.xml文件的
project-components 区域进行声明即可。
Module components. 在没一个项目的module中,仅有一个module component实例,因此在一个项目中包含多个module-
level component实例,实例的数量就是项目中加载的module的数量。创建module component,只需实现ModuleComponent
接口,然后在plugin.xml 文件的module-components 区域进行声明。
project component的实例数并不等于IntelliJ IDEA打开的项目数量,而是大于打开的项目数。除了打开的项目包含项目组件,
另一个项目是Template Project,它是一个隐藏的项目,IDEA一直加载这个项目。
Component加载
Application Component在IDEA启动时加载。Project和module component在项目启动时共同加载。
一个组件通过调用以下函数来实例化:
1. 首先加载Component的构造函数。
2. 如果组件实现JDOMExternalizable接口,将会调用 readExternal 函数。
3. 接下来initComponent 函数将被调用。
4. 如果是project或module component,projectOpened 函数将会被调用。如果是module component,moduleAdded
函数会被调用。
如果希望在component中访问其他component,我们只需在该component的构造函数声明即可,在这种情况下,IntelliJ IDEA
自动实例化所依赖的component,因此在构造函数中,所依赖的组件依据被实例化啦。
有依赖关系的component实例化样例
package com.intellij.tutorial.helloWorld;
import ...
public class MyComponent implements ApplicationComponent {
private final MyOtherComponent otherComponent;
public MyComponent(MyOtherComponent otherComponent) {
this.otherComponent = otherComponent;
}
...
}
Component卸载
Application component在IDEA关闭时被卸载, Project和module component在项目关闭时被卸载。
在卸载component是,以下函数将会被调用:
1. 如果component实现了 JDOMExternalizable 接口,component的状态将会通过调用writeExternal 函数保存到xml文件
中。
2. 如果是project 或 module component,projectClosed 将会被调用。
3. 接下来disposeComponent将会被调用。
Component 容器
前面我们提到有三种不同的容器,application container实现Application 接口; project container 实现Project接口;
module 容器实现Module接口。 每一个容器都有自己的函数去获取容器内的component。
从application容器中获取组件例子:
Application application = ApplicationManager.getApplication();
MyOtherComponent otherComponent =
application.getComponent(MyOtherComponent.class);
获取application容器是非常容易的,在IDEA中application容器仅有一个(上面的例子就说明啦)。获取project和module容器可
能有点困难。通常我们在component构造函数声明或从action的事件处理的context的获取。
将容器以构造参数方式引入到component中
import ...
public class MyProjectComponent implements ProjectComponent {
private final Project project;
public MyProjectComponent(Project project) {
this.project = project;
}
...
public void foo() {
MyOtherProjectComponent otherProjectComponent =
project.getComponent(MyOtherProjectComponent.class);
}
}
在这个例子中,组件在构造函数中获取了容器对象,将其保存,然后在component其他方面进行引用。但是还是要注意这一
点。Be careful when passing this reference to other components (especially application-level ones). If an application-
level component does not release the reference, but saves it inside itself, all the resources used by a project or module
will not be unloaded from the memory on the project closing.
一个稍微复杂的例子就是在事件处理中获取容器,请看下面的例子。 DataContex类可以为action提供获取容器的方法,这个
class应该引起足够的注意。
在Action的事件处理中获取容器对象:
import ...
public class MyAction extends AnAction {
public void actionPerformed(AnActionEvent e) {
DataContext dataContext = e.getDataContext();
Project project =
(Project)dataContext.getData(DataConstants.PROJECT);
Module module =
(Module)dataContext.getData(DataConstants.MODULE);
}
}
HelloWorld 插件
现在让我们回到我们的HelloWorld插件,我们将增加一个新的component,它将弹处一个对话框显示"Hello World!"文本。
创建 Component
在项目中创建com.intellij.tutorial.helloWorld package。在该package点击鼠标右键,在弹出的菜单中点击New-
>Application Component菜单项,
输入component名称: HelloWorldApplicationComponent。
点击 OK按钮, IntelliJ IDEA 将会创建该组件同时会在plugin.xml文件中自动注册。
接下来让我们在该组件中添加sayHello 函数。我们将使用Messages 工具类去显示特定信息。
文件: /com/intellij/tutorial/helloWorld/HelloWorldApplicationComponent.java
package com.intellij.tutorial.helloWorld;
import ...
public class HelloWorldApplicationComponent implements
ApplicationComponent {
public void initComponent() {
}
public void disposeComponent() {
}
public String getComponentName() {
return "HelloWorldApplicationComponent";
}
public void sayHello() {
// Show dialog with message
Messages.showMessageDialog(
"Hello World!",
"Sample",
Messages.getInformationIcon()
);
}
}
创建 Action
我们已经创建了"Hello World" component,接下来我们需要添加一个菜单项来体验其功能。右击 helloWorld package,在
弹出的菜单中选择New->Action菜单项,输入Action的ID和类名,在Groups 列表中选择WindowMenu (Window)(请参考下面
的截屏)。