主要的插件类型
- UI主题插件
- 自定义语言支持插件
- 框架集成插件
- 工具集成插件
开发插件的三种方式
- Using Gradle
- Using GitHub Template
在github上选择一个模板,会自动根据模板生成一个配置好的插件项目,可以直接clone到本地开发 - Using DevKit
使用DevKit开发插件
设置开发环境
准备工作
确认启用Plugin DevKit插件,该插件是IDEA自带的插件
为项目配置IntelliJ Platform SDK
- 创建一个ntelliJ Platform SDK
- 指定sdk的位置
- 配置sdk源码路径,如果不需要debug此步可以跳过
- 设置沙箱目录, 插件项目的setting信息会保存在这个目录, 可以指定任意目录。
创建插件项目
启动配置
在Run Configuration菜单下配置启动配置, 配置jre。 点击run按钮,会启动一个ieda实例,并且启用当前开发的插件。
部署插件
- build项目或模块
- Prepare your plugin for deployment.
如果插件没有其他依赖,则会创建一个jar包,否则会创建一个zip压缩包。
发布插件
可以发布到自定义仓库或者发布到idea公共仓库
插件架构
插件jar包含的文件
- 插件配置文件plugin.xml
- 实现插件功能的类
- 插件依赖的jar包
插件ClassLoader
每个插件都使用独立的ClassLoader, 所以每个插件可以使用不同版本的依赖,不会相互影响。如果插件的classLoader没有发现某个类,则默认由IDEA的ckassLoader加载。但是可以在plugin.xml中的元素下声明依赖其它插件,那么就会使用其它插件的classLoader加载未找到的类。
Actions
action官方文档 Action是实现插件功能的类, 一个Action类需要继承AnAction并且实现actionPerformed方法。当用户点击菜单或者工具栏按钮, 按快捷键,或者通过Help | Find Action点击时, IntelliJ Platform系统会回调对应Action的actionPerformed方法。 Action会被分组, 一个组可以包含actions也可以包含子组,一个action组就是一个菜单或者工具栏,子组就是子菜单。
注册Action
通过plugin.xml注册action。
<actions>
<action
id="VssIntegration.GarbageCollection"
class="com.example.impl.CollectGarbage"
text="Garbage Collector: Collect _Garbage"
description="Run garbage collector"
icon="icons/garbage.png">
<override-text place="MainMenu" text="Collect _Garbage"/>
<override-text place="EditorPopup" use-text-of-place="MainMenu"/>
<synonym text="GC"/>
<add-to-group
group-id="ToolsMenu"
relative-to-action="GenerateJavadoc"
anchor="after"/>
<keyboard-shortcut
keymap="$default"
first-keystroke="control alt G"
second-keystroke="C"/>
<keyboard-shortcut
keymap="Mac OS X"
first-keystroke="control alt G"
second-keystroke="C"
remove="true"/>
<keyboard-shortcut
keymap="Mac OS X 10.5+"
first-keystroke="control alt G"
second-keystroke="C"
replace-all="true"/>
<mouse-shortcut
keymap="$default"
keystroke="control button3 doubleClick"/>
</action>
<action
id="sdk.action.PopupDialogAction"
class="sdk.action.PopupDialogAction"
icon="SdkIcons.Sdk_default_icon"/>
<group
class="com.example.impl.MyActionGroup"
id="TestActionGroup"
text="Test Group"
description="Group with test actions"
icon="icons/testgroup.png"
popup="true"
compact="true">
<action
id="VssIntegration.TestAction"
class="com.example.impl.TestAction"
text="My Test Action"
description="My test action"/>
<separator/>
<group id="TestActionSubGroup"/>
<reference ref="EditorCopy"/>
<add-to-group
group-id="MainMenu"
relative-to-action="HelpMenu"
anchor="before"/>
</group>
</actions>
扩展(Extensions)
扩展是插件最常用的一种扩展IDEA功能的方式, 只是这种方式没有直接把Action加到菜单或者工具栏那么直接。扩展功能是通过IDEA自带的或者其它插件提供的一些扩展点实现的。 声明扩展要在plugin.xml中添加标签。
<extensions defaultExtensionNs="com.intellij">
<appStarter implementation="com.example.MyAppStarter"/>
<projectTemplatesFactory implementation="com.example.MyProjectTemplatesFactory"/>
</extensions>
<extensions defaultExtensionNs="another.plugin">
<myExtensionPoint
key="keyValue"
implementationClass="com.example.MyExtensionPointImpl"/>
</extensions>
Service
Service是插件的一个组件, 是为了把公共的逻辑放到一起,Service的实例是单例的。 有三种类型的Service, 应用级别的,项目级别的,模块级别的。
声明Service有两种方式
-
类上加@Service注解,service不需要被重写的时候可以使用这种方式 -
在plugin.xml中声明,通过applicationService,projectService扩展点声明
<extensions defaultExtensionNs="com.intellij">
<applicationService
serviceInterface="mypackage.MyApplicationService"
serviceImplementation="mypackage.MyApplicationServiceImpl"/>
<projectService
serviceInterface="mypackage.MyProjectService"
serviceImplementation="mypackage.MyProjectServiceImpl"/>
</extensions>
获取Service
MyApplicationService applicationService = ApplicationManager.getApplication()
.getService(MyApplicationService.class);
MyProjectService projectService = project.getService(MyProjectService.class);
实现类可以封装静态方法,方便获取
MyApplicationService applicationService = MyApplicationService.getInstance();
MyProjectService projectService = MyProjectService.getInstance(project);
和其它Service交互
@Service
public final class ProjectService {
private final Project myProject;
public ProjectService(Project project) {
myProject = project;
}
public void someServiceMethod(String parameter) {
AnotherService anotherService = myProject.getService(AnotherService.class);
String result = anotherService.anotherServiceMethod(parameter, false);
}
}
Extension Points
声明扩展点 有两种类型的扩展点
- Interface 其它插件提供该接口的实现类
- Bean 其它插件提供子类, 这种方式其它插件可以设置一些扩展点类的属性值
<idea-plugin>
<id>my.plugin</id>
<extensionPoints>
<extensionPoint
name="myExtensionPoint1"
beanClass="com.example.MyBeanClass"/>
<extensionPoint
name="myExtensionPoint2"
interface="com.example.MyInterface"/>
</extensionPoints>
</idea-plugin>
扩展点类
public class MyBeanClass extends AbstractExtensionPointBean {
@Attribute("key")
public String key;
@Attribute("implementationClass")
public String implementationClass;
public String getKey() {
return key;
}
public String getClass() {
return implementationClass;
}
}
其它插件使用该扩展点
<idea-plugin>
<id>another.plugin</id>
<depends>my.plugin</depends>
<extensions defaultExtensionNs="my.plugin">
<myExtensionPoint1
key="someKey"
implementationClass="another.some.implementation.class"/>
<myExtensionPoint2
implementation="another.MyInterfaceImpl"/>
</extension>
</idea-plugin>
声明扩展点的类使用扩展点
public class MyExtensionUsingService {
private static final ExtensionPointName<MyBeanClass> EP_NAME =
ExtensionPointName.create("my.plugin.myExtensionPoint1");
public void useExtensions() {
for (MyBeanClass extension : EP_NAME.getExtensionList()) {
String key = extension.getKey();
String clazz = extension.getClass();
}
}
}
plugin.xml
这个示例配置文件除了Action的配置,其余配置全部都配置了。
<idea-plugin url="https://example.com/my-plugin-site">
<id>com.example.myplugin</id>
<name>My Framework Support</name>
<version>1.0.0</version>
<vendor
url="https://plugins.jetbrains.com/my-company"
email="contact@example.com">My Company</vendor>
<product-descriptor
code="PMYPLUGIN"
release-date="20210901"
release-version="20211"
optional="true"/>
<idea-version since-build="193" until-build="193.*"/>
<description>
<![CDATA[
Provides support for <a href="https://example.com/my-framework">My
Framework</a>.
<p>Includes support for:
<ul>
<li>code completion</li>
<li>references</li>
<li>refactoring</li>
</ul>
</p>
]]>
</description>
<change-notes>Initial release of the plugin.</change-notes>
<depends>com.intellij.modules.platform</depends>
<depends>com.example.third-party-plugin</depends>
<depends
optional="true"
config-file="mysecondplugin.xml">com.example.my-second-plugin</depends>
<resource-bundle>messages.MyPluginBundle</resource-bundle>
<extensionPoints>
<extensionPoint
name="testExtensionPoint"
beanClass="com.example.impl.MyExtensionBean"/>
<applicationService
serviceImplementation="com.example.impl.MyApplicationService"/>
<projectService
serviceImplementation="com.example.impl.MyProjectService"/>
</extensionPoints>
<applicationListeners>
<listener
class="com.example.impl.MyListener"
topic="com.intellij.openapi.vfs.newvfs.BulkFileListener"/>
</applicationListeners>
<projectListeners>
<listener
class="com.example.impl.MyToolwindowListener"
topic="com.intellij.openapi.wm.ex.ToolWindowManagerListener"/>
</projectListeners>
<actions>
<action
id="VssIntegration.GarbageCollection"
class="com.example.impl.CollectGarbage"
text="Collect _Garbage"
description="Run garbage collector">
<keyboard-shortcut
first-keystroke="control alt G"
second-keystroke="C"
keymap="$default"/>
</action>
</actions>
<extensions defaultExtensionNs="VssIntegration">
<myExtensionPoint implementation="com.example.impl.MyExtensionImpl"/>
</extensions>
<application-components>
<component>
<interface-class>com.example.Component1Interface</interface-class>
<implementation-class>com.example.impl.Component1Impl</implementation-class>
</component>
</application-components>
<project-components>
<component>
<implementation-class>com.example.Component2</implementation-class>
<option name="workspace" value="true"/>
<loadForDefaultProject/>
</component>
</project-components>
<module-components>
<component>
<implementation-class>com.example.Component3</implementation-class>
</component>
</module-components>
</idea-plugin>
|