# 硬件插件设置菜单

# 功能

通过配置设置菜单,可以完成非程序运行类的功能,如查看固件信息、升级固件、配网、搜索外设、展示传感器数值等,对积木块编程和使用硬件有一定的辅助作用。

# 组成

硬件插件设置菜单至少需要包含以下部分:

  • 图标
  • 菜单名
  • 菜单点击事件处理函数

如果还需要根据当前的连接方式、运行模式,来启用或禁用菜单(比如串口连接时,可以使用“串口监视器”,但蓝牙连接时,不能使用串口功能,菜单灰显),还需要配置:

  • 菜单支持的运行模式列表
  • 菜单支持的连接方式列表

# 定义方式

在插件入口文件中,找到 register 配置,使用 SettingMenuRegister 来配置插件菜单。

import type { UCodeExternalHardwareDefinition } from "@ubtech/ucode-extension-common-sdk/types";

const register: UCodeExternalHardwareDefinition.ExtensionRegister = {
  // ... 省略其他字段 ...
  // 配置插件菜单
  SettingMenuRegister: {
    ID_FIRMWARE_VERSION /* 菜单ID */: {
      type: "callback", // 无UI的逻辑菜单类型
      name: "查看固件版本", // 菜单名
      icon: firmwareInfoIcon, // 菜单图标
      availableDeviceTypes: [UDPDeviceType], // 菜单支持的连接方式
      availableWorkingModes: ["online"], // 菜单支持的运行模式
      callback: (util: { targetId: string }) => {
        // 菜单点击事件处理函数
        console.log("查看固件信息");
      },
    },
  },
};

self.UCode.extensions.register(register);

# 参数说明

SettingMenuRegister 类型声明如下:

  • 菜单基本数据:
type CommonSettingMenuItem<T = any> = {
  /**
   * 菜单名
   */
  name: string;
  /**
   * 菜单图标
   */
  icon: string;
  /**
   * 支持的设备连接类型,不支持将被禁用。比如一个菜单只能在串口下使用,在蓝牙连接方式下,会被禁用
   */
  availableDeviceTypes?: DeviceType[];
  /**
   * 支持的工作模式,不支持将被禁用。比如一个菜单只能在在线模式下使用,在烧录模式下,会被禁用
   */
  availableWorkingModes?: UCode.WorkingModeType[];
  /**
   * UI显示的额外参数
   */
  additionalData?: T;
};
  • 不带 UI 的设置菜单类型:
