This document is applicable to the following platforms of Unity framework: iOS, Android, macOS, and Windows.
Overview
Message reading receipt helps users know whether other users have read the messages they sent in a conversation. This feature applies to enterprise office businesses and other scenarios in which the message reading status needs to be known in real time.
This document describes how to use APIs of the In-app Chat SDK to send messages that require a reading receipt, query the receipt status of messages, and set messages as read.
Warning
The In-app Chat SDK supports reading receipts for one-to-one messages and group messages (only common messages and rich media messages) and does not support reading receipts for in-room messages.
Implementation process
The sender sends a message through the In-app Chat SDK and sets the hasReceipt field of ZIMMessageSendConfig to identify whether a reading receipt is required for the message. Based on the receiptStatus field, the receiver determines whether a reading receipt is required for the message or whether the message is read or unread to render different UI effects. The message receiver can use different reading methods based on the scenario.
Send a message that requires a reading receipt
When Client A wants to send a message that requires a reading receipt to Client B:
Client A and Client B log in to the In-app Chat service.
Client A calls the sendMessage or sendMediaMessage API to send a message (common message or rich media message in one-to-one or group chats) to Client B and sets the hasReceipt field of ZIMMessageSendConfig to true.
By listening for related callback (onMessageReceived or onMessageReceived), Client B receives a message whose receiptStatus is set to PROCESSING.
Set the reading receipt status as read
In this operation, set a message as read and set a conversation as read are both supported.
Set a message as read
The receiver can set a message that requires a reading receipt from the sender as read. Then, the sender will receive a message read notification.
Warning
A single message or a batch of messages are supported. The sender and receiver must be in the same conversation. Cross-conversation operations are not supported.
To perform operations on the historical messages of the conversation, you need to get the historical messages and determine the receipt status of the historical messages. For details, see Get message history.
Through related callback (onMessageReceived or onMessageReceived), Client B receives a message that requires a reading receipt from Client A.
Based on the receiptStatus field of the callback, Client B determines the receipt status of the message. If this field is set to PROCESSING, the message is unread. Developers can call the sendMessageReceiptsRead API to set the message as read based on the service logic.
Based on onMessageReceiptChanged of ZIMEventHandler, Client A receives a callback notification, indicating that the message is set as read. Developers can implement the service logic of setting the message as read on Client A based on this callback.
Set a conversation as read
The receiver can set all messages received from the sender in a specified conversation as read.
Warning
The In-app Chat SDK supports this feature only in one-to-one chats.
This feature takes effect only on messages received before setting the feature.
It is recommended that this feature be used when a user switches from the conversation list page to a conversation. It is not recommended that this feature be used together with the sendMessageReceiptsRead API on a message chat page.
To perform operations on the historical messages of the conversation, you need to get the historical messages and determine the receipt status of the historical messages. For details, see Get message history.
Based on the receiptStatus field of the onMessageReceived callback, Client B determines the receipt status of the message. If this field is set to PROCESSING, the message is unread. Developers can call the sendConversationMessageReceiptRead API to set all messages sent by Client A in the conversation as read based on the service logic.
Based on onConversationMessageReceiptChanged of ZIMEventHandler , Client A receives a callback notification, indicating that all messages in the conversation are set as read. Developers can implement the logic of setting all messages sent from the sender in the conversation as read based on this callback. Developers can implement the service logic of knowing all sent messages in a conversation are set as read by Client B on Client A based on this callback.
More features
Get read receipt time
Through ZIMMessageReceiptInfo.readTime , you can get the read receipt time of the message, which can be used to implement the business scenario of secret chat, such as "burn after reading".
For the message sender: When all members in the conversation have read the message, the read receipt time will have a value, and the server timestamp when the last member reads will be returned. Otherwise, the value is 0.
For the message receiver: The read receipt time is the server timestamp when the sendMessageReceiptsRead API is successfully called. Otherwise, the value is 0.
Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message
To query the message receipt status, the number of users who have read the message, and the number of users who have not read the message of a message or a batch of messages, call the queryMessageReceiptsInfo API. Call ZIMMessageReceiptsInfoQueriedResult to obtain related information.
Warning
If messages sent by other users are queried, the number of users who have read the message and the number of users who have not read the message are 0.
To perform operations on the historical messages of the conversation, you need to get the historical messages and determine the receipt status of the historical messages. For details, see Get message history.
Query the list of members who have or have not read a group message
The In-app Chat SDK supports querying the list of members who have or have not read a group message.
Query the list of members who have read a group message
To perform operations on the historical messages of the conversation, you need to get the historical messages and determine the receipt status of the historical messages. For details, see Get message history.
Query the list of members who have not read a group message
If the SDK version is older than 2.16.0, when the number of group members is greater than 100, this API will not return the list of members who have not read a group message. To use this feature, contact ZEGOCLOUD technical support.
To perform operations on the historical messages of the conversation, you need to get the historical messages and determine the receipt status of the historical messages. For details, see Get message history.
Sample code
zim.setEventHandler(new ZIMEventHandler() {
@Override
public void onMessageReceiptChanged(ZIM zim, ArrayList<ZIMMessageReceiptInfo> infos) {
// The other user sets a message as read.
}
@Override
public void onConversationMessageReceiptChanged(ZIM zim, ArrayList<ZIMMessageReceiptInfo> infos) {
// The other user sets all messages in a conversation as read.
}
})
// User A sends a message that requires a reading receipt. A text one-to-one message is used as an example.
String conversationID = "xxx" ; // The conversation ID
ZIMTextMessage message = new ZIMTextMessage("test");
ZIMMessageSendConfig sendConfig = new ZIMMessageSendConfig();
sendConfig.hasReceipt = true; // Set that the messages require a reading receipt.
zim.sendMessage(message, conversationID, ZIMConversationType.PEER,sendConfig, new ZIMMessageSentCallback() {
@Override
public void onMessageAttached(ZIMMessage message) {}
@Override
public void onMessageSent(ZIMMessage message, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// This indicates that the message is sent successfully. receiptStatus of the message is set to PROCESSING. The service layer can display the logic that a message is unread based on this flag.
}
}
});
// User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// Set a message as read
List<ZIMMessage> messages = new ArrayList<>();
messages.add(message);
zim.sendMessageReceiptsRead(messages, conversationID, ZIMConversationType.PEER,
new ZIMMessageReceiptsReadSentCallback() {
@Override
public void onMessageReceiptsReadSent(String conversationID, ZIMConversationType conversationType,
ArrayList<Long> errorMessageIDs, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// Callback for setting a message as read.
}
}
});
// Set a conversation as read
zim.sendConversationMessageReceiptRead(conversationID, ZIMConversationType.PEER,
new ZIMConversationMessageReceiptReadSentCallback() {
@Override
public void onConversationMessageReceiptReadSent(String conversationID,
ZIMConversationType conversationType, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// A conversation is read. Developers can listen for this callback to set all messages sent by the sender in this conversation as read.
}
}
});
// (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
List<ZIMMessage> messages = new ArrayList<>();
messages.add(message);
zim.queryMessageReceiptsInfo(messages, conversationID, ZIMConversationType.PEER, new ZIMMessageReceiptsInfoQueriedCallback() {
@Override
public void onMessageReceiptsInfoQueried(ArrayList<ZIMMessageReceiptInfo> infos,
ArrayList<Long> errorMessageIDs, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// The status and quantity of this batch of messages are queried, and the corresponding message ID and count are obtained by traversing the information.
}
}
});
// (Optional) Query the list of members who have or have not read a group message.
// The list of members who have read a group message
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
zim.queryGroupMessageReceiptReadMemberList(message, groupID, config,
new ZIMGroupMessageReceiptMemberListQueriedCallback() {
@Override
public void onGroupMessageReceiptMemberListQueried(String groupID, ArrayList<ZIMGroupMemberInfo> userList,
int nextFlag, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// The corresponding member list is queried.
}
}
});
// The list of members who have not read a group message
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
zim.queryGroupMessageReceiptUnreadMemberList(message, groupID, config,
new ZIMGroupMessageReceiptMemberListQueriedCallback() {
@Override
public void onGroupMessageReceiptMemberListQueried(String groupID, ArrayList<ZIMGroupMemberInfo> userList,
int nextFlag, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// The corresponding member list is queried.
}
}
});
zim.setEventHandler(new ZIMEventHandler() {
@Override
public void onMessageReceiptChanged(ZIM zim, ArrayList<ZIMMessageReceiptInfo> infos) {
// The other user sets a message as read.
}
@Override
public void onConversationMessageReceiptChanged(ZIM zim, ArrayList<ZIMMessageReceiptInfo> infos) {
// The other user sets all messages in a conversation as read.
}
})
// User A sends a message that requires a reading receipt. A text one-to-one message is used as an example.
String conversationID = "xxx" ; // The conversation ID
ZIMTextMessage message = new ZIMTextMessage("test");
ZIMMessageSendConfig sendConfig = new ZIMMessageSendConfig();
sendConfig.hasReceipt = true; // Set that the messages require a reading receipt.
zim.sendMessage(message, conversationID, ZIMConversationType.PEER,sendConfig, new ZIMMessageSentCallback() {
@Override
public void onMessageAttached(ZIMMessage message) {}
@Override
public void onMessageSent(ZIMMessage message, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// This indicates that the message is sent successfully. receiptStatus of the message is set to PROCESSING. The service layer can display the logic that a message is unread based on this flag.
}
}
});
// User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// Set a message as read
List<ZIMMessage> messages = new ArrayList<>();
messages.add(message);
zim.sendMessageReceiptsRead(messages, conversationID, ZIMConversationType.PEER,
new ZIMMessageReceiptsReadSentCallback() {
@Override
public void onMessageReceiptsReadSent(String conversationID, ZIMConversationType conversationType,
ArrayList<Long> errorMessageIDs, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// Callback for setting a message as read.
}
}
});
// Set a conversation as read
zim.sendConversationMessageReceiptRead(conversationID, ZIMConversationType.PEER,
new ZIMConversationMessageReceiptReadSentCallback() {
@Override
public void onConversationMessageReceiptReadSent(String conversationID,
ZIMConversationType conversationType, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// A conversation is read. Developers can listen for this callback to set all messages sent by the sender in this conversation as read.
}
}
});
// (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
List<ZIMMessage> messages = new ArrayList<>();
messages.add(message);
zim.queryMessageReceiptsInfo(messages, conversationID, ZIMConversationType.PEER, new ZIMMessageReceiptsInfoQueriedCallback() {
@Override
public void onMessageReceiptsInfoQueried(ArrayList<ZIMMessageReceiptInfo> infos,
ArrayList<Long> errorMessageIDs, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// The status and quantity of this batch of messages are queried, and the corresponding message ID and count are obtained by traversing the information.
}
}
});
// (Optional) Query the list of members who have or have not read a group message.
// The list of members who have read a group message
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
zim.queryGroupMessageReceiptReadMemberList(message, groupID, config,
new ZIMGroupMessageReceiptMemberListQueriedCallback() {
@Override
public void onGroupMessageReceiptMemberListQueried(String groupID, ArrayList<ZIMGroupMemberInfo> userList,
int nextFlag, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// The corresponding member list is queried.
}
}
});
// The list of members who have not read a group message
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
zim.queryGroupMessageReceiptUnreadMemberList(message, groupID, config,
new ZIMGroupMessageReceiptMemberListQueriedCallback() {
@Override
public void onGroupMessageReceiptMemberListQueried(String groupID, ArrayList<ZIMGroupMemberInfo> userList,
int nextFlag, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// The corresponding member list is queried.
}
}
});
- (void)zim:(ZIM *)zim messageReceiptChanged:(NSArray<ZIMMessageReceiptInfo *> *)infos{
// The other user sets a message as read.
}
- (void)zim:(ZIM *)zim conversationMessageReceiptChanged:(NSArray<ZIMMessageReceiptInfo *> *)infos{
// The other user sets all messages in a conversation as read.
}
NSString *conversationID = @"xxx" ; // The conversation ID.
// User A sends a message that requires a reading receipt. A text one-to-one message is used as an example.
ZIMTextMessage *message = [[ZIMTextMessage alloc] init];
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc]init];
sendConfig.hasReceipt = true; // Set that the messages require a reading receipt.
[self.zim sendMessage:cmdMsg toUserID:toUserID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
// Developers can listen for whether a message is sent successfully through this callback.
if (errorInfo.code == 0) {
// This indicates that the message is sent successfully. receiptStatus of the message is set to PROCESSING. The service layer can display the logic that a message is unread based on this flag.
}
}];
// User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// Set a message as read
NSMutableArray<ZIMMessage *> *messageList = [[NSMutableArray alloc] init];
[[ZIM getInstance] sendMessageReceiptsRead:messageList conversationID:@"conversationID" conversationType:conversationType callback:^(NSString * _Nonnull conversationID, ZIMConversationType conversationType, NSArray<NSNumber *> * _Nonnull errorMessageIDs, ZIMError * _Nonnull errorInfo) {
// Callback for setting a message as read.
}];
// Set a conversation as read
[[ZIM getInstance] sendConversationMessageReceiptRead:@"conversationID" conversationType:conversationType callback:^(NSString * _Nonnull conversationID, ZIMConversationType conversationType, ZIMError * _Nonnull errorInfo) {
// Callback for setting all messages in a conversation as read.
}];
// (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
NSMutableArray<ZIMMessage *> *messageList = [[NSMutableArray alloc] init];
[[ZIM getInstance] queryMessageReceiptsInfoByMessageList:messageList conversationID:conversationID conversationType:conversationType callback:^(NSArray<ZIMMessageReceiptInfo *> * _Nonnull infos, NSArray<NSNumber *> * _Nonnull errorMessageIDs, ZIMError * _Nonnull errorInfo) {
// The status and quantity of this batch of messages are queried, and the corresponding message ID and count are obtained by traversing the information.
}];
// (Optional) Query the list of members who have or have not read a group message.
// The list of members who have read a group message
ZIMGroupMessageReceiptMemberQueryConfig *config = [[ZIMGroupMessageReceiptMemberQueryConfig alloc]init];
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
[[ZIM getInstance] queryGroupMessageReceiptReadMemberListByMessage:message groupID:groupID config:config callback:^(NSString * _Nonnull groupID, NSArray<ZIMGroupMemberInfo *> * _Nonnull userList, unsigned int nextFlag, ZIMError * _Nonnull errorInfo) {
// The corresponding member list is queried.
}];
// The list of members who have not read a group message
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
[[ZIM getInstance] queryGroupMessageReceiptUnreadMemberListByMessage:message groupID:groupID config:config callback:^(NSString * _Nonnull groupID, NSArray<ZIMGroupMemberInfo *> * _Nonnull userList, unsigned int nextFlag, ZIMError * _Nonnull errorInfo) {
// The corresponding member list is queried.
}];
- (void)zim:(ZIM *)zim messageReceiptChanged:(NSArray<ZIMMessageReceiptInfo *> *)infos{
// The other user sets a message as read.
}
- (void)zim:(ZIM *)zim conversationMessageReceiptChanged:(NSArray<ZIMMessageReceiptInfo *> *)infos{
// The other user sets all messages in a conversation as read.
}
NSString *conversationID = @"xxx" ; // The conversation ID.
// User A sends a message that requires a reading receipt. A text one-to-one message is used as an example.
ZIMTextMessage *message = [[ZIMTextMessage alloc] init];
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc]init];
sendConfig.hasReceipt = true; // Set that the messages require a reading receipt.
[self.zim sendMessage:cmdMsg toUserID:toUserID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
// Developers can listen for whether a message is sent successfully through this callback.
if (errorInfo.code == 0) {
// This indicates that the message is sent successfully. receiptStatus of the message is set to PROCESSING. The service layer can display the logic that a message is unread based on this flag.
}
}];
// User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// Set a message as read
NSMutableArray<ZIMMessage *> *messageList = [[NSMutableArray alloc] init];
[[ZIM getInstance] sendMessageReceiptsRead:messageList conversationID:@"conversationID" conversationType:conversationType callback:^(NSString * _Nonnull conversationID, ZIMConversationType conversationType, NSArray<NSNumber *> * _Nonnull errorMessageIDs, ZIMError * _Nonnull errorInfo) {
// Callback for setting a message as read.
}];
// Set a conversation as read
[[ZIM getInstance] sendConversationMessageReceiptRead:@"conversationID" conversationType:conversationType callback:^(NSString * _Nonnull conversationID, ZIMConversationType conversationType, ZIMError * _Nonnull errorInfo) {
// Callback for setting all messages in a conversation as read.
}];
// (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
NSMutableArray<ZIMMessage *> *messageList = [[NSMutableArray alloc] init];
[[ZIM getInstance] queryMessageReceiptsInfoByMessageList:messageList conversationID:conversationID conversationType:conversationType callback:^(NSArray<ZIMMessageReceiptInfo *> * _Nonnull infos, NSArray<NSNumber *> * _Nonnull errorMessageIDs, ZIMError * _Nonnull errorInfo) {
// The status and quantity of this batch of messages are queried, and the corresponding message ID and count are obtained by traversing the information.
}];
// (Optional) Query the list of members who have or have not read a group message.
// The list of members who have read a group message
ZIMGroupMessageReceiptMemberQueryConfig *config = [[ZIMGroupMessageReceiptMemberQueryConfig alloc]init];
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
[[ZIM getInstance] queryGroupMessageReceiptReadMemberListByMessage:message groupID:groupID config:config callback:^(NSString * _Nonnull groupID, NSArray<ZIMGroupMemberInfo *> * _Nonnull userList, unsigned int nextFlag, ZIMError * _Nonnull errorInfo) {
// The corresponding member list is queried.
}];
// The list of members who have not read a group message
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
[[ZIM getInstance] queryGroupMessageReceiptUnreadMemberListByMessage:message groupID:groupID config:config callback:^(NSString * _Nonnull groupID, NSArray<ZIMGroupMemberInfo *> * _Nonnull userList, unsigned int nextFlag, ZIMError * _Nonnull errorInfo) {
// The corresponding member list is queried.
}];
// User A sends a message that requires a reading receipt. A text one-to-one message is used as an example.
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
pushConfig.content = "win_push_content";
pushConfig.payload = "win_push_extended_data";
pushConfig.title = "win_push_title";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
sendConfig.pushConfig = &pushConfig;
sendConfig.hasReceipt = true; // Set that the messages require a reading receipt.
auto smessage = std::make_shared<zim::ZIMTextMessage>("test message");
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
[=](const std::shared_ptr<zim::ZIMMessage> &message) {
// Notification for message being stored in the database
});
zim_->sendMessage(
std::static_pointer_cast<zim::ZIMMessage>(smessage), userID,
zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER, sendConfig, notification,
[=](const std::shared_ptr<zim::ZIMMessage> &cb_message, const zim::ZIMError &errorInfo) {
if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
// This indicates that the message has been successfully sent. The receiptStatus of the message will be PROCESSING, and the business layer can implement logic to display the unread receipt.
}
});
// User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// Set a message as read
std::vector<std::shared_ptr<zim::ZIMMessage>> messages;
messages.emplace_back(message);
zim_->sendMessageReceiptsRead(
messages, conversationID, zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
[=](const std::string &conversationID, zim::ZIMConversationType conversationType,
const std::vector<long long> &errorMessageIDs,
const zim::ZIMError &errorInfo) {
// Callback for setting a message as read.
});
// Set a conversation as read
zim_->sendConversationMessageReceiptRead(
conversationID, zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
[=](const std::string &conversationID, zim::ZIMConversationType conversationType,
const zim::ZIMError &errorInfo) {
// Callback for conversation read receipt. Developers can use this callback to set all messages sent by the other party in this conversation as read.
});
// (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
std::vector<std::shared_ptr<zim::ZIMMessage>> messages;
messages.emplace_back(message);
zim_->queryMessageReceiptsInfo(
messages, conversationID, zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
[=](const std::vector<zim::ZIMMessageReceiptInfo> &infos,
std::vector<long long> errorMessageIDs, const zim::ZIMError &errorInfo) {});
// (Optional) Query the list of members who have or have not read a group message.
// Read user list
zim::ZIMGroupMessageReceiptMemberQueryConfig readMemberQueryConfig;
readMemberQueryConfig.count = 10; // Number of users to query.
readMemberQueryConfig.nextFlag = 0; // Query flag, fill in 0 initially, and fill in the flag returned from the callback later.
zim_->queryGroupMessageReceiptReadMemberList(
message, "group_id", readMemberQueryConfig,
[=](const std::string &groupID, const std::vector<zim::ZIMGroupMemberInfo> &userList,
unsigned int nextFlag, const zim::ZIMError &errorInfo) {
if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
// Query the corresponding member list
}
});
// Unread user list
zim::ZIMGroupMessageReceiptMemberQueryConfig unreadMemberQueryConfig;
unreadMemberQueryConfig.count = 10; // Number of users to query.
unreadMemberQueryConfig.nextFlag = 0; // Query flag, fill in 0 initially, and fill in the flag returned from the callback later.
zim_->queryGroupMessageReceiptUnreadMemberList(
message, "group_id", unreadMemberQueryConfig,
[=](const std::string &groupID, const std::vector<zim::ZIMGroupMemberInfo> &userList,
unsigned int nextFlag, const zim::ZIMError &errorInfo) {
if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
// Query the corresponding member list
}
});
// User A sends a message that requires a reading receipt. A text one-to-one message is used as an example.
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
pushConfig.content = "win_push_content";
pushConfig.payload = "win_push_extended_data";
pushConfig.title = "win_push_title";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
sendConfig.pushConfig = &pushConfig;
sendConfig.hasReceipt = true; // Set that the messages require a reading receipt.
auto smessage = std::make_shared<zim::ZIMTextMessage>("test message");
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
[=](const std::shared_ptr<zim::ZIMMessage> &message) {
// Notification for message being stored in the database
});
zim_->sendMessage(
std::static_pointer_cast<zim::ZIMMessage>(smessage), userID,
zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER, sendConfig, notification,
[=](const std::shared_ptr<zim::ZIMMessage> &cb_message, const zim::ZIMError &errorInfo) {
if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
// This indicates that the message has been successfully sent. The receiptStatus of the message will be PROCESSING, and the business layer can implement logic to display the unread receipt.
}
});
// User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// Set a message as read
std::vector<std::shared_ptr<zim::ZIMMessage>> messages;
messages.emplace_back(message);
zim_->sendMessageReceiptsRead(
messages, conversationID, zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
[=](const std::string &conversationID, zim::ZIMConversationType conversationType,
const std::vector<long long> &errorMessageIDs,
const zim::ZIMError &errorInfo) {
// Callback for setting a message as read.
});
// Set a conversation as read
zim_->sendConversationMessageReceiptRead(
conversationID, zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
[=](const std::string &conversationID, zim::ZIMConversationType conversationType,
const zim::ZIMError &errorInfo) {
// Callback for conversation read receipt. Developers can use this callback to set all messages sent by the other party in this conversation as read.
});
// (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
std::vector<std::shared_ptr<zim::ZIMMessage>> messages;
messages.emplace_back(message);
zim_->queryMessageReceiptsInfo(
messages, conversationID, zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
[=](const std::vector<zim::ZIMMessageReceiptInfo> &infos,
std::vector<long long> errorMessageIDs, const zim::ZIMError &errorInfo) {});
// (Optional) Query the list of members who have or have not read a group message.
// Read user list
zim::ZIMGroupMessageReceiptMemberQueryConfig readMemberQueryConfig;
readMemberQueryConfig.count = 10; // Number of users to query.
readMemberQueryConfig.nextFlag = 0; // Query flag, fill in 0 initially, and fill in the flag returned from the callback later.
zim_->queryGroupMessageReceiptReadMemberList(
message, "group_id", readMemberQueryConfig,
[=](const std::string &groupID, const std::vector<zim::ZIMGroupMemberInfo> &userList,
unsigned int nextFlag, const zim::ZIMError &errorInfo) {
if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
// Query the corresponding member list
}
});
// Unread user list
zim::ZIMGroupMessageReceiptMemberQueryConfig unreadMemberQueryConfig;
unreadMemberQueryConfig.count = 10; // Number of users to query.
unreadMemberQueryConfig.nextFlag = 0; // Query flag, fill in 0 initially, and fill in the flag returned from the callback later.
zim_->queryGroupMessageReceiptUnreadMemberList(
message, "group_id", unreadMemberQueryConfig,
[=](const std::string &groupID, const std::vector<zim::ZIMGroupMemberInfo> &userList,
unsigned int nextFlag, const zim::ZIMError &errorInfo) {
if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
// Query the corresponding member list
}
});
ZIMEventHandler.onMessageReceiptChanged = (zim, infos) {
// The other party has set the message read receipt
= };
ZIMEventHandler.onConversationMessageReceiptChanged = (zim, infos) {
// The other party has set the conversation read receipt
};
// User A sends a message that requires a reading receipt. A text one-to-one message is used as an example.
String conversationID = "xxx" ; // The conversation ID
ZIMTextMessage message = ZIMTextMessage(message: "test");
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
sendConfig.hasReceipt = true;
ZIM
.getInstance()!
.sendMessage(
message, conversationID, ZIMConversationType.peer, sendConfig)
.then((result) {
// This indicates that the message has been successfully sent. The receiptStatus of the message will be PROCESSING, and the business layer can implement logic to display the unread receipt.
})
.catchError((onError) {
});
// User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// Set a message as read
List<ZIMMessage> messages = [];
ZIM
.getInstance()!
.sendMessageReceiptsRead(
messages, conversationID, ZIMConversationType.peer)
.then((result) {
// Callback for setting a message as read.
})
.catchError((onError) {
});
// Set a conversation as read
ZIM
.getInstance()!
.sendConversationMessageReceiptRead(
conversationID, ZIMConversationType.peer)
.then((value) {
// A conversation is read. Developers can listen for this callback to set all messages sent by the sender in this conversation as read.
})
.catchError((onError) {
});
// (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
List<ZIMMessage> messages = [];
ZIM
.getInstance()!
.queryMessageReceiptsInfo(
messages, conversationID, ZIMConversationType.peer)
.then((value) {
// The status and quantity of this batch of messages are queried, and the corresponding message ID and count are obtained by traversing the information.
})
.catchError((onError) {});
// (Optional) Query the list of members who have or have not read a group message.
// The list of members who have read a group message
ZIMGroupMessageReceiptMemberQueryConfig config =
ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
ZIM
.getInstance()!
.queryGroupMessageReceiptReadMemberList(message, groupID, config)
.then((result) {
// The corresponding member list is queried.
})
.catchError((onError) {
});
// The list of members who have not read a group message
ZIMGroupMessageReceiptMemberQueryConfig config = ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
ZIM
.getInstance()!
.queryGroupMessageReceiptUnreadMemberList(message, groupID, config)
.then((result) {
// The corresponding member list is queried.
})
.catchError((onError) {
});
ZIMEventHandler.onMessageReceiptChanged = (zim, infos) {
// The other party has set the message read receipt
= };
ZIMEventHandler.onConversationMessageReceiptChanged = (zim, infos) {
// The other party has set the conversation read receipt
};
// User A sends a message that requires a reading receipt. A text one-to-one message is used as an example.
String conversationID = "xxx" ; // The conversation ID
ZIMTextMessage message = ZIMTextMessage(message: "test");
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
sendConfig.hasReceipt = true;
ZIM
.getInstance()!
.sendMessage(
message, conversationID, ZIMConversationType.peer, sendConfig)
.then((result) {
// This indicates that the message has been successfully sent. The receiptStatus of the message will be PROCESSING, and the business layer can implement logic to display the unread receipt.
})
.catchError((onError) {
});
// User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// Set a message as read
List<ZIMMessage> messages = [];
ZIM
.getInstance()!
.sendMessageReceiptsRead(
messages, conversationID, ZIMConversationType.peer)
.then((result) {
// Callback for setting a message as read.
})
.catchError((onError) {
});
// Set a conversation as read
ZIM
.getInstance()!
.sendConversationMessageReceiptRead(
conversationID, ZIMConversationType.peer)
.then((value) {
// A conversation is read. Developers can listen for this callback to set all messages sent by the sender in this conversation as read.
})
.catchError((onError) {
});
// (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
List<ZIMMessage> messages = [];
ZIM
.getInstance()!
.queryMessageReceiptsInfo(
messages, conversationID, ZIMConversationType.peer)
.then((value) {
// The status and quantity of this batch of messages are queried, and the corresponding message ID and count are obtained by traversing the information.
})
.catchError((onError) {});
// (Optional) Query the list of members who have or have not read a group message.
// The list of members who have read a group message
ZIMGroupMessageReceiptMemberQueryConfig config =
ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
ZIM
.getInstance()!
.queryGroupMessageReceiptReadMemberList(message, groupID, config)
.then((result) {
// The corresponding member list is queried.
})
.catchError((onError) {
});
// The list of members who have not read a group message
ZIMGroupMessageReceiptMemberQueryConfig config = ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in the callback.
config.count = 10; // The user quantity to be queried.
ZIM
.getInstance()!
.queryGroupMessageReceiptUnreadMemberList(message, groupID, config)
.then((result) {
// The corresponding member list is queried.
})
.catchError((onError) {
});
ZIM.GetInstance().onMessageReceiptChanged = (ZIM zim, List<ZIMMessageReceiptInfo> infos) =>
{
// Message receipt status changed
};
ZIM.GetInstance().onConversationMessageReceiptChanged = (ZIM zim, List<ZIMMessageReceiptInfo> infos) =>
{
// Conversation message receipt status changed
};
// User A sends a message with receipt, taking a peer-to-peer text message as an example
string conversationID = "xxx"; // Conversation ID
ZIMTextMessage message = new ZIMTextMessage("test");
ZIMMessageSendConfig sendConfig = new ZIMMessageSendConfig();
sendConfig.hasReceipt = true; // Set the message with receipt
ZIMMessageSendNotification notification = new ZIMMessageSendNotification();
ZIM.GetInstance().SendMessage(message, "conversationID", ZIMConversationType.Peer, sendConfig, notification,
(ZIMMessage message, ZIMError errorInfo) => { });
// User B receives the receipt and marks it as read, choose one of the following interfaces
// Message read
List<ZIMMessage> messages = new List<ZIMMessage>();
messages.Add(message);
ZIM.GetInstance().SendMessageReceiptsRead(messages, "conversationID", ZIMConversationType.Peer, (string conversationID, ZIMConversationType conversationType,
List<long> errorMessageIDs, ZIMError errorInfo) =>
{
// Callback for sending message read
});
// Conversation read
ZIM.GetInstance().SendConversationMessageReceiptRead("conversationID", ZIMConversationType.Peer, (string conversationID, ZIMConversationType conversationType,
ZIMError errorInfo) =>
{
// Callback for sending conversation message read
});
// (Optional) Query the receipt status, unread user count, and read user count for a batch of messages
List<ZIMMessage> queryMessages = new List<ZIMMessage>();
queryMessages.Add(message);
ZIM.GetInstance().QueryMessageReceiptsInfo(queryMessages, "conversationID", ZIMConversationType.Peer, (List<ZIMMessageReceiptInfo> infos, List<long> errorMessageIDs,
ZIMError errorInfo) =>
{ });
// (Optional) Query the list of read group members and unread group members for a specific group message
// List of read users
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The flag for querying, fill in 0 initially, and then fill in the flag returned from the callback.
config.count = 10; // The number of users to query.
ZIM.GetInstance().QueryGroupMessageReceiptReadMemberList(message, "groupID", config, (string groupID, List<ZIMGroupMemberInfo> userList,
uint nextFlag, ZIMError errorInfo) =>
{ });
// 6.2 List of unread users
ZIMGroupMessageReceiptMemberQueryConfig groupMessageReceiptMemberQueryConfig = new ZIMGroupMessageReceiptMemberQueryConfig();
groupMessageReceiptMemberQueryConfig.nextFlag = 0; // The flag for querying, fill in 0 initially, and then fill in the flag returned from the callback.
groupMessageReceiptMemberQueryConfig.count = 10; // The number of users to query.
ZIM.GetInstance().QueryGroupMessageReceiptUnreadMemberList(message, "groupID", groupMessageReceiptMemberQueryConfig, (string groupID, List<ZIMGroupMemberInfo> userList,
uint nextFlag, ZIMError errorInfo) => { });
ZIM.GetInstance().onMessageReceiptChanged = (ZIM zim, List<ZIMMessageReceiptInfo> infos) =>
{
// Message receipt status changed
};
ZIM.GetInstance().onConversationMessageReceiptChanged = (ZIM zim, List<ZIMMessageReceiptInfo> infos) =>
{
// Conversation message receipt status changed
};
// User A sends a message with receipt, taking a peer-to-peer text message as an example
string conversationID = "xxx"; // Conversation ID
ZIMTextMessage message = new ZIMTextMessage("test");
ZIMMessageSendConfig sendConfig = new ZIMMessageSendConfig();
sendConfig.hasReceipt = true; // Set the message with receipt
ZIMMessageSendNotification notification = new ZIMMessageSendNotification();
ZIM.GetInstance().SendMessage(message, "conversationID", ZIMConversationType.Peer, sendConfig, notification,
(ZIMMessage message, ZIMError errorInfo) => { });
// User B receives the receipt and marks it as read, choose one of the following interfaces
// Message read
List<ZIMMessage> messages = new List<ZIMMessage>();
messages.Add(message);
ZIM.GetInstance().SendMessageReceiptsRead(messages, "conversationID", ZIMConversationType.Peer, (string conversationID, ZIMConversationType conversationType,
List<long> errorMessageIDs, ZIMError errorInfo) =>
{
// Callback for sending message read
});
// Conversation read
ZIM.GetInstance().SendConversationMessageReceiptRead("conversationID", ZIMConversationType.Peer, (string conversationID, ZIMConversationType conversationType,
ZIMError errorInfo) =>
{
// Callback for sending conversation message read
});
// (Optional) Query the receipt status, unread user count, and read user count for a batch of messages
List<ZIMMessage> queryMessages = new List<ZIMMessage>();
queryMessages.Add(message);
ZIM.GetInstance().QueryMessageReceiptsInfo(queryMessages, "conversationID", ZIMConversationType.Peer, (List<ZIMMessageReceiptInfo> infos, List<long> errorMessageIDs,
ZIMError errorInfo) =>
{ });
// (Optional) Query the list of read group members and unread group members for a specific group message
// List of read users
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // The flag for querying, fill in 0 initially, and then fill in the flag returned from the callback.
config.count = 10; // The number of users to query.
ZIM.GetInstance().QueryGroupMessageReceiptReadMemberList(message, "groupID", config, (string groupID, List<ZIMGroupMemberInfo> userList,
uint nextFlag, ZIMError errorInfo) =>
{ });
// 6.2 List of unread users
ZIMGroupMessageReceiptMemberQueryConfig groupMessageReceiptMemberQueryConfig = new ZIMGroupMessageReceiptMemberQueryConfig();
groupMessageReceiptMemberQueryConfig.nextFlag = 0; // The flag for querying, fill in 0 initially, and then fill in the flag returned from the callback.
groupMessageReceiptMemberQueryConfig.count = 10; // The number of users to query.
ZIM.GetInstance().QueryGroupMessageReceiptUnreadMemberList(message, "groupID", groupMessageReceiptMemberQueryConfig, (string groupID, List<ZIMGroupMemberInfo> userList,
uint nextFlag, ZIMError errorInfo) => { });
// 1. Register a callback.
// The other user sets a message as read.
zim.on('messageReceiptChanged', function (zim, { infos }) {
console.log('messageReceiptChanged', infos);
});
// The other user sets all messages in a conversation as read.
zim.on('conversationMessageReceiptChanged', function (zim, { infos }) {
console.log('conversationMessageReceiptChanged', infos);
});
var userID_A = "xxxx" ; // The ID of user A.
var userID_B = "xxxx" ; // The ID of user B.
// 2. User A sends a message that requires a reading receipt to user B. A text one-to-one message is used as an example.
const userID_A = "xxxx" ; // ID of UserA
const userID_B = "xxxx" ; // ID of UserB
const messageObj: ZIMMessage = { type: 1, message: 'text receipt message' }
const config: ZIMMessageSendConfig = {
priority: 1, // Message priority. Valid values: 1: Low (default), 2: Medium, 3: High
hasReceipt: true // Set that the messages require a reading receipt.
}
const notification: ZIMMessageSendNotification = {
onMessageAttached: function(message) {
// todo: Loading
}
}
zim.sendMessage(messageObj, userID_B, 0, config, notification)
.then(function ({ message }) {
// Sent successfully.
})
.catch(function (err) {
// Sending failed.
});
// 3. User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// 3.1 Set a message as read
const messages: ZIMMessage[] = []; // Queried from queryHistoryMessage or received from peerMessageReceived
zim.sendMessageReceiptsRead(messages, userID_A, 0)
.then(function ({ conversationID, conversationType, errorMessageIDs }) {
// The operation is successful. Messages that failed to be set as read are returned through errorMessageIDs.
})
.catch(function (err) {
// The operation fails.
});
// 3.2 Set a conversation as read
zim.sendConversationMessageReceiptRead(userID_A, 0)
.then(function ({ conversationID, conversationType }) {
// The operation is successful. User B can set all messages sent from user A in this conversation as read.
})
.catch(function (err) {
// The operation fails.
});
// 4. (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
const messages: ZIMMessage[] = []; // Queried from queryHistoryMessage
zim.queryMessageReceiptsInfo(messages, userID_B, 0)
.then(function ({ infos, errorMessageIDs }) {
// The operation is successful. Messages that failed to be queried are returned through errorMessageIDs.
})
.catch(function (err) {
// The operation fails.
});
// 5. (Optional) Query the list of members who have or have not read a group message.
const groupMsgObj: ZIMMessage = {} // Queried from queryHistoryMessage
const queryConfig: ZIMGroupMessageReceiptMemberQueryConfig = {
count: 10, // The user quantity to be queried.
nextFlag: 0 // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in Promise.
}
// 5.1 The list of members who have read a group message
zim.queryGroupMessageReceiptReadMemberList(groupMsgObj, groupMsgObj.conversationID, queryConfig)
.then(function ({ nextFlag, userList, groupID }) {
// The operation is successful.
})
.catch(function (err) {
// The operation fails.
});
// 5.2 The list of members who have not read a group message
zim.queryGroupMessageReceiptUnreadMemberList(groupMsgObj, groupMsgObj.conversationID, queryConfig)
.then(function ({ nextFlag, userList, groupID }) {
// The operation is successful.
})
.catch(function (err) {
// The operation fails.
});
// 1. Register a callback.
// The other user sets a message as read.
zim.on('messageReceiptChanged', function (zim, { infos }) {
console.log('messageReceiptChanged', infos);
});
// The other user sets all messages in a conversation as read.
zim.on('conversationMessageReceiptChanged', function (zim, { infos }) {
console.log('conversationMessageReceiptChanged', infos);
});
var userID_A = "xxxx" ; // The ID of user A.
var userID_B = "xxxx" ; // The ID of user B.
// 2. User A sends a message that requires a reading receipt to user B. A text one-to-one message is used as an example.
const userID_A = "xxxx" ; // ID of UserA
const userID_B = "xxxx" ; // ID of UserB
const messageObj: ZIMMessage = { type: 1, message: 'text receipt message' }
const config: ZIMMessageSendConfig = {
priority: 1, // Message priority. Valid values: 1: Low (default), 2: Medium, 3: High
hasReceipt: true // Set that the messages require a reading receipt.
}
const notification: ZIMMessageSendNotification = {
onMessageAttached: function(message) {
// todo: Loading
}
}
zim.sendMessage(messageObj, userID_B, 0, config, notification)
.then(function ({ message }) {
// Sent successfully.
})
.catch(function (err) {
// Sending failed.
});
// 3. User B receives the message that requires a reading receipt and sets the message as read by calling any of the following APIs.
// 3.1 Set a message as read
const messages: ZIMMessage[] = []; // Queried from queryHistoryMessage or received from peerMessageReceived
zim.sendMessageReceiptsRead(messages, userID_A, 0)
.then(function ({ conversationID, conversationType, errorMessageIDs }) {
// The operation is successful. Messages that failed to be set as read are returned through errorMessageIDs.
})
.catch(function (err) {
// The operation fails.
});
// 3.2 Set a conversation as read
zim.sendConversationMessageReceiptRead(userID_A, 0)
.then(function ({ conversationID, conversationType }) {
// The operation is successful. User B can set all messages sent from user A in this conversation as read.
})
.catch(function (err) {
// The operation fails.
});
// 4. (Optional) Batch query the message receipt status, number of users who have read the message, and number of users who have not read the message.
const messages: ZIMMessage[] = []; // Queried from queryHistoryMessage
zim.queryMessageReceiptsInfo(messages, userID_B, 0)
.then(function ({ infos, errorMessageIDs }) {
// The operation is successful. Messages that failed to be queried are returned through errorMessageIDs.
})
.catch(function (err) {
// The operation fails.
});
// 5. (Optional) Query the list of members who have or have not read a group message.
const groupMsgObj: ZIMMessage = {} // Queried from queryHistoryMessage
const queryConfig: ZIMGroupMessageReceiptMemberQueryConfig = {
count: 10, // The user quantity to be queried.
nextFlag: 0 // The query flag. It is set to 0 in the first query. In subsequent queries, it is set to the flag returned in Promise.
}
// 5.1 The list of members who have read a group message
zim.queryGroupMessageReceiptReadMemberList(groupMsgObj, groupMsgObj.conversationID, queryConfig)
.then(function ({ nextFlag, userList, groupID }) {
// The operation is successful.
})
.catch(function (err) {
// The operation fails.
});
// 5.2 The list of members who have not read a group message
zim.queryGroupMessageReceiptUnreadMemberList(groupMsgObj, groupMsgObj.conversationID, queryConfig)
.then(function ({ nextFlag, userList, groupID }) {
// The operation is successful.
})
.catch(function (err) {
// The operation fails.
});
Get the delivered status of receipt messages
After the sender sends a receipt message, if the receiver's device has received the message, the receipt status of the message will change to delivered. Developers can listen for receipt status changes through the onMessageReceiptChanged callback.
Note
Since ZIM 3.1.0, a "delivered" status has been added between "processing" and "completed" for message receipts, indicating that the receipt message has been delivered. To use this feature, contact ZEGO technical support.
The receipt status of messages in the following scenarios will change to "delivered" and trigger the onMessageReceiptChanged callback.
One-to-one chat:
After the receiver receives the message online, the SDK automatically confirms delivery.
After the receiver receives an offline push and calls the server API to confirm delivery.
When there is no offline push, the SDK automatically confirms delivery after the receiver comes online and pulls the message.
Group chat:
When all group members have received the message and some members have not yet read it, the receipt status transitions to "delivered".
Note
Offline push delivery does not mean the message itself has been delivered. Only when the ZIM message actually reaches the receiver or is confirmed through the server API will the status transition to "delivered".
If you need the message receipt status on the sender side to change to "delivered" after the message receiver receives an offline push (iOS can enable push interception, Android FCM can use DataMessage push message type, domestic Android manufacturers currently do not support this), you can call Server API - Set delivered receipts for group messages after receiving the push to confirm.
Query the member list of group message receipt status
Call queryGroupMessageReceiptMemberList to query the member list of group messages with read, unread (undelivered), or delivered status.
Parameter description:
Parameter
Description
message
The message with receipt to query.
groupID
The group ID of the corresponding group conversation.
count
The number of users to query, up to 100 per query.
config
Query configuration: ZIMGroupMessageReceiptMemberQueryConfig, which can configure the query start marker nextFlag and the query item (read, unread [undelivered], delivered).
callback
Query result callback: ZIMGroupMessageReceiptMemberListQueriedCallback, where userList is the group member list matching the query conditions, and nextFlag is the start marker for the next query (when nextFlag is 0, the query is complete).
Parameter
Description
message
The message with receipt to query.
groupID
The group ID of the corresponding group conversation.
count
The number of users to query, up to 100 per query.
config
Query configuration: ZIMGroupMessageReceiptMemberQueryConfig, which can configure the query start marker nextFlag and the query item (read, unread [undelivered], delivered).
Query result, where userList is the group member list matching the query conditions, and nextFlag is the start marker for the next query (when nextFlag is 0, the query is complete).
Sample code:
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // Query start marker, initially set to 0, then set to the nextFlag returned from the callback.
config.count = 10; // Number of users to query, up to 100 per query.
zim.queryGroupMessageReceiptMemberList(
message, groupID, count, config,
new ZIMGroupMessageReceiptMemberListQueriedCallback() {
@Override
public void onGroupMessageReceiptMemberListQueried(
String groupID, ArrayList<ZIMGroupMemberInfo> userList,
int nextFlag, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// Query successful, userList is the group member list matching the query conditions
// nextFlag is the start marker for the next query, nextFlag is 0 when the query is complete
} else {
// Query failed
}
}
});
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // Query start marker, initially set to 0, then set to the nextFlag returned from the callback.
config.count = 10; // Number of users to query, up to 100 per query.
zim.queryGroupMessageReceiptMemberList(
message, groupID, count, config,
new ZIMGroupMessageReceiptMemberListQueriedCallback() {
@Override
public void onGroupMessageReceiptMemberListQueried(
String groupID, ArrayList<ZIMGroupMemberInfo> userList,
int nextFlag, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
// Query successful, userList is the group member list matching the query conditions
// nextFlag is the start marker for the next query, nextFlag is 0 when the query is complete
} else {
// Query failed
}
}
});
ZIMGroupMessageReceiptMemberQueryConfig *config = [[ZIMGroupMessageReceiptMemberQueryConfig alloc] init];
config.nextFlag = 0; // Query start marker, initially set to 0, then set to the nextFlag returned from the callback.
config.count = 10; // Number of users to query, up to 100 per query.
[zim queryGroupMessageReceiptMemberListByMessage:message
groupID:groupID
count:count
config:config
callback:^(NSString *_Nonnull groupID, NSArray<ZIMGroupMemberInfo *> *_Nonnull userList,
unsigned int nextFlag, ZIMError *_Nonnull errorInfo) {
if (errorInfo.code == 0) {
// Query successful, userList is the group member list matching the query conditions
// nextFlag is the start marker for the next query, nextFlag is 0 when the query is complete
} else {
// Query failed
}
}];
ZIMGroupMessageReceiptMemberQueryConfig *config = [[ZIMGroupMessageReceiptMemberQueryConfig alloc] init];
config.nextFlag = 0; // Query start marker, initially set to 0, then set to the nextFlag returned from the callback.
config.count = 10; // Number of users to query, up to 100 per query.
[zim queryGroupMessageReceiptMemberListByMessage:message
groupID:groupID
count:count
config:config
callback:^(NSString *_Nonnull groupID, NSArray<ZIMGroupMemberInfo *> *_Nonnull userList,
unsigned int nextFlag, ZIMError *_Nonnull errorInfo) {
if (errorInfo.code == 0) {
// Query successful, userList is the group member list matching the query conditions
// nextFlag is the start marker for the next query, nextFlag is 0 when the query is complete
} else {
// Query failed
}
}];
zim::ZIMGroupMessageReceiptMemberQueryConfig config;
config.nextFlag = 0; // Query start marker, initially set to 0, then set to the nextFlag returned from the callback.
config.count = 10; // Number of users to query, up to 100 per query.
zim->queryGroupMessageReceiptMemberList(
message, groupID, count, config,
[=](const std::string &groupID, const std::vector<ZIMGroupMemberInfo> &userList,
unsigned int nextFlag, const ZIMError &errorInfo) {
if (errorInfo.code == 0) {
// Query successful, userList is the group member list matching the query conditions
// nextFlag is the start marker for the next query, nextFlag is 0 when the query is complete
} else {
// Query failed
}
});
zim::ZIMGroupMessageReceiptMemberQueryConfig config;
config.nextFlag = 0; // Query start marker, initially set to 0, then set to the nextFlag returned from the callback.
config.count = 10; // Number of users to query, up to 100 per query.
zim->queryGroupMessageReceiptMemberList(
message, groupID, count, config,
[=](const std::string &groupID, const std::vector<ZIMGroupMemberInfo> &userList,
unsigned int nextFlag, const ZIMError &errorInfo) {
if (errorInfo.code == 0) {
// Query successful, userList is the group member list matching the query conditions
// nextFlag is the start marker for the next query, nextFlag is 0 when the query is complete
} else {
// Query failed
}
});
ZIMGroupMessageReceiptMemberQueryConfig config = ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // Query start marker, initially set to 0, then set to the nextFlag returned from the callback.
config.count = 10; // Number of users to query, up to 100 per query.
ZIM.getInstance()!
.queryGroupMessageReceiptMemberList(message, groupID, count, config)
.then((result) {
// Query successful, result.userList is the group member list matching the query conditions
// result.nextFlag is the start marker for the next query, nextFlag is 0 when the query is complete
})
.catchError((onError) {
// Query failed
});
ZIMGroupMessageReceiptMemberQueryConfig config = ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0; // Query start marker, initially set to 0, then set to the nextFlag returned from the callback.
config.count = 10; // Number of users to query, up to 100 per query.
ZIM.getInstance()!
.queryGroupMessageReceiptMemberList(message, groupID, count, config)
.then((result) {
// Query successful, result.userList is the group member list matching the query conditions
// result.nextFlag is the start marker for the next query, nextFlag is 0 when the query is complete
})
.catchError((onError) {
// Query failed
});
// 1. Construct query configuration
const config = new ZIMGroupMessageReceiptMemberListQueryConfig();
config.nextFlag = 0; // Initially set to 0, then set to the nextFlag returned from the result
config.filterType = ZIMMessageReceiptFilterType.Read; // Default value, query read members
// 2. Call the API
zim.queryGroupMessageReceiptMemberList(message, groupID, 10, config)
.then((result) => {
// Query successful
// result.userList — List<ZIMGroupMemberInfo>, group member list matching the query conditions
// result.nextFlag — Start marker for the next query, 0 means the query is complete
// result.groupID — Group ID
// result.errorInfo — ZIMError, code 0 means success
})
.catch((error) => {
// Query failed
});
// 1. Construct query configuration
const config = new ZIMGroupMessageReceiptMemberListQueryConfig();
config.nextFlag = 0; // Initially set to 0, then set to the nextFlag returned from the result
config.filterType = ZIMMessageReceiptFilterType.Read; // Default value, query read members
// 2. Call the API
zim.queryGroupMessageReceiptMemberList(message, groupID, 10, config)
.then((result) => {
// Query successful
// result.userList — List<ZIMGroupMemberInfo>, group member list matching the query conditions
// result.nextFlag — Start marker for the next query, 0 means the query is complete
// result.groupID — Group ID
// result.errorInfo — ZIMError, code 0 means success
})
.catch((error) => {
// Query failed
});