跳转至

Dart VM 扩展开发

适用于支持 dartVmDevTool 扩展点的 FlutterX 版本

FlutterX 的 Dart VM ToolWindow 通过 shop.itbug.FlutterCheckVersionX.dartVmDevTool 扩展点开放 tab 能力。内置的 Vm、Memory、Http Monitor、Logging、Provider、Shared Preferences、Hive CE、Drift DB 都使用同一个扩展点注册,第三方插件也可以用同样的方式加入自己的 Dart VM DevTools。

接入方式

第三方插件需要先依赖 FlutterX,然后在 FlutterX 的命名空间下注册 dartVmDevTool。

<depends>shop.itbug.FlutterCheckVersionX</depends>

<extensions defaultExtensionNs="shop.itbug.FlutterCheckVersionX">
    <dartVmDevTool
        id="myTool"
        implementation="com.example.MyDartVmDevTool"
        descriptionKey="my.tool.description"
        order="after hive"/>
</extensions>

扩展属性

属性 是否必填 说明
id 是 稳定的 tab ID。FlutterX 会用它保存用户隐藏 tab 的设置,发布后不建议修改。
implementation 是 实现 shop.itbug.flutterx.api.vm.DartVmDevToolExtension 的类。
descriptionKey 否 多语言描述 key。FlutterX 会从贡献插件的 resource bundle 读取文本,并显示在 Dart VM 设置页里。
order 否 IntelliJ 扩展排序规则,例如 first、last、after hive、before drift。

如果没有配置 descriptionKey,或者 key 在 resource bundle 中不存在,设置页不会显示描述文本。

实现扩展类

扩展类建议保持无状态,不要在构造函数里执行耗时逻辑。真正的 UI 和 VM Service 访问应放到 createComponent 返回的组件生命周期里处理。

package com.example

import com.intellij.openapi.project.Project
import shop.itbug.flutterx.api.vm.DartVmDevToolContext
import shop.itbug.flutterx.api.vm.DartVmDevToolExtension
import java.awt.BorderLayout
import javax.swing.JComponent
import javax.swing.JLabel
import javax.swing.JPanel

class MyDartVmDevTool : DartVmDevToolExtension {
    override fun getTabTitle(project: Project): String = "My Tool"

    override fun isAvailable(context: DartVmDevToolContext): Boolean {
        return true
    }

    override fun createComponent(context: DartVmDevToolContext): JComponent {
        return JPanel(BorderLayout()).apply {
            add(JLabel("My FlutterX Dart VM tool"), BorderLayout.CENTER)
        }
    }
}

createComponent 返回的是 Swing JComponent。FlutterX 不把 Compose 或 Jewel 类型暴露给第三方插件,这样可以减少 Kotlin、Compose、Jewel 版本兼容问题。

读取运行中的 Flutter 应用

DartVmDevToolContext 提供当前项目、ToolWindow 和运行中的 Flutter 应用状态。

interface DartVmDevToolContext {
    val project: Project
    val toolWindow: ToolWindow
    val runningApps: StateFlow<List<DartVmApp>>
}

runningApps 是动态状态。如果用户先打开 FlutterX Dart VM ToolWindow,再启动 Flutter 应用,扩展组件需要订阅 context.runningApps 才能收到更新。

interface DartVmApp {
    val appId: String
    val vmUrl: String
    val deviceId: String
    val mode: String
    val vmService: VmService
}

可以通过 DartVmApp.vmService 调用 Dart VM Service RPC。VM 调用可能耗时或失败,不要阻塞 EDT。

多语言描述

如果想在 Dart VM 设置页展示 tab 描述,可以配置 descriptionKey,并在第三方插件自己的 resource bundle 里提供文本。

<idea-plugin>
    <resource-bundle>messages.MyPluginBundle</resource-bundle>

    <depends>shop.itbug.FlutterCheckVersionX</depends>

    <extensions defaultExtensionNs="shop.itbug.FlutterCheckVersionX">
        <dartVmDevTool
            id="myTool"
            implementation="com.example.MyDartVmDevTool"
            descriptionKey="my.tool.description"
            order="after hive"/>
    </extensions>
</idea-plugin>
my.tool.description=Shows custom diagnostics collected from Dart VM Service.

用户显示和隐藏 tab

FlutterX 会在 Dart VM 设置页自动列出所有已注册的 Dart VM tab,包括第三方插件贡献的 tab。tab 默认显示,用户取消勾选后不会再显示。

隐藏设置通过扩展的 id 保存。已经发布的第三方插件不要随意修改 id,否则用户之前的显示或隐藏偏好会失效。

注意事项

  • v1 不支持第三方插件安装或卸载后即时刷新已经打开的 Dart VM tab,通常需要重新打开 ToolWindow 或重启 IDE。
  • 某个扩展创建组件失败时,FlutterX 会跳过该 tab,并继续加载其他 tab。
  • 使用 isAvailable 可以按项目、依赖或运行状态决定是否显示 tab。
  • 组件需要自己处理释放逻辑,避免后台协程、监听器或 VM Service 订阅泄漏。

验证

开发第三方扩展时建议验证以下场景:

  • ./gradlew compileKotlin 能通过。
  • ./gradlew verifyPluginStructure 能通过。
  • 打开 FlutterX Dart VM 后能看到第三方 tab。
  • order="after hive" 等排序规则生效。
  • 先打开 ToolWindow 再运行 Flutter 应用,订阅 runningApps 的 UI 能正常刷新。
  • 在 Dart VM 设置页取消勾选后,tab 不再显示;重新勾选后恢复显示。