type CallbackSettingMenuItem = CommonSettingMenuItem & {
  type: "callback";
  callback: (util: ExtensionSettingUtil) => void;
};
  • 支持自定义 UI 的菜单类型:

    interface ReactComponent {
      (props: ReactComponentPropType): JSX.Element;
    }
    
    type ReactComponentRegisterData = {
      title?: string | UBT.IntlMessage;
      size?: UCodeCustomUI.ModalSizeType;
      radius?: string | number; // 弹窗的圆角
    };
    
    type ReactSettingMenuItem = CommonSettingMenuItem<ReactComponentRegisterData> & {
      type: "component";
      component: ReactComponent; // react组件
    };
    

    例:

    • 定义弹窗:
    // components/example.tsx
    import React from "react";
    import { UCodeExternalHardwareDefinition } from "@ubtech/ucode-extension-common-sdk/types";
    
    export const DemoComponent: UCodeExternalHardwareDefinition.ReactComponent = (props) => {
      console.log(props.getDevice());
      return (
        <h1>
          我是一个 React Hook 组件 MenuId: {props.menuId}, 设备类型: {props.getDevice()?.deviceType?.name}
        </h1>
      );
    };
    
    • 注册菜单:
    // index.ts
    import { DemoComponent } from './components/example';
    
    self.UCode.extensions.register({
      // 省略...
      SettingMenuRegister: {
        myMenu: {
          name: '我的组件(自定义弹窗,无图标)',
          icon: '', // demo暂未配置图标
          type: 'component', // 声明为有UI的菜单
          component: DemoComponent, // 注册组件
          additionalData: {
            title: '我的组件',
          },
        },
    
    • 菜单展示:

    • UI 展示:

# 菜单名

设置 name 参数。

# 菜单图标

设置 icon 参数。

需要在 webpack 中使用 url-loader,将图标打包进代码中。或者用完整的网络图标地址,比如:https://xxxx.xxxx.xxx/xxx/menu.svg

// webpack > module > rules
{
  test: /\.(svg|png|jpg|gif)$/i,
  use: [
    {
      loader: 'url-loader',
      options: {
        limit: 10240,
      },
    },
  ],
},

为了与 uCode 的 UI 风格保持一致,我们建议自定义图标符合以下描述:

备注
颜色 #6A7078 或接近值 线框颜色
尺寸 推荐 22 x 22, 单位:px
图标格式 推荐 SVG。png、jpg、gif 可用
风格描述 - 线型
- 图标无异议

# 支持的连接方式

设置 availableDeviceTypes 参数。

availableDeviceTypes、DeviceRegister、当前连接方式,共同决定了该菜单是否可用。

DeviceRegister 中,设置了 DeviceType 。当设备已连接,且连接方式是 DeviceRegister 设置的一种。如果菜单设置支持的连接方式列表中,包含当前连接方式,那么菜单可用。

availableDeviceTypes 类型声明如下:

availableDeviceTypes?: DeviceType[];

type DeviceType = DeviceType: AutoConnectDeviceType | DiscoverDeviceType | InputIdDeviceType

连接方式可以是内置提供的,也可以是自定义的。如果是自定义类型,类型需要是AutoConnectDeviceType | DiscoverDeviceType | InputIdDeviceType中的一种。

具体可以查阅 API 文档--DeviceType

  • 内置的 DeviceType

    内置的 DeviceType 有:

    • 串口
    • 蓝牙 webble
    • 蓝牙 ucodeble
    • mDNS
    • udp
    • tcp

    通过下面方式,可以获取内置的 DeviceType:

    import { CommonProtocols } from "@ubtech/ucode-extension-common-sdk";
    
    const { SerialPortDeviceType } = CommonProtocols.SerialPort;
    const { WebBleDeviceType, UCodeBleDeviceType } = CommonProtocols.BLE;
    const { mDNSDeviceType } = CommonProtocols.MDNS;
    const { UDPDeviceType } = CommonProtocols.UDP;
    const { AutoTCPDeviceType } = CommonProtocols.TCP;
    
    // 使用时,根据需要,配置列表。
    // register > SettingMenuRegister > menu > item
    availableDeviceTypes: [SerialPortDeviceType, WebBleDeviceType, UDPDeviceType, AutoTCPDeviceType /* 其他... */];
    
  • 自定义的 DeviceType

    假设自定义的 如下:

    import type { DiscoverDeviceType } from "@ubtech/ucode-extension-common-sdk/types";
    
    export function getTCPUDPDeviceType(): DiscoverDeviceType {
      return {
        connectType: "discover", // 连接类型,先搜索后连接。
        id: "udp-tcp", // 通过id判断菜单是否支持当前连接方式
        name: "Wi-Fi", // 在连接方式选择界面中显示的连接方式的文案。(当有多个连接方式时,会出现连接方式选择界面。)
        scanTime: 20, // 20秒搜索超时
        needUcodelink: !isRunInMobile(), // 是否需要uCodeLink才能连接设备
      };
    }
    
    // 使用时,根据需要,配置列表。
    // register > SettingMenuRegister > menu > item
    availableDeviceTypes: [SerialPortDeviceType, getTCPUDPDeviceType() /* 其他... */];
    

    设置了多个连接方式:

# 支持的运行模式

设置 availableWorkingModes 参数。

availableWorkingModes 和 uCode 当前所处的运行模式共同决定了该菜单是否可用。

声明如下:

availableWorkingModes?: UCode.WorkingModeType[]; // UCode.WorkingModeType有两个值:'online', 'upload'

如果支持在线模式,填'online';如果支持烧录模式,填'upload';如果都支持,那就都填上。

availableWorkingModes: ["online", "upload"];