乐趣区

关于android:Android-Studio-IDE-插件开发

作者:字节跳动终端技术——周宸韬

概述

这篇文章旨在向读者介绍 IntelliJ IDE 插件的开发流程以及罕用的一些通用性能,任何基于 IntelliJ 开发的 IDE 都能够通过该形式制作插件,例如 Android Studio(AS),本篇也将基于 Android Studio 进行开展介绍,读者将从 0 到 1 学习到 Android Studio 插件开发。

背景介绍

什么是 IDE 插件、IDE 插件能做什么?

IDE 插件是将一些性能集成到了 IDE 界面当中,当咱们应用 IDE 进行开发工作时能很不便的通过 UI 界面应用这些性能,例如大家相熟的 project 工程目录,Gradle 工具栏,IDE 底部的 Run、Terminal、Build 界面等,都是通过 IDE 插件来实现的,能够说大部分须要通过命令行执行、或用户手动的一些操作都能够通过插件实现,并以 UI 的模式出现。

如下图:左图为 Android Studio IDE 界面右侧 Gradle 工具栏,蕴含了很多 Gradle 工作,点击 UI 的成果等同于用户在命令行中输出 Gradle 命令。右图为 IDE 顶部菜单栏版本控制局部,其中对于版本的提交、拉取等按钮等价于命令行输出对应指令。

<center class=”half”>

 <img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin1.png" width="300"/><img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin2.png" width="300"/> </center>

为什么要做 Android Studio IDE 插件?

笔者作为中台部门开发者,常常波及到一些通用的性能的开发,并以工具或组件等模式交由内部应用。所以如何升高用户学习老本、进步工作效率是我的指标,而这些优化方向都离不开奇妙的应用工具。例如本次要介绍的 IDE 插件的开发背景就是以此为指标:将本来须要应用命令行实现的工作、或者学习老本较高的操作通过 UI 进行包装,并且附丽在原生的 AS 界面中,通过 UI 的交互大幅升高用户学习老本,同时晋升应用体验。

举例比照一下,上面两幅图片是某个工程主动搭建性能的截图,左右两图别离为应用命令行和应用 AS 插件的体验比照,能够看到左侧在应用 CLI 命令行进行工程搭建时界面信息不够简洁明了,且用户交互体验较差,用户必须在应用前浏览文档,并且没有容错机制,输错就得从头开始。而雷同的性能应用右侧 AS 插件的体验则好很多,不仅各条信息分明明了,还能拓展更多细节性能,如动静测验用户输出,输出无误才可进行下一步等等,用户齐全能够在零常识背景的状况下应用该插件并轻松实现所有性能操作,而且靠近原生的界面更好看。

<center class=”half”>

 <img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin3.png" width="400"/><img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin4.png" width="400"/> </center>

如何开发一个 IDE 插件?

筹备工作

在开发第一个插件前,咱们要下载正确的开发工具,在 JetBrain 官网中下载 IntelliJ IDEA 下载链接

这里应用的开发工具是 IntelliJ IDEA 而不是 Android Studio,因为 AS 是基于 IntelliJ 为模版开发的,IDE 插件必须通过 IntelliJ 开发、公布,再装置到 Android Studio 中能力应用。

咱们须要确认咱们应用的 Android Studio 是基于哪个 IntelliJ 版本。这很重要,和你以后应用的 Android Studio 版本雷同能让你在调试时很不便,而新版的 IntelliJ 蕴含的 features 在你应用的 AS 上可能并没有,导致插件无奈装置,或提醒兼容性报错。(图中的报错也会呈现在未开启向高版本兼容时产生,开发时按需开启)。

<center class=”half”>

 <img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin5.png" width="400"/></center>

下载时请追随这个步骤:

  1. 关上你的 Android Studio,查看版本号(The Build Number),这就是咱们须要的 IntelliJ 版本号。
  2. 在下载页面,点击 Other versions,找到对应的 IntelliJ 版本,下载安装即可。

<center class=”half”>

 <img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin6.png" width="300"/><img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin7.png" width="500"/> </center>

创立新的工程 + 配置

