--- title: 接收消息 --- # 接收消息 您可通过设置代理监听或通知监听拦截 SDK 接收的消息,并进行相应的业务操作。 ## 消息接收代理委托协议 IMKit SDK 提供了消息接收监听协议 [RCIMReceiveMessageDelegate],可接收实时消息或离线消息。该协议提供两个代理方法,监听消息处理只需要在其中一个代理方法内实现。SDK 会通过此方法接收包含单聊、群聊、聊天室、系统类型的所有消息。只需全局设置一次即可,多次设置会导致其他代理失效。 如果您设置了IMlib消息监听之后,SDK在接收到消息时候会执行此方法。您可以根据 `nLeft` 的数量来优化您的 App 体验和性能,比如收到大量消息时等待 `nLeft` 为 0 再刷新 UI。 ```objectivec /*! 接收消息的回调方法 @param message 当前接收到的消息 @param nLeft 还剩余的未接收的消息数,left>=0 */ - (void)onRCIMReceiveMessage:(RCMessage *)message left:(int)left; ``` 与第一个代理方法相比,第二个代理方法额外暴露了 `offline` 和 `hasPackage` 参数。您可以根据 `nLeft`、`offline`、`hasPackage` 选择合适的时机刷新 UI。建议当 `hasPackage`=0 并且 `nLeft`=0 时刷新 UI。如果使用此方法,那么就不能再使用 RCIM 中的 `- (void)onRCIMReceived:(RCMessage *)message left:(int)nLeft` ,否则会出现重复操作的情形。 ```objectivec /** 接收消息的回调方法 @param message 当前接收到的消息 @param nLeft 还剩余的未接收的消息数,left>=0 @param offline 是否是离线消息 @param hasPackage SDK 拉取服务器的消息以包(package)的形式批量拉取,有 package 存在就意味着远端服务器还有消息尚未被 SDK 拉取 */ - (void)onRCIMReceived:(RCMessage *)message left:(int)nLeft offline:(BOOL)offline hasPackage:(BOOL)hasPackage; ``` | 参数 | 类型 | 说明 | |:------- | :--------------- | :---- | | message | [RCMessage] | 接收的消息对象。 | | nLeft | int | 当客户端连接成功后,服务端会将所有离线消息?以消息包(Package)的形式下发给客户端,每个 Package 中最多含 200 条消息。客户端会解析 Package 中的消息,逐条上抛并通知应用。`nLeft` 为当前正在解析的消息包(Package)中还剩余的消息条数。 | | offline | boolean | 当前消息是否离线消息。 | | hasPackage | boolean | 是否在服务端还存在未下发的消息包(Package)。 | ## 添加消息接收代理 SDK 支持设置多个消息接收代理。所有接收到的消息都会在此接口方法中回调。建议在应用生命周期内注册消息监听。 ```objectivec [[RCIM sharedRCIM] addReceiveMessageDelegate:self]; ``` ## 移除消息接收代理 SDK 支持移除监听器。为了避免内存泄露,请在不需要监听时将监听器移除。 ```objectivec [[RCIM sharedRCIM] removeReceiveMessageDelegate:self]; ``` ## 通知监听 开发者可以在任何时机使用通知监听消息接收。 收到消息后,SDK 会分发下面通知。 ```objectivec FOUNDATION_EXPORT NSString *const RCKitDispatchMessageNotification; ``` Notification 的 object 为 RCMessage 消息对象。 userInfo 为 NSDictionary 对象。 userInfo 字典对象说明: | key | value | 说明 | | :------ | :------- | :--------- | | left | NSNumber 类型 | 剩余待接收消息数 | ```objectivec [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMessageNotification:) name:RCLibDispatchReadReceiptNotification object:nil]; ``` ```objectivec - (void)didReceiveMessageNotification:(NSNotification *)notification { RCMessage *message = notification.object; int left = [[notification.userInfo objectForKey:@"left"] intValue]; } ``` ## 禁用消息排重机制 消息排重机制会在 SDK 接收单聊、群聊、系统消息、聊天室时自动去除内容重复消息。当 App 本地存在大量消息,SDK 默认的排重机制可能会因性能问题导致收消息卡顿。因此在接收消息发生卡顿问题时,可尝试关闭 SDK 的排重机制。 ### 为什么接收消息可能出现消息重复 发送端处于弱网情况下可能出现该问题。A 向 B 发送消息后,消息成功到达服务端,并成功下发到接收者 B。但 A 由于网络等原因可能未收到服务端返回的 ack,导致 A 认为没有发送成功。此时如果 A 重发消息(IMKit 默认具有失败自动重发机制,建议同时关闭),此时 B 就会收到与之前重复的消息(消息内容相同,但 Message UID 不同)。 ```mermaid sequenceDiagram autonumber Note over UserA, RongCloudServer: 发送端处于弱网情况 UserA ->> RongCloudServer: 发送消息 RongCloudServer --x UserA: 弱网情况未返回回执 RongCloudServer ->> UserB: 下发消息 UserA ->> RongCloudServer: 重新发送消息 RongCloudServer -->> UserA: 返回回执 RongCloudServer ->> UserB: 下发消息 ``` ### 关闭消息排重机制 单聊、群聊、系统消息使用 IMLib 的核心类 `RCCoreClient` 中的 `setCheckDuplicateMessage` 方法(要求 SDK 版本 ≧ 5.3.4),禁用消息排重行为。请在 SDK 初始化之后,建立 IM 连接之前完成以下配置: ```objectivec BOOL enableCheck = NO; // 关闭消息排重 [[RCCoreClient sharedCoreClient] setCheckDuplicateMessage:enableCheck]; ``` 聊天室消息排重使用 RongChatRoom 的核心类 `RCChatRoomClient` 中的 `setCheckChatRoomDuplicateMessage` 方法(要求 SDK 版本 ≧ 5.8.2),禁用消息排重行为。请在 SDK 初始化之后,建立 IM 连接之前完成以下配置: ```objectivec BOOL enableCheck = NO; // 关闭消息排重 [[RCChatRoomClient sharedChatRoomClient] setCheckChatRoomDuplicateMessage:enableCheck]; ``` ### 关闭失败重发机制 IMKit SDK 默认启用了消息失败自动重发机制。在禁用消息排重机制后,为避免收到 UID 重复的消息,建议同时在 App 中禁用 IMKit 的失败重发机制。 请在 SDK 初始化之后,建立 IM 连接之前完成以下配置: ```objectivec RCKitConfigCenter.message.enableMessageResend = NO; ``` [RCIMReceiveMessageDelegate]: https://doc.rongcloud.cn/apidoc/imkit-ios/latest/zh_CN/documentation/rongimkit/rcimreceivemessagedelegate?language=objc [RCMessage]: https://doc.rongcloud.cn/apidoc/imlibcore-ios/latest/zh_CN/documentation/rongimlibcore/rcmessage?language=objc