uniapp 实现腾讯云 IM 消息已读回执处理全攻略
一、功能实现原理
腾讯云 IM 的已读回执功能通过 消息已读上报机制
实现,核心流程如下:
- 接收方阅读消息时,客户端自动上报已读状态
- 云端记录最新已读时间戳(精确到会话维度)
- 发送方通过监听事件获取接收方的已读状态
- 群聊场景支持显示已读成员列表(需开通高级功能)
二、核心实现步骤
1. 发送消息时启用已读回执
// 创建文本消息(启用已读回执)
export function createTextMessageWithReceipt(options) {
const tim = initIM()
return tim.createTextMessage({
to: options.to,
conversationType: options.type || 'C2C',
payload: { text: options.content },
cloudCustomData: JSON.stringify({
needReadReceipt: true // 启用已读回执
})
})
}
2. 接收方自动上报已读
// 初始化时配置自动已读
tim = TIM.create({
SDKAppID: config.SDKAppID
})
// 进入会话时标记消息为已读
export async function markConversationRead(conversationID) {
const tim = initIM()
const conv = tim.getConversationProfile(conversationID)
// 获取最后一条消息
const lastMsg = conv.getLastMessage()
if (!lastMsg) return
// 上报已读到最新消息
await tim.messageReportedRead({
conversationID,
lastMsgID: lastMsg.clientMsgID
})
}
3. 监听已读回执通知
// 全局消息监听器
export function setupMessageListener(callback) {
const tim = initIM()
tim.on(tim.EVENT.MESSAGE_READ_BY_PEER, (event) => {
const { data } = event
// 更新本地消息状态
data.forEach(receipt => {
const conv = tim.getConversationProfile(receipt.conversationID)
conv.setMessageRead(receipt.messageKey.clientMsgID)
// 触发UI更新
uni.$emit('message-read', {
conversationID: receipt.conversationID,
msgID: receipt.messageKey.clientMsgID,
reader: receipt.reader
})
})
})
}
4. 群聊已读成员处理
// 获取群聊已读成员列表
export async function getGroupReadMembers(groupID, msg) {
const tim = initIM()
try {
const res = await tim.getGroupMessageReadMembersList({
groupID,
messageKey: tim.createMessageKey(msg.clientMsgID)
})
return res.data.readMemberList || []
} catch (error) {
console.error('获取已读成员失败:', error)
return []
}
}
三、关键问题处理
1. 性能优化策略
// 批量上报已读(防抖处理)
let readReportDebounce = null
export function batchReportRead(conversationID, lastMsgID) {
clearTimeout(readReportDebounce)
readReportDebounce = setTimeout(async () => {
try {
await tim.messageReportedRead({
conversationID,
lastMsgID
})
} catch (error) {
console.warn('批量上报失败:', error)
}
}, 500) // 500ms防抖
}
2. 隐私保护方案
// 用户隐私设置(示例)
const PRIVACY_CONFIG = {
DISABLE_READ_RECEIPT: false // 用户是否关闭已读回执
}
// 发送消息时动态判断
export function createMessage(options) {
const tim = initIM()
return tim.createTextMessage({
...,
cloudCustomData: JSON.stringify({
needReadReceipt: !PRIVACY_CONFIG.DISABLE_READ_RECEIPT
})
})
}
3. 跨平台差异处理
// 微信小程序特殊处理
#ifdef MP-WEIXIN
// 修复小程序页面切换导致的已读上报延迟
Page({
onHide() {
const lastMsg = getCurrentPage().data.lastMsg
if (lastMsg) batchReportRead(lastMsg.conversationID, lastMsg.clientMsgID)
}
})
#endif
四、高级功能扩展
1. 已读状态可视化
<template>
<view class="message-item" :class="{ 'is-read': msg.isPeerRead }">
{{ msg.payload.text }}
<!-- 群聊已读状态 -->
<view v-if="isGroup && msg.isPeerRead" class="read-status">
{{ readCount }}人已读
</view>
</view>
</template>
<script>
export default {
props: ['msg', 'isGroup'],
computed: {
readCount() {
return this.msg.readCount || 0
}
}
}
</script>
2. 定时同步已读状态
// 定时任务配置(每5分钟同步)
setInterval(async () => {
const tim = initIM()
const convList = await tim.getConversationList()
convList.forEach(conv => {
const lastMsg = conv.getLastMessage()
if (lastMsg && !lastMsg.isPeerRead) {
tim.messageReportedRead({
conversationID: conv.conversationID,
lastMsgID: lastMsg.clientMsgID
})
}
})
}, 5 * 60 * 1000)
3. 业务逻辑集成
// 客服场景:自动标记为已读
export function autoReadMessages(conversationID) {
const tim = initIM()
const conv = tim.getConversationProfile(conversationID)
// 获取未读消息列表
const unreadMsgs = conv.getUnreadMessageList()
// 批量标记为已读
unreadMsgs.forEach(msg => {
conv.setMessageRead(msg.clientMsgID)
})
}
五、常见问题排查
Q: 已读回执未触发
A: 检查消息的cloudCustomData
是否包含needReadReceipt: true
,确认接收方版本 ≥ 2.18.0Q: 群聊已读人数不准确
A: 需在控制台开通「群消息已读回执」增值服务,并确保使用最新版 SDKQ: 已读状态同步延迟
A: 检查网络状况,已读回执默认使用长轮询,可升级到 WebSocket 连接Q: 消息漫游后状态丢失
A: 确保消息漫游策略包含已读状态(需在控制台配置)
六、最佳实践建议
- 重要消息(如系统通知)强制启用已读回执
- 对长文本消息采用分片上报策略(每10条上报一次)
- 结合消息优先级实现差异化已读策略(如@消息优先处理)
- 在消息列表展示最近已读时间(使用
TIM.TYPES.CONV_LAST_MSG
)