OverlayService

# OverlayService

OverlayService 管理全局浮层组件(Overlay)。Overlay 是渲染在所有 Tab 和 App 上方的 UI 层,不属于任何一个 Tab,始终可见。典型用途包括全局悬浮按钮、状态栏、AI 助手入口等。

# 什么是 Overlay

在 AutumnBox 中,UI 层级从下到上依次为:

  1. Card -- 首页卡片,嵌入主界面
  2. App -- Tab 页面,打开后占据主区域
  3. Overlay -- 浮层,覆盖在所有内容之上

Overlay 组件由宿主在根级别渲染,独立于 Tab 切换和 App 生命周期。只要插件处于加载状态,其注册的 Overlay 就会持续显示。

# 获取方式

import { useService } from '@autumnbox/sdk/hooks';
import { OverlayService } from '@autumnbox/sdk/hooks';

// React 组件中
const overlayService = useService(OverlayService);

// pluginMain 或非 React 环境中
const overlayService = context.getService(OverlayService);

# API 一览

方法 / 属性 签名 说明
overlays readonly overlays: IReadonlyState<readonly OverlayEntry[]> 响应式的已注册 Overlay 列表
register register({ id, component, pluginPackageName }): void 注册一个 Overlay
unregister unregister(overlayId: string): void 按 ID 注销一个 Overlay
unregisterByPluginPackageName unregisterByPluginPackageName(pluginPackageName: string): void 注销某个插件的所有 Overlay

每个 OverlayEntry 包含:

interface OverlayEntry {
  id: string;                    // 唯一标识
  component: React.ComponentType; // 渲染组件
  pluginPackageName: string;     // 所属插件
}

# 注册 Overlay

Overlay 应在 pluginMain 中注册,而非在 App 或 Card 组件内部。这是因为 Overlay 的生命周期与插件绑定,而不是与某个 Tab 绑定。

# 基本模式

import type { PluginContext } from '@autumnbox/sdk';
import { OverlayService } from '@autumnbox/sdk/hooks';

export function pluginMain(context: PluginContext): () => void {
  const overlayService = context.getService(OverlayService);

  overlayService.register({
    id: 'my-overlay',
    component: MyOverlayComponent,
    pluginPackageName: context.pluginPackageName,
  });

  // 插件卸载时必须注销
  return () => {
    overlayService.unregister('my-overlay');
  };
}

注意

务必在清理函数中调用 unregister。如果遗漏,插件卸载后 Overlay 组件仍会残留在界面上,且其引用的代码已被释放,可能导致运行时错误。

# 示例:悬浮助手按钮

一个固定在右下角的圆形按钮,点击后展开助手面板:

import { useState } from 'react';
import { Button, Drawer } from 'antd';
import { RobotOutlined } from '@ant-design/icons';

const FloatingAssistant: React.FC = () => {
  const [open, setOpen] = useState(false);

  return (
    <>
      <div style={{ position: 'fixed', bottom: 24, right: 24, zIndex: 1000 }}>
        <Button
          type="primary"
          shape="circle"
          size="large"
          icon={<RobotOutlined />}
          onClick={() => setOpen(true)}
        />
      </div>
      <Drawer
        title="AI 助手"
        placement="right"
        open={open}
        onClose={() => setOpen(false)}
      >
        <p>在这里实现助手功能...</p>
      </Drawer>
    </>
  );
};

注册方式与上文"基本模式"相同,将 FloatingAssistant 作为 component 传入即可。

# 示例:全局状态栏

在顶部显示设备连接状态,Overlay 内可正常使用所有 SDK Hook:

import { useService, useServiceState } from '@autumnbox/sdk/hooks';
import { DevicesService } from '@autumnbox/sdk/services';

const DeviceStatusBar: React.FC = () => {
  const devicesService = useService(DevicesService);
  const [devices] = useServiceState(devicesService.devices);
  const connected = devices.length > 0;

  return (
    <div style={{
      position: 'fixed', top: 0, left: 0, right: 0, height: 28,
      background: connected ? '#52c41a' : '#ff4d4f',
      color: '#fff', display: 'flex', alignItems: 'center',
      justifyContent: 'center', fontSize: 12, zIndex: 999,
    }}>
      {connected
        ? `已连接 ${devices.length} 台设备`
        : '未连接任何设备'}
    </div>
  );
};

注册方式与悬浮按钮示例相同,只需替换 idcomponent

# 下一步