消息回执
功能简介
消息已读回执,是指用户在会话中发送一条消息后,得知其他用户已读或未读此消息。本功能可用于在企业办公等需要实时知晓消息是否已经被阅读的场景。
本文档介绍了如何使用 ZIM SDK 的接口,实现发送一条附带回执的消息,以及查看和应答回执详情等功能。
ZIM SDK 目前支持发送“单聊”会话和“群组”会话的消息回执(仅支持普通消息和富媒体消息),暂不支持发送“房间”会话的消息回执。
实现流程
消息发送端通过 ZIM SDK 发送一条消息,并通过设置 ZIMMessageSendConfig 的 hasReceipt
字段标记该消息是否需要带回执,接收端可根据消息的回执状态 receiptStatus
判断该消息当前是否带回执,或者回执处于正在进行中还是已完成,从而渲染不同的 UI 效果,而接收端可根据不同的场景进行不同的已读方式。
发送一条附带回执的消息
如果客户端 A 想要向客户端 B 发送一条附带回执的消息:
- 客户端 A 和 客户端 B 登录 ZIM SDK;
- 客户端 A 调用 sendMessage 或 sendMediaMessage 接口,向客户端 B 发送一条消息(仅支持“单聊”会话和“群组”会话的普通消息和富媒体消息),并设置 ZIMMessageSendConfig 的
hasReceipt
字段为 true; - 客户端 B 通过监听相关回调( receivePeerMessage 或 receiveGroupMessage )会收到一条
receiptStatus
为PROCESSING
的消息。
接收端对消息回执进行已读操作
已读操作分为消息已读
和会话已读
。
消息已读
消息已读,是指接收端收到对方发送的附带回执的消息,可对该消息设置已读,已读成功,发送方将会收到该消息已被读的通知。
- 消息可为单条消息或批量消息,但是消息发送端与接收端必须在同一会话内,不允许跨会话。
- 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
- 客户端 B 通过相关回调( receivePeerMessage 或 receiveGroupMessage )收到客户端 A 发送的一条附带回执的消息;
- 客户端 B 根据回调的
receiptStatus
字段判断该消息的回执状态。如果是该字段为PROCESSING
,表示该消息处于“回执中”,开发者可根据自己的业务逻辑,调用 sendMessageReceiptsRead 接口将该消息设置为已读。 - 客户端 B 通过 ZIMMessageReceiptsReadSentCallback 得知设置是否成功。
- 客户端 A 通过 ZIMEventHandler 的 messageReceiptChanged 收到该消息被设置为消息已读的回调通知。开发者可根据这个回调,在客户端 A 实现将此消息设置为已读的业务逻辑。
会话已读
会话已读,是指接收端将指定会话内所有已接收的对方消息都设置为已读。
- 目前 ZIM SDK 只允许在单聊会话实现此功能;
- 此功能只作用于设置已读之前获取的消息,不对设置之后的消息生效。
- 此功能建议在用户从会话列表页进入到会话时使用,不推荐在同一会话中与 sendMessageReceiptsRead 接口混用。
- 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
- 客户端 B 根据回调 receivePeerMessage 的
receiptStatus
字段判断该消息的回执状态。如果是该字段为PROCESSING
,则表示该消息处于回执中,开发者可根据自己的业务逻辑,调用 sendConversationMessageReceiptRead 接口将会话内客户端 A 已发送的所有消息都设置为已读。 - 客户端 B 通过 ZIMConversationMessageReceiptReadSentCallback 得知设置是否成功。
- 客户端 A 通过 ZIMEventHandler 的 conversationMessageReceiptChanged 收到该消息被设置为会话已读的回调通知,开发者可根据这个回调,实现该会话所有对方发的消息都设置为已读的逻辑。开发者可根据这个回调,在客户端 A 实现自己发的所有消息都被客户端 B 设置为已读的业务逻辑。
更多功能
批量查询消息的回执状态、已读用户数和未读用户数
当需要查询一条或一批消息的回执状态、已读用户数和未读未读用户数时,可以调用 queryMessageReceiptsInfoByMessageList 接口查询,通过 ZIMMessageReceiptsInfoQueriedCallback 获取相关信息。
- 如果是查询其他用户发送的信息,得到的已读用户数和未读用户数都是 0。
- 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
查询群组里自己发送的消息的已读和未读成员列表
ZIM SDK 支持查询群组里自己发送的消息的已读成员列表和未读成员列表。
查询已读成员列表
当需要查询有哪些成员读了自己发送的消息,可调用 queryGroupMessageReceiptReadMemberListByMessage 接口查询具体成员列表。
如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
查询未读成员列表
当需要查询还有哪些成员未读自己发送的消息,可调用 queryGroupMessageReceiptUnreadMemberListByMessage 接口查询具体成员列表。
- 若 SDK 版本低于 2.16.0,当群成员人数大于 100 时,此接口不会返回具体未读成员列表。如需使用此功能,可联系 ZEGO 技术支持。
- 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
示例代码
// 1、创建 ZIM 对象,传入 appID、appSign
ZIMAppConfig *appConfig = [[ZIMAppConfig alloc] init];
appConfig.appID = (unsigned int)appID; // 替换为您从 ZEGO 控制台申请到的 AppID
appConfig.appSign = @"appSign"; // 替换为您从 ZEGO 控制台申请到的 AppSign
self.zim = [ZIM createWithAppConfig: appConfig];
// 2、登录
ZIMUserInfo *userInfo = [[ZIMUserInfo alloc]init];
userInfo.userID = @"zegoUser1"; // 填入 NSString 类型的值
userInfo.userName = @"zegotest"; // 填入 NSString 类型的值
[self.zim loginWithUserInfo:userInfo callback:^(ZIMError * _Nonnull errorInfo){
// 开发者可根据 ZIMError 来判断是否登录成功。
}];
- (void)zim:(ZIM *)zim messageReceiptChanged:(NSArray<ZIMMessageReceiptInfo *> *)infos{
// 对方设置了消息的已读回执
}
- (void)zim:(ZIM *)zim conversationMessageReceiptChanged:(NSArray<ZIMMessageReceiptInfo *> *)infos{
// 对方设置会话的已读回执
}
NSString *conversationID = @"xxx" ; // 会话 ID
// 3、用户 A 发送一条消息,并带上回执,以单聊文本消息为例
ZIMTextMessage *message = [[ZIMTextMessage alloc] init];
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc]init];
sendConfig.hasReceipt = true; // 设置消息带回执
[self.zim sendMessage:cmdMsg toUserID:toUserID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
// 开发者可以通过该回调监听消息是否发送成功。
if (errorInfo.code == 0) {
// 这里表示发送消息成功,message 的 receiptStatus 会为 PROCESSING,业务层可根据这个标志实现展示回执中(消息未读)的逻辑。
}
}];
// 4、用户 B 接收到回执,并做已读操作,选择以下任一接口即可
// 4.1 消息已读
NSMutableArray<ZIMMessage *> *messageList = [[NSMutableArray alloc] init];
[[ZIM getInstance] sendMessageReceiptsRead:messageList conversationID:@"conversationID" conversationType:conversationType callback:^(NSString * _Nonnull conversationID, ZIMConversationType conversationType, NSArray<NSNumber *> * _Nonnull errorMessageIDs, ZIMError * _Nonnull errorInfo) {
// 设置消息已读的回调
}];
// 4.2、会话已读
[[ZIM getInstance] sendConversationMessageReceiptRead:@"conversationID" conversationType:conversationType callback:^(NSString * _Nonnull conversationID, ZIMConversationType conversationType, ZIMError * _Nonnull errorInfo) {
// 设置会话已读的回调
}];
// 5、(可选)查询一批消息的回执状态、未读用户数和已读用户数
NSMutableArray<ZIMMessage *> *messageList = [[NSMutableArray alloc] init];
[[ZIM getInstance] queryMessageReceiptsInfoByMessageList:messageList conversationID:conversationID conversationType:conversationType callback:^(NSArray<ZIMMessageReceiptInfo *> * _Nonnull infos, NSArray<NSNumber *> * _Nonnull errorMessageIDs, ZIMError * _Nonnull errorInfo) {
// 查询到这一批消息的状态和数量,遍历 infos 获取对应 的消息 ID 和 count
}];
// 6、(可选)查询某一条群消息的已读群成员列表和未读群成员列表
// 6.1 已读用户列表
ZIMGroupMessageReceiptMemberQueryConfig *config = [[ZIMGroupMessageReceiptMemberQueryConfig alloc]init];
config.nextFlag = 0; // 查询的 flag ,初始时填 0,后续填从 callback 里返回的 flag。
config.count = 10; // 需要查询的用户数量。
[[ZIM getInstance] queryGroupMessageReceiptReadMemberListByMessage:message groupID:groupID config:config callback:^(NSString * _Nonnull groupID, NSArray<ZIMGroupMemberInfo *> * _Nonnull userList, unsigned int nextFlag, ZIMError * _Nonnull errorInfo) {
// 查询到对应的成员列表
}];
// 6.2 未读用户列表
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // 查询的 flag ,初始时填 0,后续填从 callback 里返回的 flag。
config.count = 10; // 需要查询的用户数量。
[[ZIM getInstance] queryGroupMessageReceiptUnreadMemberListByMessage:message groupID:groupID config:config callback:^(NSString * _Nonnull groupID, NSArray<ZIMGroupMemberInfo *> * _Nonnull userList, unsigned int nextFlag, ZIMError * _Nonnull errorInfo) {
// 查询到对应的成员列表
}];