macOS 事件与回调
口径说明
融云公开文档不覆盖 macOS 原生 SDK 与桌面交付链(dmg / 代码签名 / 公证 / 分发 / Gatekeeper);本页为本项目按 Apple 与 Electron 官方实践补齐的接入文档。
IMLib 的 16 类事件在主进程订阅,SDK 的 preload 桥再把事件广播给已订阅的窗口;渲染进程通过 window.niPaasIMBridge.onEvent 接收 {event,payload,seq,ts} 帧。多窗口共享同一主进程连接,窗口刷新不会丢监听。
事件与载荷
| 事件 | 载荷类型 | 触发时机 | 接收方式 |
|---|---|---|---|
CONNECTING | {attempt:int} | 开始连接(含自动重连尝试) | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
CONNECTED | {userId:string, sessionId?:string} | 连接成功且离线补发完成 | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
DISCONNECT | {code:int, reason:string} | 连接断开(含错误码与原因) | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
SUSPEND | {code:int, reason:string} | 服务端挂起连接(多端互踢等) | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
MESSAGES | {messages:Message[]} | 收到在线 / 离线补发消息 | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
CONVERSATION | {conversation:Conversation} | 会话变更(未读、置顶、草稿等) | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
MESSAGE_RECALLED | {message:Message} | 消息被撤回 | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
READ_RECEIPT | ReadReceipt | 已读回执更新 | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
TYPING | {conversationType:ConversationType,targetId:string,userId:string,typing:bool,timestamp:int64} | 对方正在输入 | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
MESSAGE_REACTION_CHANGED | {messageId:string,conversationType:ConversationType,targetId:string,reactionId:string,operation:added|removed|cleared,userId:string,reactionTime:int64,totalCount:uint32,users:string[]?} | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` | |
MESSAGE_EXPANSION_CHANGED | {messageId:string,conversationType:ConversationType,targetId:string,updated:Record<string,string>?,removed:string[]?,timestamp:int64} | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` | |
STREAM_MESSAGE_CHANGED | {streamId:string,messageId:string,conversationType:ConversationType,targetId:string,senderId:string,delta:string,seq:uint32,text:string,status:streaming|ended,complete:bool,timestamp:int64} | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` | |
PRESENCE_CHANGED | {userId:string,online:bool,lastSeenAt:int64,timestamp:int64,reason:connect|disconnect|kick|deactivate} | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` | |
FRIEND_EVENT | {kind:FriendEventKind,request?:FriendRequest,fromUserId?:string,toUserId?:string,timestamp:int64} | 好友申请 / 同意 / 拒绝 | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
CHATROOM_EVENT | {chatroomId:string,kind:ChatroomEventKind,userId?:string,onlineCount?:uint32,chatroom?:Chatroom,timestamp:int64} | 聊天室加入 / 离开 / 销毁 / 成员变化 | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
KICKED | {code:int,reason:string} | 被踢下线 | 主进程 `service.client.addEventListener`;渲染进程 `bridge.onEvent` |
载荷字段以实测为准
CONNECTING 的载荷在当前 Electron SDK 中 attempt 可能为 undefined(未携带重试序号);不要依赖该字段做业务分支,重连状态用 onState 的 status 判断。主进程订阅
JavaScript
import { Events } from '@ni-paas-im/electron/main';
// 宿主能力(通知 / 托盘 / Dock 角标)直接订阅主进程事件
service.client.addEventListener(Events.CONNECTED, (payload) => console.log('connected', payload.userId));
service.client.addEventListener(Events.MESSAGES, ({ messages }) => console.log('messages', messages.length));
service.client.addEventListener(Events.KICKED, () => console.log('kicked, need re-login'));渲染进程订阅
JavaScript
// 页面无需自己写 IPC:SDK preload 已暴露 window.niPaasIMBridge
const offEvent = window.niPaasIMBridge.onEvent(({ event, payload, seq, ts }) => {
switch (event) {
case 'MESSAGES': renderMessages(payload.messages); break;
case 'CONVERSATION': refreshConversations(); break;
case 'READ_RECEIPT': updateReadState(payload); break;
case 'KICKED': showReLoginDialog(); break;
default: break;
}
});
const offState = window.niPaasIMBridge.onState(({ status, userId, dbOpen }) => {
// status: 0=CONNECTED / 1=CONNECTING / 2=DISCONNECTED / 3=SUSPEND
updateStatus(status, userId, dbOpen);
});
// 页面卸载时取消订阅(避免重复回调)
offEvent();
offState();回调约定
- `onEvent` / `onState` 返回取消函数;组件卸载时调用,避免重复注册。
- 事件顺序:`CONNECTING → CONNECTED → MESSAGES(离线补发)`;UI 以 CONNECTED 作为“可发送”的信号。
- `KICKED` 表示账号在其它端登录:主进程断开连接并清理敏感状态,渲染进程回到登录页。
- 事件只是通知:渲染进程收到后应回读本地库 / 拉取最新会话,避免只依赖事件载荷拼装状态。
- 多窗口已由 SDK 广播,不需要宿主再写 `webContents.send`。