# SGS Map SDK 通信协议规格 (Protocol Specification) > 版本: V2.0.0 > 适用对象: SGS Map SDK 核心开发者、渲染基座 (h5-sdk) 开发者 本文档定义了外壳 SDK (`sgs-map-sdk.js`) 与 独立渲染基座 iframe (`h5-sdk/page.tsx`) 之间的 `postMessage` 通信契约。所有消息传递必须严格遵循此结构,以保障多域环境下的确权、安全过滤与异步生命周期追踪。 --- ## 1. 消息模型抽象 双方通信产生的 JSON 对象统一分为三大类: ### 1.1 命令 (Command): SDK -> 基座 外壳 SDK 向基座发起的主动操作。 ```json { "type": "SGS_MAP_COMMAND", "action": "PLAN_ROUTE", // [必填] 行为动词 "requestId": "req_sdk_123_45", // [可选] 异步确权追踪信标 "payload": { ... } // [可选] 负载参数 } ``` ### 1.2 响应 (Response): 基座 -> SDK 基座处理完 `Command` 后(同步或异步计算),向 SDK 携带结果的被动回执。 ```json { "type": "SGS_MAP_RESPONSE", "action": "PLAN_ROUTE", // [必填] 原样回显 Command 的 action "requestId": "req_sdk_123_45", // [必填] 原样回显 Command 的 requestId "payload": { "success": true }, // [可选] 成功时的返回值 "error": { "code": "ERR_NO_PATH", "message": "无路径" } // [可选] 失败时的异常信息 } ``` ### 1.3 事件 (Event): 基座 -> SDK 基座中发生的不可预知行为(如鼠标点击)或系统状态变更,主动向外广播。 ```json { "type": "SGS_MAP_EVENT", "action": "ON_POI_CLICK", // [必填] 事件动词 (ON_开头) "payload": { "poiId": 1234 } // [可选] 事件负载 } ``` --- ## 2. 握手时序 (Handshake Sequence) 为了解决 iframe 初始化过程中的“假死”与状态竞态,必须采用基于事件的确权握手。 ```mermaid sequenceDiagram participant SDK as 外壳 SDK participant Iframe as 浏览器 DOM participant Base as 渲染基座 (h5-sdk) SDK->>Iframe: 动态创建 iframe(src) Iframe-->>SDK: 触发 iframe.onload Note over SDK,Base: 此时 HTML 刚加载,WebGL/GLB 模型并未解析完成 SDK->>Base: 发送 HELLO { protocolVersion: 2, sdkVersion: "2.0.0" } Base->>Base: 挂载 WebGL,拉取 GLB 及 POI 接口 Base-->>SDK: 内部加载完毕,推送 ENGINE_READY 事件 SDK->>SDK: 解锁 isReady = true,清空缓存命令队列 ``` --- ## 3. 指令字典 (Command Action Dictionary) 基座通过严格的**白名单机制**过滤 `action`,任何未在下表中声明的指令都将被立刻退回 `ERR_UNSUPPORTED` 响应。 | Action | Payload 负载签名 | 成功 Response 负载 | 说明 | |--------|------------------|--------------------|------| | `HELLO` | `{ protocolVersion, sdkVersion }` | (无,以 `ENGINE_READY` 代替回执) | 初始心跳探测 | | `CHANGE_FLOOR` | `{ floorId: number }` | `{ success: true, floorId }` | 触发析构当前层并加载新层 | | `FOCUS_TO` | `SgsMapNode` | `{ success: true }` | 镜头平滑转移,改变相机视角 | | `PLAN_ROUTE` | `{ startNode?: SgsMapNode, endNode?: SgsMapNode, from?: SgsMapNode, to?: SgsMapNode, options? }` | `RouteResult` | 寻路计算。基座将转换为微服务调用 | | `CLEAR_ROUTE` | (空) | `{ success: true }` | 销毁当前的 NavMeshPathLayer | | `GET_STATE` | (空) | `{ floorId, isReady, ... }` | 查询内部状态机当前切片 | | `ADD_MARKER` | `MarkerConfig` | `{ success: true }` | 生成三维图钉并依附到骨骼节点 | | `REMOVE_MARKER`| `{ markerId: string }` | `{ success: true }` | 释放指定图钉的材质 | | `CLEAR_MARKERS`| (空) | `{ success: true }` | 卸载所有动态业务图钉 | | `HIGHLIGHT_POLYGON`| `{ nodeName: string }` | `{ success: true }` | 激活发光材质特效 | | `RESET_VIEW` | (空) | `{ success: true }` | 重置相机视角至初始状态 | | `SET_VIEW_MODE` | `{ mode: '2d' | '3d' }` | `{ success: true }` | 切换 2D/3D 视角模式 | | `TOGGLE_LAYER` | `{ types: string[], visible: boolean }` | `{ success: true, visibleTypes: string[] }` | 批量控制某类底座设施的显示隐藏 | > **类型定义备注:** > `SgsMapNode` 及 `RouteResult` 的精确结构请参考 TypeScript 源码定义:`sdk-src/types.ts`。 --- ## 4. 事件广播列表 (Event Action List) | 事件 Action | Payload 结构 | SDK 派发事件名 | 触发时机 | |-------------|--------------|----------------|----------| | `ENGINE_READY` | `{ engineVersion, protocolVersion, sdkVersion }` | `ready` | 基座完全挂载,WebGL 画布可渲染 | | `ON_POI_CLICK` | `{ id, name, type }` | `poiClick` | 用户在触摸屏或鼠标点击了高亮要素 | | `ON_FLOOR_CHANGED`| `{ floorId }` | `floorChanged` | 楼层完全切换完毕后自动抛出 | --- ## 5. 安全沙箱规则 (Security & Sandboxing) 1. **Origin 发射校验 (SDK 侧)** - `sgs-map-sdk.js` 使用 `iframe.contentWindow.postMessage(msg, targetOrigin)` 发射指令。若 `targetOrigin` 错误,浏览器底层会进行跨域阻断。 2. **Origin 监听校验 (SDK 侧)** - 收到事件时比对 `event.origin !== targetOrigin`,丢弃第三方注入的伪造消息。 - 收到事件时比对 `event.source !== this.iframe.contentWindow`,丢弃宿主页面其他无关 iframe 的干扰。 3. **安全内存释放 (GC)** - 断网或后服务宕机时,SDK 侧的 `Promise` 将在设定的 `timeout` (默认 5000ms) 到达后自动 `reject`。 - SDK 实例调用 `destroy()` 后,会清除自身 DOM 及事件树,杜绝闭包引用与孤儿 WebGL Context。