IM 会话阅读回执
1 需求
IM 单聊
消息发送人角度:显示对方已读|未读
接收人角度:本人会话的未读数
群聊
消息接收人角度:本人会话的未读数
发送人角度:群内其他人对本人发送消息的阅读情况:未读人数,已读|未读用户列表
单聊与群聊的阅读差异
单聊是一一对话,可认为对方阅读了会话最新消息就是将改会话的所有消息都读了,这样本身没问题,因为单聊下不存在一个人发很多消息对方一直没有回应,因此不存在有大量未读消息。
群聊则不同,群里的消息可能发送很多,群成员再查看群消息时,经常会有大量的未读消息,阅读时只看最近的若干条消息,并且也不继续往上看未读的历史消息。
本篇探讨单聊消息的阅读回执问题
2 单聊(会话)
2.1 产品需求
消息发送人:对方的已读/未读状态
消息接收人:多端阅读状态同步(会话的未读消息数同步)
2.2 核心问题与设计
2.2.1 核心问题
及时性
消息接收人阅读状态多端同步
消息接收人阅读后同步给消息发送人
这两个事都要有及时的反馈。
正确性:
计数不可逆,没有新消息未读数不能变多
即:已读的不能变为未读
离线阅读
离线下也可以阅读,并消除本地未读计数(红点强迫症)
消除后最好可以再 app 再上线后自动将离线的阅读操作同步上报。
精确性
单聊一般采用非精确方式,进入会话即视为改会话所有消息本人都已读。
未读数统计
客户端本地按消息统计
统计本地消息库中某个时间后的消息数
问题:会有消息补偿时效问题(超期未读的消息未同步下来没有计算到未读数)。
需要时从服务端获取
问题:存储或计算量过大
如采用实时统计:需要统计各个会话某个时间后的消息
如后端存储未读数:有消息就需要变更未读计数。
一般采用客户端统计:原因就是单聊不存在大量未读消息(按常用的使用场景来看)
未读与消息同步的时效问题
1>历史消息不会全部同步下来-一般只登陆后只同步热消息(最近的-单聊可忽略,群聊不可以)
2>阅读用户角度:没有读的会话希望可以标记出来-不遗漏重要消息,即便消息很久了。
3>消息发送人角度
对方是否阅读了本人的消息-即便很久的消息。
请求量大
客户端进入单聊会话时需判断是否需要进行阅读位置更新,不需要时减少请求量。
客户端本地记录本人的阅读位置:包括本地阅读及同步的其它端的阅读位置-记录最大值。
群聊会话的阅读状态请求量会远大于消息量。
2.2.2 设计
及时性
通过 IM 的长连接通道用消息或在线通知方式通知在线客户端
离线再登陆通过事件补偿推/拉 会话|消息进行同步
正确性
用 IM 同一个会话中消息的顺序指标作为标记值,如 IM 本身采用消息的发送时间戳,那么阅读操作也用消息的发送时间戳,如果用递增的消息 id,那么阅读操作也使用递增的消息 id.
即便出现补偿消息补偿到了较早的消息客户端也不回退(已读功能就认为消息是严格按序到达)。
服务端或客户端更新会话阅读标记时进行比较更新,只有大于时才更新。
离线阅读
客户端需要做离线记录,并上线同步。
精确性
非精确,单聊多采用只记录阅读位置,不记录阅读消息。阅读回执只到会话级别。
未读数计算
一般用客户端本地通过消息计算
针对历史消息可与服务端配合进行模糊性未读数补充+限量消息补偿。
超时的会话给少量最新消息,阅读位置如果小于用模糊计数表示
消息同步的失效问题
产品上做阉割,超过有效期的不处理,只热消息正确即可。
效果:
阅读人角度:会话做全量同步,保证不丢会话,阅读位置小于会话消息的进行补偿拉取。
消息发送人角度:对方的阅读记录进度记录在会话上,不受消息失效限制。
2.3 方案
1:会话上添加阅读位置属性
服务端会话:本人阅读位置+对方的阅读位置两个字段
阅读位置更新时,更新会话同步时间。
会话存储结构
====会话存储================================
单聊会话:
最后一条消息 id|时间
本人阅读位置
对方阅读位置
群聊:
记录本人阅读位置用于计算本人的未读消息数
=================================================
2:进入会话,如有新消息,更新阅读位置
判断会话的阅读位置与本会话中本人为接收人的最后一条消息,如有新消息触发更新
先更新本地+再调用 server 更新(更新失败记录到待补偿任务中)
server 更新:
设置最后一条消息的时间戳:更新两个会话(本人+对方)
触发多端同步:
给在线其他端推送事件
给发消息用户推送通知
3:登陆后同步
同步消息,同步会话
会话阅读位置小于会话最后一条消息进行会话消息补偿拉取。拉取到后如果有洞未读数模糊计数。
4:客户端收到阅读更新事件
递增更新本地阅读位置(本人阅读位置|对方阅读位置)。
5:离线下本地消除
更新本地后,记录补偿任务,上线后重新远程提交补偿任务。
6:客户端未读计算:
消息同步后,本地消息库统计。
7:时间有效期问题(历史消息同步问题)
消息接收人
长久不登陆,历史消息热消息拉不下来,有未读数的单聊会话进行补偿拉取。
即会话的历史消息即便不能全部步,但保证某个会话都有最新的几条消息,
消息库不确定未读个数的计数用模糊(*)代替精确数。
消息发送人
不会丢失对方的阅读信息(对方的阅读位置在会话上因此不受消息补偿的影响)。
版权声明: 本文为 InfoQ 作者【superman】的原创文章。
原文链接:【http://xie.infoq.cn/article/e8b369c484faea7f752456910】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论