这部分也可参照官网:https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started.html

  1. 创立新工程蕴含两个向导页面,【抉择工程模版框架 + 填写插件工程信息】,按图中配置即可。

<center class=”half”>

 <img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin8.png" width="350"/><img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin9.png" width="350"/><img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin10.png" width="100" hight="300"/> </center>
  1. 实现两步向导程序后主动创立工程,咱们须要先理解两个外围文件:【build.gradle + plugin.xml】,并做一些前置的配置工作。

build.gradle

因为 build.gradle 和 Android 工程中的构建文件十分相似,这里只解释 Android 中没有的配置。

  • version:intellij 闭包创立时只带一个属性 version,该属性代表用来构建这个插件的 IntelliJ 平台 IDE 的版本,如果咱们在开发时调用【runIde】这个 Gradle task,一个基于这个版本的 IntelliJ IDE 实例就会被创立。
  • localPath:因为咱们心愿在 AS 的环境下测试咱们的插件,所以咱们须要将 AS 作为咱们插件的一个依赖,减少一个属性叫 localPath 指定本机 Android Studio 应用程序 Contents 的装置目录,一个基于这个版本的 Android Studio 实例就会被创立(留神 localPath 不能和 version 属性同时应用,因为咱们本地的 AS 门路中曾经有了版本信息)。
  • plugins:增加开发须要的依赖插件。能够在这里增加很多咱们想用的插件,比方咱们想在插件中执行 git 命令,咱们能够增加’git4idea‘plugin。
intellij {
    version '2020.1.4'
    localPath '/Applications/Android Studio.app/Contents'
    plugins = ['Kotlin','android','git4idea']
}

plugin.xml

在 resource 文件夹下能够找到 plugin.xml 文件,这个文件中能够配置咱们插件的各项属性,外围性能是注册咱们插件蕴含的 components 和 service(性能类实现后还须要在这里进行注册能力应用,相似在 AndroidManifest.xml 中申明 Activity 和 Service)。

  • 申明咱们的插件须要并且和 AS 相兼容:减少 android 和 android studio modules 作为依赖。
<idea-plugin>
    ...
    <depends>com.intellij.modules.platform</depends>
    <depends>org.jetbrains.android</depends>
    <depends>com.intellij.modules.androidstudio</depends>

    <extensions defaultExtensionNs="com.intellij">
        <!-- Add your extensions here -->
    </extensions>

    <actions>
        <!-- Add your actions here -->
    </actions>

</idea-plugin>

运行插件

配置实现后咱们能够尝试运行插件工程,具体位置在 Gradle 工具栏 项目名称 /Tasks/intelliJ/runIde门路。运行 runIde 工作,因为咱们配置了 Android Studio 为启动门路,所以一个 Android Studio 模仿 IDE 会关上,所有内容都和咱们本地的 Android Studio 没有差异。

<center class=”half”>

 <img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin11.png" width="270"/><img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin12.png" width="670"/> </center>

IDE 插件罕用性能介绍

创立一个 Action

什么是 Action?

Actions 官网介绍: The system of actions allows plugins to add their own items to IDEA menus and toolbars. An action is a class, derived from the AnAction.

Actions 是用户调用插件性能最常见的形式,如下图的工具目录是开发者常常用到的,外面所有的可选项都是一个 Action,能够进一步开展的则是 Action Group。

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin13.png" width="500"/> </center>

如何创立一个 Action?

两个步骤:

  • 【code implementation – 实现 Action 的具体代码逻辑】:决定了这个 action 在哪个 context 下无效,并且在 UI 中被抉择后的性能(继承父类 AnAction 并重写 actionPerformed()办法,用于 Action 被执行后的回调)。
  • 【registered – 在配置文件中注册】:决定了这个 action 在 IDE 界面的哪个地位呈现(创立新的 group 或寄存进现有的 ActionGroup,以及在 group 中的地位)。

两个条件达成,action 就能够从 IntelliJ Platform 中取得用户执行动作后的回调,例子:‘HelloWorld’。

Code implementation

