跳到主要内容

接收消息

您可通过设置消息监听器拦截 SDK 接收的消息,并进行相应的业务操作。

监听消息接收

应用程序可以通过 addReceiveMessageDelegate 方法设置多个消息接收代理。所有接收到的消息都会在此 RCIMClientReceiveMessageDelegate 协议的代理方法中回调。建议在应用生命周期内注册消息监听。

[[RCCoreClient sharedCoreClient] addReceiveMessageDelegate:self];

RCIMClientReceiveMessageDelegate 可用于处理接收实时消息或离线消息。该协议提供两个代理方法,监听消息处理只需要在其中一个代理方法内实现。SDK 会通过此方法接收包含单聊、群聊、聊天室、系统类型的所有消息。

代理方法一提供了还剩余的未接收的消息数 nLeft 参数。您可以根据 nLeft 的数量来优化您的 App 体验和性能,比如收到大量消息时等待 nLeft 为 0 再刷新 UI。

/*!
接收消息的回调方法

@param message 当前接收到的消息
@param nLeft 还剩余的未接收的消息数,left>=0
@param object 消息监听设置的 key 值

*/
- (void)onReceived:(RCMessage *)message left:(int)nLeft object:(id)object;

当客户端连接成功后,服务端会将所有离线消息?以消息包(Package)的形式下发给客户端,每个 Package 中最多含 200 条消息。客户端会解析 Package 中的消息,逐条上抛并通知应用。第二个代理方法额外暴露了 offlinehasPackage 参数。您可以根据 nLeftofflinehasPackage 选择合适的时机刷新 UI。

/**
接收消息的回调方法

@param message 当前接收到的消息
@param nLeft 还剩余的未接收的消息数,left>=0
@param object 消息监听设置的 key 值
@param offline 是否是离线消息
@param hasPackage SDK 拉取服务器的消息以包(package)的形式批量拉取,有 package 存在就意味着远端服务器还有消息尚未被 SDK
拉取
*/
- (void)onReceived:(RCMessage *)message
left:(int)nLeft
object:(id)object
offline:(BOOL)offline
hasPackage:(BOOL)hasPackage;
参数类型说明
messageRCMessage接收的消息对象。
nLeftint当客户端连接成功后,服务端会将所有离线消息?以消息包(Package)的形式下发给客户端,每个 Package 中最多含 200 条消息。客户端会解析 Package 中的消息,逐条上抛并通知应用。nLeft 为当前正在解析的消息包(Package)中还剩余的消息条数。
offlineboolean当前消息是否离线消息。
hasPackageboolean是否在服务端还存在未下发的消息包(Package)。

同时满足以下条件,表示离线消息已收取完毕:

  • hasPackageNO:表示当前正在解析最后一包消息。
  • nLeft 为 0:表示最后一个消息包中最后一条消息已接收完毕。

从 5.2.3 版本开始,每次连接成功后,离线消息收取完毕时会触发 RCIMClientReceiveMessageDelegate 中的以下回调方法。如果没有离线消息,连接成功后会立即触发。

/*!
离线消息接收完成
*/
- (void)onOfflineMessageSyncCompleted;

SDK 支持移除监听器。为了避免内存泄露,请在不需要监听时将监听器移除。

[[RCCoreClient sharedCoreClient] removeReceiveMessageDelegate:self];

消息接收状态

提示

在 5.6.8 版本前,IMLib SDK 使用 RCMessagereceivedStatus 表示接收到的消息的状态。该属性在多设备场景下无法正常更新消息的已读状态,已被废弃。

从 5.6.8 版本开始,RCMessage 类中封装了 receivedStatusInfo 属性,使用以下属性表示接收到的消息的状态。

