# 调试插件

在开发插件的过程中遇到报错或运行异常很正常，别慌！飞块为你提供了完善的诊断排查机制。

高效排查的关键是**精准定位阶段**：先分清问题究竟是发生在**插件启动阶段**、**动作执行阶段**，还是**前端页面渲染阶段**。逐层剥离往往能让你在几分钟内准确定位根因，避免盲目修改代码或配置文件。

---

## 1. 插件无法启动或闪退

当你在拓展管理中尝试启用插件却提示失败时，通常由以下几种原因引起：

### 症状一：提示找不到文件或模块
- **排查方向**：仔细核对 `manifest.json` 中的 `main`、`page` 路径与项目实际产物结构。
- **常见根因**：如果你使用 TypeScript 开发，请确认已运行 `flyon build` 生成了对应的编译文件（例如 `dist/index.js`），且清单中的 `main` 指向的是编译产物而非源码。

### 症状二：提示“注册不一致”或未找到声明的处理函数
- **排查方向**：检查清单中声明的每个动作、状态或服务 ID，是否都在 `definePlugin()` 中注册了同名处理函数。ID 区分大小写且必须完全匹配。

### 症状三：直接使用 `node index.js` 启动报错
- **排查方向**：插件后台依赖飞块宿主注入的上下文环境（如 `process.env.FLYONDECK_SDK_PATH`）。**切勿在终端直接用普通 Node 启动插件入口**，请通过飞块桌面端的“加载开发文件夹”或运行 `flyon dev` 进行热联调。

> 💡 **排查小妙招**：在 `onStart()` 或文件顶层加入 `console.log()`，结合 `flyon logs` 或桌面端控制台日志，能清晰还原插件启动时的每一个步骤。

---

## 2. 插件间依赖与协作报错

当你的插件声明了依赖其他插件提供的能力（如服务或数据源）时，请按照以下规则排查：

- **缺少提供方插件**：必须先在飞块中安装并启动提供方插件，消费方才能正常建立连接并调用。
- **版本不兼容**：
  - 检查 `manifest.json` 中 `dependencies[pluginId]` 填写的 SemVer 版本范围是否涵盖提供方的实际 `version`；
  - 检查 `uses` 中声明的服务 ID 和整数版本号，是否与提供方的 `contributes.services` 契约严格一致。
- **循环依赖警告**：宿主出于安全稳定考量，禁止插件间产生互相依赖的死锁环。如遇循环依赖，请抽离公共能力的第三方插件作为基础提供方。
- **卸载与更新顺序**：当提供方正在被多个消费方使用时，无法直接强制停用或替换。请先停用或卸载消费方，再更新提供方插件。

---

## 3. 动作执行报错或没有反应

当你按下实体按键或运行工作流时，动作抛出异常或表现不如预期：

### 症状一：提示数据类型不匹配（如“类型应为 string”）
- **排查方向**：检查前端传入的参数类型是否与清单中的 `argsSchema` 一致。例如，数字 `"42"`（字符串）与 `42`（数值）在 Schema 校验中是严格区分的。若需数字输入，请在 Schema 中声明为 `type: "number"` 或 `integer`。

### 症状二：提示“无效参数”或找不到字段
- **排查方向**：对照 [Action.argsSchema 参考](../reference/actions.md) 检查参数字段命名。建议在动作处理函数的开头打印参数对象：
  ```javascript
  console.log("收到动作参数:", JSON.stringify(args, null, 2));
  ```

### 症状三：流程中后续步骤取不到上一步的返回值
- **排查方向**：确认函数的 `return` 返回值字段名是否与清单中的 `outputSchema` 丝毫不差。推荐在流程末尾加入一个内置的“输出”动作，在内容中绑定前一步的“步骤结果”进行打印验证。

---

## 4. 超级块页面空白或数据未刷新

超级块的前端页面涉及浏览器渲染与后台 IPC 通信，建议按如下次序分步排错：

1. **检查页面 SDK 是否正确加载**：  
   打开开发者工具（桌面端支持右键检查元素或通过远程调试端口），查看 Console 控制台是否报错。主页面 HTML 头部必须正确引入官方 SDK 脚本：
   ```html
   <script src="/api/plugin-sdk/widget-page-v1.js"></script>
   ```
2. **核对状态来源 ID（Source ID）**：  
   确认 `manifest.json` 中的 `stateSource`、后台调用的 `context.states.publish()`，以及前端页面所监听的来源 ID 是否保持三方统一。
3. **核查实例标识（适用于 widget-instance 作用域）**：  
   如果超级块使用的是私有实例状态，后台向实例推送数据时必须携带有效的 `(deviceId, screenId, blockId)`。可以在后台打印 `context.widgets.instances()` 的返回值，确认当前实例是否已成功被宿主识别并分配。
4. **区分目录预览与实际放置**：  
   未放置在画布上的组件位于选择目录中，此时没有真实的实例上下文。请参考[最佳实践](../guides/widgets.md#最佳实践一-桌面端与移动端数据同步)，在无真实实例时展示带有“示例”标注的演示内容，放置到画布后再接收真实状态。

---

## 5. 网络请求受阻与跨域失败

由于飞块严格的安全机制，插件发起的所有外网请求均受到安全白名单的保护：

- **通过后台发起请求（`context.network.getJson`）**：  
  如果提示无权请求，请检查 `manifest.json` 的 `permissions` 数组是否已包含 `"network.getJson"`，且目标域名已精确添加到 `networkOrigins` 白名单中。
- **通过前端页面直接 `fetch()`**：  
  如果是超级块 HTML 页面直接调用接口，请检查清单中的 `widgetConnectOrigins` 是否已放行对应源，并确认目标接口服务器已开启正确的 CORS 响应头。

> 📚 **深入参考**：更多关于权限范围与网络安全规则的详细配置，请查阅[权限与联网参考文档](../reference/permissions.md)。
