消息管理–获取消息的已读回执和送达回执

更新时间:2022-02-28

本文介绍环信即时通讯 IM iOS SDK 从服务器获取消息的已读回执和送达回执。

环信即时通讯 IM 消息投递成功将返回送达回执。提供消息已读功能,接收方查看消息后,将返回已读回执。

功能 描述
消息送达回执 消息下发成功后,会返回消息送达回执。
消息已读回执 接收方查看消息后,会返回消息已读回执。
单个消息已读回执 提供单聊消息已读回执能力。
群组消息已读回执 提供群组消息已读回执能力。

使用环信即时通讯 IM iOS SDK 可以实现消息的送达回执与已读回执,主要方法如下:

  • enableRequireReadAck 开启送达回执;
  • ackConversationRead 发出指定会话的已读回执;
  • sendMessageReadAck 发出指定消息的已读回执;
  • sendGroupMessageReadAck 发出群组消息的已读回执。

开始前,请确保满足以下条件:

  • 完成 SDK 初始化,并连接到服务器,详见 快速开始
  • 了解环信即时通讯 IM 的使用限制,详见 使用限制

消息送达回执

若想要在消息送达时收到通知,你可以打开消息送达开关,这样在消息到达对方设备时你可以收到通知。

//设置是否需要接受方送达确认,默认 `YES`。
options.enableRequireReadAck = YES;

onMessageDelivered 回调是对方收到消息时的通知,你可以在收到该通知时,显示消息的送达状态。

- (void)messagesDidRead:(NSArray *)aMessages
  {
    for (EMChatMessage *message in aMessages) {
       //做消息已读处理等。
    }
  }

//记得在不需要的时候移除 delegate,如在 viewController 的 dealloc 时。
[[EMClient sharedClient].chatManager removeDelegate:self];

消息已读回执

消息阅读后,可以发出已读回执,该回执需要你调用 API 实现,这样消息发送方可以知道消息已被阅读。

会话已读回执

会话已读回执用于需要获知接收方是否阅读消息的场景,目前仅适用于单聊(ChatType.Chat)

注意

群消息已读回执功能为增值服务,仅旗舰版及以上支持,具体使用参考 群消息已读回执。

发送已读回执消息

推荐进入会话页面,根据会话是否有未读消息,发送会话已读回执(conversation ack),有则发送,没有则不再发送。

[[EMClient sharedClient].chatManager ackConversationRead:conversationId completion:nil];
监听已读回执回调
- (void)onConversationRead:(NSString *)from to:(NSString *)to
  {
    //添加刷新页面通知等逻辑。
  }
  

注意

onConversationRead 中的 fromto 与消息 EMChatMessage 中的定义相同。

会话已读回执 onConversationRead 的场景:

(1)消息被接收方阅读,且发送了已读回执 (conversation ack)

(2)多端多设备登录场景下,一端发送会话已读回执 (conversation ack),服务器端会将未读消息数置为 0,同时其他端会回调此方法。

单个消息的已读回执

注意

消息已读回执功能目前仅适用于单聊(ChatType.Chat),推荐使用方案为会话已读回执 (conversation ack)+单条消息已读回执(read ack)结合实现,可减少发送 read ack 消息量。群消息已读回执功能为增值服务,仅旗舰版及以上支持,具体使用请参考 群消息已读回执。

发送已读回执消息

建议进入会话首先发送会话已读回执(conversation ack)

[[EMClient sharedClient].chatManager sendMessageReadAck:messageId toUser:conversationId completion:nil];

在会话页面,接收到消息时可根据消息类型发送消息已读回执(read ack),如下所示:

//接收消息回调。

- (void)messagesDidReceive:(NSArray *)aMessages
  {
    for (EMChatMessage *message in aMessages) {
        //发送消息已读回执。
        [self sendReadAckForMessage:message];
    }
  }

/**

  * 发送已读回执。
  * @param message
    */

- (void)sendReadAckForMessage:(EMChatMessage *)aMessage
  {
    //这里是接收的消息,未发送过 read ack 消息且是单聊。
    if (aMessage.direction == EMMessageDirectionSend || aMessage.isReadAcked || aMessage.chatType != EMChatTypeChat)
        return;

    EMMessageBody *body = aMessage.body;
    //视频、语音及文件需要点击后再发送,可以根据需求进行调整。
    if (body.type == EMMessageBodyTypeFile || body.type == EMMessageBodyTypeVoice || body.type == EMMessageBodyTypeImage)
        return;
        
    [[EMClient sharedClient].chatManager sendMessageReadAck:aMessage.messageId toUser:aMessage.conversationId completion:nil];
  }
  
监听单个消息的已读回执

可以调用接口监听某个消息是否已读,示例代码如下:

//接收到已读回执。

- (void)messagesDidRead:(NSArray *)aMessages
  {
    for (EMChatMessage *message in aMessages) {
        //添加刷新页面通知等逻辑。
    }
  }
  

群组消息已读回执

对于群消息,消息发送方(目前为管理员和群主)可设置是否需要已读回执。若需要,设置 EMChatMessage 的属性 isNeedGroupAckYES

EMChatMessage *message = [[EMChatMessage alloc] initWithConversationID:to from:from to:to body:aBody ext:aExt];
message.isNeedGroupAck = YES;
发送群组消息的已读回执
- (void)sendGroupMessageReadAck:(EMChatMessage *)msg
  {
    if (msg.isNeedGroupAck && !msg.isReadAcked) {
        [[EMClient sharedClient].chatManager sendGroupMessageReadAck:msg.messageId toGroup:msg.conversationId content:@"123" completion:^(EMError *error) {
            if (error) {
               

            }
        }];

    }
  }
  
监听群组消息已读回调

群消息已读回调在回调代理 EMChatManagerDelegate 中。

//接收到群组消息的已读回执, 消息的接收方已经阅读此消息。

- (void)groupMessageDidRead:(EMChatMessage *)aMessage groupAcks:(NSArray *)aGroupAcks
  {
    for (GroupMessageAck *messageAck in aGroupAcks) {
        //receive group message read ack
    }
  } 
  

接收到群组消息已读回执后,发出消息的属性 groupAckCount 会有相应变化;

获取群组消息已读回执详情

如果想实现群消息已读回执的列表显示,可以通过下列接口获取到已读回执的详情。

/**

  * 从服务器获取指定群已读回执。
    *
 * 异步方法
   *
 * @param  aMessageId           要获取的消息 ID。
 * @param  aGroupId             要获取回执对应的群 ID。
 * @param  aGroupAckId          要获取的群回执 ID。
 * @param  aPageSize            获取消息条数。
 * @param  aCompletionBlock     获取消息结束的回调。
   */
   [[EMClient sharedClient].chatManager asyncFetchGroupMessageAcksFromServer:messageId groupId:groupId startGroupAckId:nil pageSize:pageSize completion:^(EMCursorResult *aResult, EMError *error, int totalCount) {
   //页面刷新等操作。
   }];
   

推荐使用方案

推荐使用方案为会话已读回执(conversation ack)+单条消息已读回执(read ack)结合实现,可减少发送已读回执数量。

(1)未启动聊天页面的情况下,有未读消息,点击进入聊天页面,调用会话已读回执 (conversation ack);

(2)已经启动聊天页面内的情况下,接收到消息,即发送单条消息已读回执 (read ack) ,具体实现可参考:发送 read ack 消息