状态描述
isRead是否已读。当前设备或其他设备上已读后,该状态值会变为已读。如果消息在当前设备上被阅读,该状态会变为已读。SDK 5.6.8 版本开始,只要在其他设备上阅读过该消息,当前设备的该状态值会也变为已读。
isListened是否已被收听,仅用于语音消息。
isDownloaded是否已被下载,仅适用于媒体消息。
isRetrieved该消息是否已被同时在线或之前登录的其他设备接收。只要其他设备先收到该消息,该状态值都会变为已接收。

接收消息处理建议

  1. 如果接收消息量比较小,建议当 nLeft == 0 时刷新 UI,即消息是分批进行刷新。
  2. 如果接收消息量比较大,建议当 hasPackage == NO && nLeft == 0 (即所有的远端消息已经全部接收)时整体刷新一次。
  3. 如果接收消息量较大,还可以考虑使用 iOS 函数节流(throttle) 方式,即在一定时间段内,丢弃掉其它触发,就做一次执行。大致思路是接收大量消息的时候起定时器,固定时间刷新一次,等条件满足 hasPackage == NO && nLeft == 0 时关闭定时器再刷新一次。

下面分按消息数量大小分两种情况讨论以上方案。

  • 消息数量小:假设远端服务器有 200 条消息需要接收,接收总过程耗时 0.1 秒。

    • 方案 1:刷新 UI 次数为 200/200 = 1 次,即 0.1 秒钟之内刷新了 1 次。
    • 方案 2:刷新 UI 次数为 1 次,不管多少消息只有全部刷新一次,即 0.1 秒之内刷新了 1 次。
    • 方案 3:假设设置的是 0.1 秒固定刷新,那么次数为 0.1/0.1 + 1 = 2 次,即 0.1 秒之内刷新了 2 次。
  • 消息数量大:假设远端服务器有 1 万条消息需要接收,接收总过程耗时 1 秒。

    • 方案 1:刷新 UI 次数为 10000/200 = 50 次,即 1 秒钟之内刷新了 50 次
    • 方案 2:刷新 UI 次数为 1 次,不管多少消息只有全部刷新一次,即 1 秒之内刷新了 1 次
    • 方案 3:假设设置的是 0.5 秒固定刷新,那么次数为 1/0.5 + 1 = 3 次,即 1 秒之内刷新了 3 次。

整体来说方案 1、2 的开发难度小,方案 3 的开发难度大。您需要根据接收消息数量大小的实际情况,选择合适的方案。

上述方案都需要您自行实现。您也可以参考 IMKit SDK 中的处理方法。

禁用消息排重机制

消息排重机制会在 SDK 接收单聊、群聊、系统消息、聊天室时自动去除内容重复消息。当 App 本地存在大量消息,SDK 默认的排重机制可能会因性能问题导致收消息卡顿。因此在接收消息发生卡顿问题时,可尝试关闭 SDK 的排重机制。

为什么接收消息可能出现消息重复

发送端处于弱网情况下可能出现该问题。A 向 B 发送消息后,消息成功到达服务端,并成功下发到接收者 B。但 A 由于网络等原因可能未收到服务端返回的 ack,导致 A 认为没有发送成功。此时如果 A 重发消息,此时 B 就会收到与之前重复的消息(消息内容相同,但 Message UID 不同)。

关闭消息排重

提示

单聊、群聊、系统消息从 5.3.4 版本开始支持关闭消息排重。仅在 RCCoreClient 中提供。

请在 SDK 初始化之后,建立 IM 连接之前调用。多次调用以最后一次为准。

BOOL enableCheck = NO; // 关闭消息排重
[[RCCoreClient sharedCoreClient] setCheckDuplicateMessage:enableCheck];

聊天室消息从 5.8.2 版本开始支持关闭消息排重。在 RCChatRoomClient 中提供。

请在 SDK 初始化之后,建立 IM 连接之前调用。多次调用以最后一次为准。

BOOL enableCheck = NO; // 关闭消息排重
[[RCChatRoomClient sharedChatRoomClient] setCheckChatRoomDuplicateMessage:enableCheck];