class HelloWorldAction : AnAction() {override fun actionPerformed(event: AnActionEvent) {
        // 这里创立了一个音讯提醒弹窗,在 IDE 中展现“Hello World”val notificationGroup = NotificationGroup(
            displayId = "myActionId",
            displayType = NotificationDisplayType.BALLOON
        )

        val notification = notificationGroup.createNotification(
            title = "chentao Demo",
            content = "Hello World",
            type = NotificationType.INFORMATION
        ).notify(event.project) // 从办法的 Event 对象中获取到以后 IDE 正在展现的 project,在该 project 中展现弹窗
    }
}

Registering a Custom Action

<actions>
    <!-- Add your actions here -->
    <!-- 创立了一个 ActionGroup -->
    <group id = "ChentaoDemo.TopMenu"
           text="ChentaoDemo Plugin"
           description="Demo Plugin in top menu">
           <!-- 注册 HelloWorld Action -->
        <action class="com.chentao.demo.actions.HelloWorldAction"
                id="DemoAction"
                text="Hello World Action"
                description="This is a test action">
                <!-- 设置 HelloWorld Action 的键盘快捷键 -->
            <keyboard-shortcut first-keystroke="control alt p" keymap="$default"/>
            <!-- 将 HelloWorld Action 增加到剪切拷贝组中 -->
            <add-to-group group-id="CutCopyPasteGroup" anchor="last"/>          
        </action>
        <!-- 将这个 Group 增加到主菜单 -->
        <add-to-group group-id="MainMenu" anchor="last"/>
    </group>
</actions>

运行插件 – 后果展现

实现了以上两步后,运行runIde Task,顶部的主菜单栏开端呈现了咱们增加的 ActionGroup,开展可看见 HelloWorldAction,点击 Action,右下角弹出“Hello World”提示信息。咱们不仅能够创立 Group 来搁置 Action,还能够将 Action 增加进 IDE 已有的 Group 当中,如下左图中,咱们将 HelloWorld Action 增加进了 IDE 的 CutCopyPasteGroup,和复制粘贴等 Action 放在了一起。

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin14.png" width="800"/> </center>

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin15.png" width="400"/><img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin16.png" width="400"/> </center>

plugin.xml 文件中 actions 的 group 能够更为简单,group 能够互相蕴含,并造成工具栏或菜单(如下图),有趣味的同学能够拉取 Demo(文章开端)体验一下。

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin17.png" width="800"/> </center>

向导程序 Wizard

Wizard 意为向导程序,就是指引使用者实现某个性能的程序,通常为单个或多个指引界面组成。例如上面两幅图为 Android Studio 中经典的创立新工程窗口,就蕴含两个页面的向导程序。上面将介绍如何制作出和图中主题完全相同的向导程序。

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin18.png" width="480"/><img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin19.png" width="480"/> </center>

向导程序的根底类属于 android.jar,由以下几个外围类形成:

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin20.png" width="300"/> </center>

1. ModelWizard

向导程序的“主类”,一个 ModelWizard 蕴含了一个 ModelWizardStep 的队列(Step 队列是一个有序的队列,并且每个 Step 都蕴含了它的下一个 Step 的援用),当一个 ModelWizard 完结时,它会遍历所有 steps,拜访 step 对应的 WizardModel,并调用 WizardModel#handleFinished()办法。

2. ModelWizardStep

一个 Step 就是 Wizard 向导程序中的一个独自页面,它负责创立一个 UI 界面出现给用户,确定页面上的信息是否无效,并且将用户数据保留在对应的 WizardModel 对象中。

3. SkippableWizardStep

能够设置可见性的 Step,能够通过前一个 Step 来管制跟在其后的 Step 可见性,例如一个 Step 提供了一些选项给用户,并依据用户的抉择来决定之后哪些 Steps 能够被展现。

4. WizardModel

Model 就是数据的汇合,这些数据由 wizard 中的每个 step 进行填充。多个 step 能够共享同一个 model,外围的办法是 handleFinished(),当用户在向导程序中点击了“Finish”按钮时,wizard 完结,这个办法将会被调用进行最终的逻辑解决。

