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_RECEIPTReadReceipt已读回执更新主进程 `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`。