消息管理–获取消息的已读回执和送达回执
更新时间:2022-02-28
本文介绍环信即时通讯 IM SDK 从服务器获取消息的已读回执和送达回执。
功能描述
环信即时通讯 IM 消息投递成功将返回送达回执,提供消息已读功能,接收方查看消息后返回已读回执。
功能 | 描述 |
---|---|
消息送达回执 | 消息下发成功后,返回消息送达回执。 |
消息已读回执 | 接收方查看消息后,返回消息已读回执。 |
单个消息已读回执 | 提供单聊消息已读回执能力。 |
群组消息已读回执 | 提供群组消息已读回执能力。群聊回执仅旗舰版及以上支持。 |
技术原理
使用环信即时通讯 IM SDK 可以实现消息的送达回执与已读回执,主要方法如下:
setRequireDeliveryAck
开启送达回执;ackConversationRead
发出指定会话的已读回执;ackMessageRead
发出指定消息的已读回执;ackGroupMessageRead
发出群组消息的已读回执。
前提条件
实现方法
消息送达回执
若在消息送达时收到通知,你可以打开消息送达开关,这样在消息到达对方设备时你可以收到通知。
// 设置是否需要接收方送达确认,默认 `false` 即不需要。
options.setRequireDeliveryAck(false);
onMessageDelivered
回调是对方收到消息时的通知,你可以在收到该通知时,显示消息的送达状态。
EMMessageListener msgListener = new EMMessageListener() {
//收到消息。
@Override
public void onMessageReceived(List<EMMessage> messages) {
}
//收到已送达回执。
@Override
public void onMessageDelivered(List<EMMessage> message) {
}
};
//记得在不需要的时候移除 listener,如在 activity 的 onDestroy() 时。
EMClient.getInstance().chatManager().removeMessageListener(msgListener);
消息已读回执
消息阅读后,可以发出已读回执,该回执需要你调用 API 实现,这样消息发送方可以知道消息已被阅读。
发送会话已读回执
发送已读回执消息
推荐进入会话页面,根据会话是否有未读消息,发送会话已读回执(conversation ack)
,有则发送,没有则不再发送。
try {
EMClient.getInstance().chatManager().ackConversationRead(conversationId);
} catch (HyphenateException e) {
e.printStackTrace();
}
该方法为异步方法,需要捕捉异常。
监听已读回执回调
EMClient.getInstance().chatManager().addConversationListener(new EMConversationListener() {
……
@Override
public void onConversationRead(String from, String to) {
//添加刷新页面通知等逻辑。
}
});
注意
onConversationRead
中的 from
和 to
与消息 EMMessage
中的定义相同。
会话已读回执 onConversationRead
的场景:
(1)消息被接收方阅读,且发送了已读回执 (conversation ack)
;
(2)多端多设备登录场景下,一端发送会话已读回执 (conversation ack)
,服务器端会将未读消息数置为 0,同时其他端会回调此方法。
单个消息的已读回执
注意
消息已读回执功能目前单聊 (ChatType.Chat)
可以直接集成,群聊需联系环信即时通讯 IM 的客户经理开通。单聊消息已读回执推荐使用方案为会话已读回执 (conversation ack)
+ 单条消息已读回执 (read ack)
结合实现,可减少发送已读回执数量。群消息已读回执功能为增值服务,具体使用请跳转到群消息已读回执。
发送已读回执消息
推荐进入会话首先发送会话已读回执 (conversation ack)
。
try {
EMClient.getInstance().chatManager().ackMessageRead(conversationId);
}
catch (HyphenateException e) {
e.printStackTrace();
}
在会话页面,可以在接收到消息时,根据消息类型发送消息已读回执 (read ack)
,如下所示:
EMClient.getInstance().chatManager().addMessageListener(new EMMessageListener() {
......
@Override
public void onMessageReceived(List<EMMessage> messages) {
......
sendReadAck(message);
......
}
......
});
/**
* 发送已读回执。
* @param message
*/
public void sendReadAck(EMMessage message) {
//这里是接收的消息,未发送过已读回执且是单聊。
if(message.direct() == EMMessage.Direct.RECEIVE
&& !message.isAcked()
&& message.getChatType() == EMMessage.ChatType.Chat) {
EMMessage.Type type = message.getType();
//视频,语音及文件需要点击后再发送,可以根据需求进行调整。
if(type == EMMessage.Type.VIDEO || type == EMMessage.Type.VOICE || type == EMMessage.Type.FILE) {
return;
}
try {
EMClient.getInstance().chatManager().ackMessageRead(message.getFrom(), message.getMsgId());
} catch (HyphenateException e) {
e.printStackTrace();
}
}
}
监听单个消息的已读回执
可以调用接口监听某个消息是否已读,示例代码如下:
EMClient.getInstance().chatManager().addMessageListener(new EMMessageListener() {
......
@Override
public void onMessageRead(List<EMMessage> messages) {
//添加刷新消息等逻辑。
}
......
});
群组消息已读回执
当消息为群消息时,消息发送方(目前为管理员和群主)可以设置此消息是否需要已读回执,如需要,则设置 EMMessage
的方法 setIsNeedGroupAck()
为 YES
,之后发送。
EMMessage message = EMMessage.createTxtSendMessage(content, to);
message.setIsNeedGroupAck(true);
发送群组消息的已读回执
public void sendAckMessage(EMMessage message) {
if (!validateMessage(message)) {
return;
}
if (message.isAcked()) {
return;
}
// May a user login from multiple devices, so do not need to send the ack msg.
if (EMClient.getInstance().getCurrentUser().equalsIgnoreCase(message.getFrom())) {
return;
}
try {
if (message.isNeedGroupAck() && !message.isUnread()) {
String to = message.conversationId(); // do not use getFrom() here
String msgId = message.getMsgId();
EMClient.getInstance().chatManager().ackGroupMessageRead(to, msgId, ((EMTextMessageBody)message.getBody()).getMessage());
message.setUnread(false);
EMLog.i(TAG, "Send the group ack cmd-type message.");
}
} catch (Exception e) {
EMLog.d(TAG, e.getMessage());
}
}
监听群组消息已读回调
群消息已读回调在消息监听类 EMMessageListener
中。
//接收到群组消息体的已读回执, 消息的接收方已经阅读此消息。
void onGroupMessageRead(List<EMGroupReadAck> groupReadAcks) {
//receive group message read ack
}
接收到群组消息已读回执后,发出消息的属性 groupAckCount
会有相应变化;
获取群组消息已读回执详情
如果想实现群消息已读回执的列表显示,可以通过下列接口获取到已读回执的详情。
/**
* \~chinese
* 从服务器获取群组消息回执详情。
* 分页获取。
* 发送群组消息回执,详见{@link #ackGroupMessageRead(String, String, String)}。
*
* 异步方法。
*
* @param msgId 消息 ID。
* @param pageSize 每次获取群消息已读回执的条数。
* @param startAckId 已读回执 ID,如果为空,从最新的回执向前开始获取。
* @param callBack 结果回调,成功执行 {@link EMValueCallBack#onSuccess(Object)},失败执行{@link EMValueCallBack#onError(int, String)}。
*
*/
public void asyncFetchGroupReadAcks(final String msgId, final int pageSize,
final String startAckId, final EMValueCallBack<EMCursorResult<EMGroupReadAck>> callBack) {
}
推荐使用方案
推荐使用方案为会话已读回执 (conversation ack)
+ 单条消息已读回执 结合实现,可减少发送 read ack
消息量。
(1)未启动聊天页面的情况下,有未读消息,点击进入聊天页面,调用会话已读回执 (conversation ack);
(2)已经启动聊天页面内的情况下,接收到消息,即发送单条消息已读回执 (read ack) ,具体实现可参考:发送 read ack 消息。