Wizard 向导程序工作流程图

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin21.jpeg" width="900"/> </center>

创立一个 Android Studio 款式的向导程序

同样在 android.jar 库中,和 wizard 同级的名叫 ui 的包中提供了一个很不便的类,帮忙使用者创立 AS 款式的 ModelWizard,只需将 ModelWizard 对象作为参数放入 StudioWizardDialogBuilder 的结构器中即可。应用 AS 款式包装咱们的插件 UI 能让用户应用时更有原生的感觉,体验更好。

class CreateNewProjectAction : AnAction() {override fun actionPerformed(e: AnActionEvent) {
        StudioWizardDialogBuilder(ModelWizard.Builder().addStep(NewProjectStep()).build(),
            "Create New MARS Project"
        ).build().show()
    }
}

class ProjectWizardModel : WizardModel() {
    // 记录一些心愿保留的字段
      //...
    override fun handleFinished() {// 解决最初的逻辑}
}

class NewProjectStep : ModelWizardStep<ProjectWizardModel?>(ProjectWizardModel(), "Create MARS Project") {

    init {// 创立 Step 页面的 UI}
    // 链接下一个 Step
    override fun createDependentSteps(): MutableCollection<out ModelWizardStep<*>> {return arrayListOf(SelectBaselineStep(model))
    }
}

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin22.png" width="480"/><img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin23.png" width="480"/> </center>

Tool Windows

Tool Windows 是 IDE 的子窗口。这些窗口通常都在 IDE 主窗口的“边框”上领有属于本人的一个 tool window button,点击后将在 IDE 主窗口的左、右、下侧激活 panel 来展现信息。如下图左一 Gradle 工具栏。创立 Tool Window 须要提供一个 JPanel,并通过 ToolWindowFactory 来实现。

ToolWindowFactory

Performs lazy initialization of a tool window registered in {@code plugin.xml}.

使用者必须创立 ToolWindowFactory 的实现类,并实现 createToolWindowContent()办法,在该办法中初始化 tool Window 的 UI,并增加到 Android Studio 中。ToolWindowFactory 提供了懒加载机制,这样实现的益处是未应用的工具窗口不会减少启动工夫或导致内存应用方面的任何开销:如果用户没有与该工具窗口交互,相干代码就不会被加载和执行。

public class MyToolWindowFactory implements ToolWindowFactory {

    @Override
    public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
        // 初始化自定义组件对象
        MyToolWindow myToolWindow = new MyToolWindow(project, toolWindow);

        // 组件增加到 AS 中
        ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
        Content content = contentFactory.createContent(myToolWindow.getContent(), "", false);
        toolWindow.getContentManager().addContent(content);
    }
}

在插件中应用 Tool Windows 有两种模式:

