逐条已读(v5)
逐条已读是在普通已读回执之上的细粒度语义:按消息逐条上报与查询,适合“群聊里某条重要消息谁读了”的场景。它与普通回执共用服务端读者记录,不产生两套状态。
与普通回执的差异
| 维度 | 普通已读回执 | 逐条已读(v5) |
|---|---|---|
| 上报粒度 | 一次可传多条 messageIds | 按消息逐条查询 / 展示 |
| 展示 | 单聊已读/未读;群聊 n/m | 每条消息的已读人数与已读用户 |
| 数据来源 | READ_RECEIPT 事件 + getMessageReadCount | getMessageReadUsers 分页明细 |
| 适用 | 会话级已读态 | 重点消息回执、群公告、审批类消息 |
| 成本 | 低 | 按消息查询,注意分页与频率 |
getMessageReadCount
查询消息已读人数。
| 项 | 值 |
|---|---|
| Swift | func getMessageReadCount(messageId: String) async -> RcResult<IMPMessageReadCount> |
| Objective-C | - (void)getMessageReadCountWithMessageId:(NSString *)messageId completion:(void (^)(IMPOSResult *result))completion |
| 传输 | REST(HTTP) |
| 幂等 | 否 |
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | 是 | 消息 ID(服务端生成) |
返回
{messageId:string, readCount:uint32, totalMembers:uint32}:已读人数与群成员总数
示例(Swift / Objective-C)
let count = await client.getMessageReadCount(messageId: "m_10001")
print(count.code)[client getMessageReadCountWithMessageId:@"m_10001" completion:^(IMPOSResult *result) {
if (result.code != 0) { NSLog(@"IM 调用失败:%ld %@", (long)result.code, result.msg); }
}];错误码
| 错误码 | 名称 | 分类 | HTTP | 可重试 | 说明 |
|---|---|---|---|---|---|
1001 | INVALID_PARAMETER | 客户端 / 参数 / 权限 | 400 | 否 | 参数错误 |
1003 | FORBIDDEN | 客户端 / 参数 / 权限 | 403 | 否 | 无权限 |
1004 | USER_NOT_FOUND | 客户端 / 参数 / 权限 | 404 | 否 | 用户不存在 |
getMessageReadUsers
查询已读用户明细(分页)。
| 项 | 值 |
|---|---|
| Swift | func getMessageReadUsers(messageId: String, options: IMPPageOptions?) async -> RcResult<IMPMessageReadUsers> |
| Objective-C | - (void)getMessageReadUsersWithMessageId:(NSString *)messageId options:(NSDictionary<NSString *, id> * _Nullable)options completion:(void (^)(IMPOSResult *result))completion |
| 传输 | REST(HTTP) |
| 幂等 | 否 |
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | 是 | 消息 ID(服务端生成) |
options | {offset?:uint32, limit?:uint32} | 否 | 选项对象(字段见类型列):{ offset?:uint32, limit?:uint32 } |
返回
{messageId:string, readCount:uint32, totalMembers:uint32, readers:UserProfile[]}:已读用户明细(分页)
示例(Swift / Objective-C)
let users = await client.getMessageReadUsers(messageId: "m_10001", options: nil)
print(users.code)[client getMessageReadUsersWithMessageId:@"m_10001" options:nil completion:^(IMPOSResult *result) {
if (result.code != 0) { NSLog(@"IM 调用失败:%ld %@", (long)result.code, result.msg); }
}];错误码
| 错误码 | 名称 | 分类 | HTTP | 可重试 | 说明 |
|---|---|---|---|---|---|
1001 | INVALID_PARAMETER | 客户端 / 参数 / 权限 | 400 | 否 | 参数错误 |
1003 | FORBIDDEN | 客户端 / 参数 / 权限 | 403 | 否 | 无权限 |
1004 | USER_NOT_FOUND | 客户端 / 参数 / 权限 | 404 | 否 | 用户不存在 |
展示建议
- 消息气泡只展示“已读 n / 总 m”,点击后弹出已读用户列表(分页加载)。
- 大群(成员数 > 500)不要在消息流里逐条拉明细,只在用户点击时按需查询。
- 已读用户列表按已读时间倒序;支持搜索昵称 / userId。
- 未读用户 = 群成员 - 已读用户;成员变动后以服务端总数 m 为准。
- 缓存已读结果 30 秒,避免频繁点击触发重复请求。
Swift
let res = await client.sendReadReceipt(conversationType: .privateChat, targetId: "user2", messageIds: ["m_10003"])
print(res.code)与 IMKit 的配合
`MessageStatusIndicator` 只负责展示;已读明细面板由宿主页面实现,数据由 IMLib 提供。