• UIKit
  • SDK
  • 服务端 API
Chat/
SDK/
Android/
消息/
SDK
  • 集成 SDK
  • 初始化
  • 登录登出
  • 消息
    • 介绍
    • 发送消息
    • 接收消息
    • 历史消息
    • 转发消息
    • 消息变更
    • 插入消息
    • 删除消息
    • 清空消息
    • 撤回消息
    • 在线消息
    • 已读回执
    • 查询消息
    • 群 @ 消息
    • 群定向消息
    • 消息免打套
    • 消息扩展
    • 消息回应
    • 消息翻译
    • 消息置顶
  • 会话
    • 介绍
    • 会话列表
    • 获取会话
    • 会话未读数
    • 置顶会话
    • 删除会话
    • 会话草稿
    • 会话标记
    • 会话分组
  • 群组
    • 介绍
    • 管理群组
    • 群资料
    • 管理群成员
    • 群成员资料
    • 自定义属性
    • 群计数器
  • 社群话题
    • 管理社群
    • 权限组
  • 用户
    • 用户资料
    • 用户状态
    • 管理好友
    • 好友分组
    • 黑名单
    • 关注与粉丝
  • 本地搜索
    • 搜索消息
    • 搜索好友
    • 搜索群组
    • 搜索群成员
  • 信令
  • 客户端 API
    • Java
  • 开发指引
  • 控制台指南
    • 创建和升级应用
    • 基本配置
    • 功能配置
    • 账号管理
    • 群组管理
    • 回调配置
  • 产品介绍
    • 消息管理
      • 单聊消息
      • 消息存储
      • 离线推送
      • 群消息
      • 消息格式
    • 账号系统
      • 登陆验证
      • 在线状态管理
    • 群相关
      • 群组系统
      • 群组管理
    • 用户资料和关系链
      • 资料管理
      • 关系链管理
  • 购买指南
    • 计费概述
    • 价格中心
  • 错误码

已读回执

功能描述

已读回执(Read Receipt)用于通知发送人“接收人已经阅读了发送的消息”。当接收人阅读消息后,上报消息已读,后台系统会生成一条通知,并将其发送给发送人,以告知消息已被查看。
在即时通讯工具(例如:WhatsApp、微信等)中,当接收人查看消息时,发送人会看到消息旁边的已读标记,例如蓝色的对勾或“已读”字样。
说明:
“回执”的含义是“回复的收据”,它代表了一种确认接收的凭证。当你发送一条消息,并请求一个回执,你实际上是在请求对方“我想确认你们是否接收并阅读了我的消息”。这个确认就像是一张“收据”,证明你的消息已经被接收。
已读回执有助于确保重要信息已被查看,但也可能引发心理压力和隐私问题,因此我们支持用户关闭已读回执功能。
说明:
该功能仅对进阶版客户开放,购买进阶版后可使用。
群聊已读回执仅增强版 SDK 6.1.2155 及以上版本支持。
单聊已读回执仅增强版 SDK 6.2.2363 及以上版本支持。

效果展示

您可以使用本功能,实现如下图所示的消息未读、已读效果:




接口说明

设置支持已读回执的群类型

如果要支持群聊消息已读回执,需要先在 控制台 中设置支持已读回执的群类型,选中的群类型才能使用已读回执功能。配置路径:Applications > Your App > Chat > Configuration > Group Configuration > Group feature configuration > Read receipts for group messages。
单聊消息已读回执不需要在控制台做任何设置,默认支持已读回执。

发送端设置消息需要已读回执