  • declarative setup:能够了解为动态,在 plugin.xml 文件中注册,始终可见用户随时都能够应用。
  • Programmatic Setup:通过 API 接口动静注入,能够在一些操作前后呈现和暗藏。

Declarative Setup

<extensions defaultExtensionNs="com.intellij">
    <!-- Add your extensions here -->
    <toolWindow id="MyToolWindow" secondary="true" anchor="right" factoryClass="com.volcengine.plugin.toolwindow.MyToolWindowFactory"/>
</extensions>

Programmatic Setup

updateBaselineBtn.addActionListener(e -> {BaselineWindow baselineWindow = new BaselineWindow(versionsJson, project, toolWindow);
    ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
    Content content = contentFactory.createContent(baselineWindow.getContent(), "", false);
    toolWindow.getContentManager().addContent(content);
    toolWindow.getContentManager().setSelectedContent(content);
});

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin24.png" width="320"/>

<img src=”http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin25.png” width=”320″/>

<img src=”http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin26.png” width=”320″/> </center>

UI创立工具

Wizard 向导程序和 Tool Window 工具栏都须要 UI 作为面板内容的填充,基本上来说,须要的只是一个内容丰盛的 JPanel 作为 Content。AS 插件中的 UI 大量的应用了 Java Swing 组件,所以对 Swing 比拟相熟的同学上手会很快,这里介绍几种在 AS 插件中生成 UI 的技巧。

GUI Form

New –> Swing UI Designer –> GUI Form 填写信息后就会生成对可视化的.form 文件以及绑定的 java 类,在对应的 java 文件中减少一个 getRootPanel 办法获取 root panel 就能够将构建好的 Panel 给到向导程序或工具栏中应用。

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin27.png" /> </center>

Eclipse – WindowBuilder

下面提到的 GUI Form 有一个毛病,只能应用 Java,并且.fome 文件和.java 文件强绑定,咱们也无奈独自应用这个生成的 java 文件,并且当咱们想编写纯 Kotlin 代码时,GUI Form 就显得不好用了。

Eclipse 是少数同学刚接触 Java 时应用的经典 IDE,其中有一个 WindowBuilder 插件同样能够可视化创立 GUI 界面,然而相比于 GUI Form,WindowBuilder 生成的是独自的.java 文件,用户在 GUI 可视化界面操作的每个步骤都会生成对应的源码,咱们能够间接 copy 这些代码到 AS 插件当中,并应用“convert java code to Kotlin”性能,将这些代码一键转为 Kotlin 代码,十分不便(更重要的是,WindowBuilder 的应用体验集体感觉更好)。

<center class=”half”>

<img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin28.png"/>
    <img src="http://lf3-client-infra.bytetos.com/obj/client-infra-images/ASPlugin29.png"/>

</center>

Kotlin UI DSL

IntelliJ 插件官网提供的一些基于 Kotlin 的畛域特定语言,能够在 Kotlin 代码中写 UI,长处是代码柔美,毛病是累,具体可参考官网的指引 https://plugins.jetbrains.com…

数据长久化

有时咱们心愿能保留用户在插件中的操作或一些配置,防止反复的工作以及必要数据的读取,或防止用户反复屡次输出。IntelliJ Platform 提供了一些不便的 API 来做数据长久化。

Plugin Service

这是 IntelliJ 插件开发中的根底能力,分为三种不同的类型,当咱们想要在 IDE 插件的不同生命周期进行一些状态和逻辑上的解决,就能够应用这三种服务,例如:长久化状态、订阅事件、Application 启动 / 敞开时、Project 被关上 / 敞开时。

Service 接口类型 作用形容
Application Level IDEA 启动时会初始化,IDEA 生命周期中仅存在一个实例
Project Level IDEA 会为每一个 Project 实例创立一个 Project 级别的实例
Module Level IDEA 会为每一个 Project 的加载过的 Module 实例 Module 级别的实例,在多模块我的项目中容易导致内存泄露

这块代码是模仿在 IDE 启动时,主动测验以后是否存在新版本的性能,若有新版本则进行更新操作,就是应用了长久化存储来实现的。

@State(name = "DemoConfiguration", storages = [Storage(value = "demoConfiguration.xml")
])

class DemoComoponent:ApplicationComponent, PersistentStateComponent<DemoComoponent>, Serializable {
    var version = 1
    var localVersion = 0;

    private fun isANerVersion() = localVersion < version

    private fun updateVersion(){localVersion = version}

    override fun initComponent() {if(isANerVersion()){updateVersion()
        }
    }

    override fun getState(): DemoComoponent? = this
    override fun loadState(state: DemoComoponent) {XmlSerializerUtil.copyBean(state, this)
    }
}

长久化存储的两种形式

1. PropertiesComponent

这是一个简略的 Key-Value 数据结构,能够当作 Map 应用,用于保留 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)

2. PersistentStateComponent

简单类型的数据结构应用 PersistentStateComponent,能够指定长久化的存储地位。

public interface PersistentStateComponent<T> {
  @Nullable
  T getState();
  void loadState(T state);
}
  1. 创立一个 PersistentStateComponent 的实现类,T 示意须要长久化的数据结构类型,能够是任意类,甚至是实现类自身,而后重写 getState 和 loadState 办法。
  2. 若要指定存储的地位,须要在浮现类上减少 @State 注解。
  3. 若不心愿其中的某个字段被长久化,能够在该字段上减少@Transient 注解。
@State(
    name = "ChentaoPlugin" ,
    storages = [Storage("chentao-plugin.xml")]
)

class AarCheckBoxSettings :PersistentStateComponent<HashMap<String, AarCheckBoxState>> {var checkBoxStateList = HashMap<String, AarCheckBoxState>()

    override fun getState(): HashMap<String, AarCheckBoxState>? {return checkBoxStateList}
    override fun loadState(stateList: HashMap<String, AarCheckBoxState>) {checkBoxStateList = stateList}

    // 将长久化组件申明为 Serveice 的获取形式是通过 ServiceManager
    companion object{
        @JvmStatic
        fun getInstance(): PersistentStateComponent<HashMap<String, AarCheckBoxState>>{return ServiceManager.getService(AarCheckBoxSettings::class.java)
        }
    }
}
data class AarCheckBoxState(val componentId:String, val isSelected:Boolean)
注册长久化组件

PersistentStateComponent 的实现类须要在 plugin.xml 中注册为 Service 后应用。

<extensions defaultExtensionNs="com.intellij">
    <applicationService serviceImplementation="com.volcengine.plugin.actions.AarCheckBoxSettings"/>
</extensions>

插件打包与装置

  • 打包:在 Gradle 工具栏中运行 assemble 工作,即可在 /build/distribution/{插件名称}-{插件版本}.zip 门路下找到打包好的插件 zip 包。
  • 本地装置:还没将插件公布到插件市场前咱们能够抉择装置本地插件,关上 AS 菜单栏 /Android Studio/Preference/Plugins/Install Plugin from Disk… 装置后即可应用。
  • 公布插件市场:

    • 拜访 https://hub.jetbrains.com/,创立账号。
    • 应用账号登陆 jetbrains marketplace https://plugins.jetbrains.com/,公布插件(需官网审核 2 个工作日)。
    • 插件的第一个版本都须要在网站手动上传,之后的版本能够应用 hub 账号中的 token 自动更新。

总结

回顾开发过程:IDE 插件的外围步骤:装置正确版本 IntelliJ –> 配置工程 –> 创立 Action –> 将简单流程注入 Wizard 向导程序或 ToolWindow 工具栏(同时创立 UI) –> 应用数据长久化保留必要数据 –> 打包 & 装置 & 公布。

笔者感觉 IDE 插件开发的难点次要是摸索的过程,IDE 插件较冷门,网上介绍的文章很少,官网介绍了一些性能和组件后也没有具体的 API 指引,令人有点无从下手。最终,通过反编译查看一些官网插件(Firebase、Flutter 等)的源码,以及收集 Google、Youtube 和各大博客的信息,终于将 AS 插件的一期雏形打造结束,也将学到的一些罕用的通用能力在本文中进行整顿,心愿能帮到之后想要接触 AS 插件开发的同学。

Demo

https://github.com/ChentaoZho…

对于字节终端技术团队

字节跳动终端技术团队 (Client Infrastructure) 是大前端根底技术的全球化研发团队(别离在北京、上海、杭州、深圳、广州、新加坡和美国山景城设有研发团队),负责整个字节跳动的大前端基础设施建设,晋升公司全产品线的性能、稳定性和工程效率;反对的产品包含但不限于抖音、今日头条、西瓜视频、飞书、懂车帝等,在挪动端、Web、Desktop 等各终端都有深入研究。

就是当初!客户端/前端/服务端/端智能算法/测试开发 面向寰球范畴招聘! 一起来用技术扭转世界 ,感兴趣请分割 [chenxuwei.cxw@bytedance.com](mailto:chenxuwei.cxw@bytedanc…),邮件主题 简历 - 姓名 - 求职意向 - 冀望城市 - 电话

字节跳动利用开发套件 MARS 是字节跳动终端技术团队过来九年在抖音、今日头条、西瓜视频、飞书、懂车帝等 App 的研发实际成绩,面向挪动研发、前端开发、QA、运维、产品经理、项目经理以及经营角色,提供一站式整体研发解决方案,助力企业研发模式降级,升高企业研发综合老本。

退出移动版