发送端创建消息后,先通过消息对象 V2TIMMessageneedReadReceipt(Android / iOS & Mac / Windows) 字段设置这条消息需要已读回执,再发送消息到会话中。
示例代码如下:
Android
iOS & Mac
Windows
V2TIMMessage message = V2TIMManager.getMessageManager().createTextMessage("群已读回执消息");
// 设置消息需要已读回执
message.setNeedReadReceipt(true);
// 发送消息
V2TIMManager.getMessageManager().sendMessage(message, null, "groupA", V2TIMMessage.V2TIM_PRIORITY_NORMAL, false, null, new V2TIMSendCallback<V2TIMMessage>() {
@Override
public void onProgress(int progress) {
}

@Override
public void onSuccess(V2TIMMessage message) {
}

@Override
public void onError(int code, String desc) {
}
});
/// 接口调用示例
V2TIMMessage *message = [[V2TIMManager sharedInstance] createTextMessage:@"群已读回执消息"];
// 设置消息需要已读回执
message.needReadReceipt = YES;
// 发送消息
[[V2TIMManager sharedInstance] sendMessage:message receiver:nil groupID:@"groupA" priority:V2TIM_PRIORITY_NORMAL onlineUserOnly:NO offlinePushInfo:nil progress:nil succ:nil fail:nil];
class SendCallback final : public V2TIMSendCallback {
public:
using SuccessCallback = std::function<void(const V2TIMMessage&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;
using ProgressCallback = std::function<void(uint32_t)>;

SendCallback() = default;
~SendCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback,
ProgressCallback progress_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
progress_callback_ = std::move(progress_callback);
}

void OnSuccess(const V2TIMMessage& message) override {
if (success_callback_) {
success_callback_(message);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}
void OnProgress(uint32_t progress) override {
if (progress_callback_) {
progress_callback_(progress);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
ProgressCallback progress_callback_;
};

V2TIMMessage message = V2TIMManager::GetInstance()->GetMessageManager()->CreateTextMessage(u8"群已读回执消息");
// 设置消息需要已读回执
message.setNeedReadReceipt(true);

auto callback = new SendCallback{};
callback->SetCallback([=](const V2TIMMessage& message) { delete callback; },
[=](int error_code, const V2TIMString& error_message) { delete callback; },
[=](uint32_t progress) {});

V2TIMManager::GetInstance()->GetMessageManager()->SendMessage(
message, "groupA", {}, V2TIMMessagePriority::V2TIM_PRIORITY_DEFAULT, false, {}, callback);

接收端发送消息已读回执

接收端收到消息后,根据消息对象 V2TIMMessageneedReadReceipt 字段判断消息是否需要已读回执。如果需要,当用户查看消息后,调用 sendMessageReadReceipts(Android / iOS & Mac / Windows) 接口发送消息已读回执。
示例代码如下:
Android
iOS & Mac
Windows
// 假设 message 消息用户已经查看
if (!message.isSelf() && message.isNeedReadReceipt()) {
List<V2TIMMessage> messageList = new ArrayList<>();
messageList.add(message);
V2TIMManager.getMessageManager().sendMessageReadReceipts(messageList, new V2TIMCallback() {
@Override
public void onSuccess() {
// 发送消息已读回执成功
}

@Override
public void onError(int code, String desc) {
// 发送消息已读回执失败
}
});
}
/// 接口调用示例
/// 假设 msg 消息用户已经查看
if (!msg.isSelf && msg.needReadReceipt) {
[[V2TIMManager sharedInstance] sendMessageReadReceipts:@[msg] succ:^{
// 发送消息已读回执成功
} fail:^(int code, NSString *desc) {
// 发送消息已读回执失败
}];
}
class Callback final : public V2TIMCallback {
public:
using SuccessCallback = std::function<void()>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

Callback() = default;
~Callback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess() override {
if (success_callback_) {
success_callback_();
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

auto callback = new Callback;
callback->SetCallback(
[=]() {
// 发送消息已读回执成功
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 发送消息已读回执失败
delete callback;
});

// 假设 message 消息用户已经查看
if (!message.isSelf && message.needReadReceipt) {
V2TIMMessageVector messageList;
messageList.PushBack(message);
V2TIMManager::GetInstance()->GetMessageManager()->SendMessageReadReceipts(messageList, callback);
}

发送端监听消息已读回执通知

接收端发送消息已读回执后,发送端可以在 V2TIMAdvancedMsgListeneronRecvMessageReadReceipts(Android / iOS & Mac / Windows) 中收到已读回执通知,在通知中更新 UI,例如更新某条消息为 “2 人已读”。
示例代码如下:
Android
iOS & Mac
Windows
V2TIMAdvancedMsgListener advancedMsgListener = new V2TIMAdvancedMsgListener() {
@Override
public void onRecvMessageReadReceipts(List<V2TIMMessageReceipt> receiptList) {
for (V2TIMMessageReceipt receipt : receiptList) {
// 已读回执消息 ID
String msgID = receipt.getMsgID();
// C2C 消息对方 ID
String userID = receipt.getUserID();
// C2C 消息对方已读状态
boolean isPeerRead = receipt.isPeerRead();
// 群消息最新已读数
long readCount = receipt.getReadCount();
// 群消息最新未读数
long unreadCount = receipt.getUnreadCount();
}
}
};
V2TIMManager.getMessageManager().addAdvancedMsgListener(advancedMsgListener);
/// 接口调用示例
[[V2TIMManager sharedInstance] addAdvancedMsgListener:self];
- (void)onRecvMessageReadReceipts:(NSArray<V2TIMMessageReceipt *> *)receiptList {
for(V2TIMMessageReceipt *receipt in receiptList) {
// 已读回执消息 ID
NSString *msgID = receipt.msgID;
// C2C 消息对方 ID
NSString * userID = receipt.userID;
// C2C 消息对方已读状态
BOOL isPeerRead = receipt.isPeerRead;
// 群组 ID
NSString * groupID = receipt.groupID;
// 群消息最新已读数
uint64_t readCount = receipt.readCount;
// 群消息最新未读数
uint64_t unreadCount = receipt.unreadCount;
}
}
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {
public:
/**
* 消息已读回执通知
*
* @param receiptList 已读回执列表
*/
void OnRecvMessageReadReceipts(const V2TIMMessageReceiptVector& receiptList) override {
for (size_t i = 0; i < receiptList.Size(); ++i) {
const V2TIMMessageReceipt& receipt = receiptList[i];
// 已读回执消息 ID
V2TIMString msgID = receipt.msgID;
// C2C 消息对方 ID
V2TIMString userID = receipt.userID;
// C2C 消息对方已读状态
bool isPeerRead = receipt.isPeerRead;
// 群组 ID
V2TIMString groupID = receipt.groupID;
// 群消息最新已读数
int32_t readCount = receipt.readCount;
// 群消息最新未读数
int32_t unreadCount = receipt.unreadCount;
}
}
// 其他成员 ...
};

// 添加高级消息的事件监听器,注意在移除监听器之前需要保持 advancedMsgListener 的生命期,以免接收不到事件回调
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);

发送端主动拉取消息已读回执信息

发送端从其他界面进入消息列表后,先拉取历史消息,再调用 getMessageReadReceipts(Android / iOS & Mac / Windows) 接口拉取消息已读回执信息。
其中已读回执信息 V2TIMMessageReceipt 字段含义如下:
属性
含义
说明
msgID
消息 ID
消息唯一 ID。
userID
对端用户 ID
如果是单聊,该字段表示对端用户 ID。
isPeerRead
消息对端用户是否已读
如果是单聊,该字段表示消息对端用户是否已读。
timestamp
对端用户标记会话已读时间
该字段在消息已读场景无效。如果是单聊,当对端用户调用 markC2CMessageAsRead 接口标记会话已读时,自己会收到的 onRecvC2CReadReceipt 回调,回调里会携带 timestamp 信息。markC2CMessageAsRead 的使用请参考:会话未读数
groupID
群组 ID
如果是群聊,该字段为群组 ID。
readCount
群消息已读人数
如果是群聊,该字段为群消息已读人数。
unreadCount
群消息未读人数
如果是群聊,该字段为群消息未读人数。
示例代码如下:
Android
iOS & Mac
Windows
/// 接口调用示例(以 Group 消息为例)
V2TIMManager.getMessageManager().getGroupHistoryMessageList("groupA", 20, null, new V2TIMValueCallback<List<V2TIMMessage>>() {
@Override
public void onSuccess(final List<V2TIMMessage> v2TIMMessages) {
List<V2TIMMessage> receiptMsgs = new ArrayList<>();
// 自己发送的消息 && 需要已读回执,需要拉取消息的已读回执信息
for (V2TIMMessage msg : v2TIMMessages) {
if (msg.isSelf() && msg.isNeedReadReceipt()) {
receiptMsgs.add(msg);
}
}
V2TIMManager.getMessageManager().getMessageReadReceipts(receiptMsgs, new V2TIMValueCallback<List<V2TIMMessageReceipt>>() {
@Override
public void onSuccess(List<V2TIMMessageReceipt> v2TIMMessageReceipts) {
Map<String, V2TIMMessageReceipt> messageReceiptMap = new HashMap<>();
for (V2TIMMessageReceipt receipt : v2TIMMessageReceipts) {
messageReceiptMap.put(receipt.getMsgID(), receipt);
}
for (V2TIMMessage msg : v2TIMMessages) {
V2TIMMessageReceipt receipt = messageReceiptMap.get(msg.getMsgID());
if (receipt != null) {
// C2C 消息对方 ID
String userID = receipt.getUserID();
// C2C 消息对方已读状态
boolean isPeerRead = receipt.isPeerRead();
// 群组 ID
String groupID = receipt.getGroupID();
// 消息已读数,readCount 为 0,表示消息无人已读
long readCount = receipt.getReadCount();
// 消息未读数,unreadCount 为 0,表示消息全部已读
long unreadCount = receipt.getUnreadCount();
}
}
}

@Override
public void onError(int code, String desc) {
// 拉取消息已读状态失败
}
});
}

@Override
public void onError(int code, String desc) {
// 拉取消息失败
}
});
/// 接口调用示例(以 Group 消息为例)
[[V2TIMManager sharedInstance] getGroupHistoryMessageList:@"groupA" count:20 lastMsg:nil succ:^(NSArray<V2TIMMessage *> *msgs) {
NSMutableArray *receiptMsgs = [NSMutableArray array];
// 自己发送的消息 && 需要已读回执,需要拉取消息的已读回执信息
for (V2TIMMessage *msg in msgs) {
if (msg.isSelf && msg.needReadReceipt) {
[receiptMsgs addObject:msg];
}
}
[[V2TIMManager sharedInstance] getMessageReadReceipts:receiptMsgs succ:^(NSArray<V2TIMMessageReceipt *> *receiptList) {
NSMutableDictionary *param = [NSMutableDictionary dictionary];
for (V2TIMMessageReceipt *receipt in receiptList) {
[param setObject:receipt forKey:receipt.msgID];
}
for (V2TIMMessage *msg in msgs) {
V2TIMMessageReceipt *receipt = param[msg.msgID];
// C2C 消息对方 ID
NSString * userID = receipt.userID;
// C2C 消息对方已读状态
BOOL isPeerRead = receipt.isPeerRead;
// 群组 ID
NSString * groupID = receipt.groupID;
// 消息已读数,readCount 为 0,表示消息无人已读
uint64_t readCount = receipt.readCount;
// 消息未读数,unreadCount 为 0,表示消息全部已读
uint64_t unreadCount = receipt.unreadCount;
}
} fail:^(int code, NSString *desc) {
// 拉取消息已读状态失败
}];
} fail:^(int code, NSString *desc) {
// 拉取消息失败
}];
template <class T>
class ValueCallback final : public V2TIMValueCallback<T> {
public:
using SuccessCallback = std::function<void(const T&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

ValueCallback() = default;
~ValueCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess(const T& value) override {
if (success_callback_) {
success_callback_(value);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

// 接口调用示例(以 Group 消息为例)
V2TIMMessageListGetOption option;
option.getType = V2TIMMessageGetType::V2TIM_GET_CLOUD_OLDER_MSG; // 拉取云端的更老的消息
option.count = 20; // 每页 20 条
option.groupID = "groupA"; // 拉取群聊消息

auto callback = new ValueCallback<V2TIMMessageVector>{};
callback->SetCallback(
[=](const V2TIMMessageVector& messageList) {
V2TIMMessageVector receiptMsgs;
for (size_t i = 0; i < messageList.Size(); ++i) {
const V2TIMMessage& message = messageList[0];
// 自己发送的消息 && 需要已读回执,需要拉取消息的已读回执信息
if (message.isSelf && message.needReadReceipt) {
receiptMsgs.PushBack(message);
}
}

auto receipt_callback = new ValueCallback<V2TIMMessageReceiptVector>{};
receipt_callback->SetCallback(
[=](const V2TIMMessageReceiptVector& receiptList) {
std::unordered_map<V2TIMString, V2TIMMessageReceipt> map;
for (size_t i = 0; i < receiptList.Size(); ++i) {
const V2TIMMessageReceipt& receipt = receiptList[i];
map[receipt.msgID] = receipt;
}
for (size_t i = 0; i < messageList.Size(); ++i) {
const V2TIMMessage& message = messageList[0];
if (map.count(message.msgID)) {
const V2TIMMessageReceipt& receipt = map[message.msgID];
// C2C 消息对方 ID
V2TIMString userID = receipt.userID;
// C2C 消息对方已读状态
bool isPeerRead = receipt.isPeerRead;
// 群组 ID
V2TIMString groupID = receipt.groupID;
// 消息已读数,readCount 为 0,表示消息无人已读
int32_t readCount = receipt.readCount;
// 消息未读数,unreadCount 为 0,表示消息全部已读
int32_t unreadCount = receipt.unreadCount;
}
const V2TIMMessageReceipt& receipt = receiptList[i];
}

delete receipt_callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 拉取消息已读状态失败
delete receipt_callback;
});

V2TIMManager::GetInstance()->GetMessageManager()->GetMessageReadReceipts(messageList, receipt_callback);

delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 拉取消息失败
delete callback;
});

V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(option, callback);

发送端主动拉取群消息已读或未读成员列表

发送端在需要查看群消息已读或未读成员列表时,可以调用 getGroupMessageReadMemberList(Android / iOS & Mac / Windows) 接口分页拉取消息已读或未读群成员列表。
Android
iOS & Mac
Windows
/// 接口调用示例
V2TIMManager.getMessageManager().getGroupMessageReadMemberList(message, V2TIMMessage.V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_READ, 0, 100, new V2TIMValueCallback<V2TIMGroupMessageReadMemberList>() {
@Override
public void onSuccess(V2TIMGroupMessageReadMemberList v2TIMGroupMessageReadMemberList) {
// members 当前分页拉取的已读成员列表
List<V2TIMGroupMemberInfo> members = v2TIMGroupMessageReadMemberList.getMemberInfoList();
// nextSeq 下次分页拉取的游标位置
long nextSeq = v2TIMGroupMessageReadMemberList.getNextSeq();
// isFinished 已读列表是否已经全部拉取完毕
boolean isFinished = v2TIMGroupMessageReadMemberList.isFinished();
// 如果已读列表没有全部拉取完毕,继续下一页拉取(这里只是示例代码,分页拉取建议由用户点击 UI 触发)
if (!isFinished) {
V2TIMManager.getMessageManager().getGroupMessageReadMemberList(message, V2TIMMessage.V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_READ, nextSeq, 100, new V2TIMValueCallback<V2TIMGroupMessageReadMemberList>() {
@Override
public void onSuccess(V2TIMGroupMessageReadMemberList v2TIMGroupMessageReadMemberList) {
// 拉群已读成员列表成功
}

@Override
public void onError(int code, String desc) {
// 拉群已读成员列表失败
}
});
}
}

@Override
public void onError(int code, String desc) {
// 拉群已读成员列表失败
}
});
/// 接口调用示例
[[V2TIMManager sharedInstance] getGroupMessageReadMemberList:message filter:V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_READ nextSeq:0 count:100 succ:^(NSMutableArray<V2TIMGroupMemberInfo *> *members, uint64_t nextSeq, BOOL isFinished) {
// members 当前分页拉取的已读成员列表
// nextSeq 下次分页拉取的游标位置
// isFinished 已读列表是否已经全部拉取完毕
// 如果已读列表没有全部拉取完毕,继续下一页拉取(这里只是示例代码,分页拉取建议由用户点击 UI 触发)
if (!isFinished) {
[[V2TIMManager sharedInstance] getGroupMessageReadMemberList:message filter:V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_READ nextSeq:nextSeq count:100 succ:^(NSMutableArray<V2TIMGroupMemberInfo *> *members, uint64_t nextSeq, BOOL isFinished) {
// 拉群已读成员列表成功
} fail:^(int code, NSString *desc) {
// 拉群已读成员列表失败
}];
}
} fail:^(int code, NSString *desc) {
// 拉群已读成员列表失败
}];
template <class T>
class ValueCallback final : public V2TIMValueCallback<T> {
public:
using SuccessCallback = std::function<void(const T&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

ValueCallback() = default;
~ValueCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess(const T& value) override {
if (success_callback_) {
success_callback_(value);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

auto callback = new ValueCallback<V2TIMGroupMessageReadMemberList>{};
callback->SetCallback(
[=](const V2TIMGroupMessageReadMemberList& groupMessageReadMemberList) {
// members 当前分页拉取的已读成员列表
const V2TIMGroupMemberInfoVector& members = groupMessageReadMemberList.members;
// nextSeq 下次分页拉取的游标位置
uint64_t nextSeq = groupMessageReadMemberList.nextSeq;
// isFinished 已读列表是否已经全部拉取完毕
bool isFinished = groupMessageReadMemberList.isFinished;
// 如果已读列表没有全部拉取完毕,继续下一页拉取(这里只是示例代码,分页拉取建议由用户点击 UI 触发)
if (!isFinished) {
auto callback = new ValueCallback<V2TIMGroupMessageReadMemberList>{};
callback->SetCallback(
[=](const V2TIMGroupMessageReadMemberList& groupMessageReadMemberList) {
// 拉群已读成员列表成功
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 拉群已读成员列表失败
delete callback;
});
V2TIMManager::GetInstance()->GetMessageManager()->GetGroupMessageReadMemberList(
message, V2TIMGroupMessageReadMembersFilter::V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_READ,
nextSeq, 100, callback);
}

delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 拉群已读成员列表失败
delete callback;
});

V2TIMManager::GetInstance()->GetMessageManager()->GetGroupMessageReadMemberList(
message, V2TIMGroupMessageReadMembersFilter::V2TIM_GROUP_MESSAGE_READ_MEMBERS_FILTER_READ, 0, 100,
callback);