logo
In-app Chat
SDK Error Codes
Powered Byspreading
On this page

Reply to a message


Introduction

The ZIM SDK supports the functionality of replying to messages within a session, which means quoting a received message to provide a targeted response and forming a tree-like structure of message replies starting from that message. With this feature, users can ask questions, provide feedback, or provide additional background information in response to a specific message.

Concepts

This feature involves the following concepts:

  • Root message: The starting point of a reply tree, usually the initial message of a specific discussion.
  • Child message: A direct or indirect reply to a certain message.
  • Source message: The previous level message of a reply.
  • Reply count: The number of replies received by the root message.

Using messages A, B, and C in group chat as examples:

  1. Message B replies to message A:
    • Message A is the root message.
    • Message A is the source message of message B.
    • Message B is a child message of message A.
  2. Message C replies to message B:
    • Message B is the source message of message C.
    • Message C is a child message of message B.
  3. Both message B and message C are child messages of message A.
  4. The reply count of message A is 2. Message B does not have a reply count.

Reply to a message

After logging in to ZIM, users can listen to the peerMessageReceived and groupMessageReceived callback to receive new messages from one-on-one and group conversations, or call the queryHistoryMessageByConversationID interface to fetch historical messages.

At this point, users can choose a message to reply to by using that message as the toOriginalMessage parameter and constructing a new message as the message parameter. Then, call the replyMessage interface.

Note

Only the following types are supported for the toOriginalMessage and message parameters:

In addition to the required parameters mentioned above, you can also construct a notification object based on your business needs and listen to the following callbacks:

  • onMessageAttached: This callback is triggered before sending the reply, allowing you to obtain a temporary ZIMMessage object. You can use this object to add some logic, such as displaying UI in advance.
  • onMediaUploadingProgress: This callback provides updates on the progress of file uploads when sending messages with rich media.

The sending result will be returned through the ZIMMessageSentCallback.

Untitled
// Reply content
ZIMTextMessage *textMessage = [[ZIMTextMessage alloc] init];
textMessage.message = @"Message content";

ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
// Set message priority
config.priority = ZIMMessagePriorityLow;

ZIMMessageSendNotification *notification = [[ZIMMessageSendNotification alloc] init];
notification.onMessageAttached = ^(ZIMMessage * _Nonnull message) {
    // Callback before sending, where you can get a temporary object that is the same as the zimMessage object created by you. You can use this feature to add some business logic, such as displaying UI in advance.
};
notification.onMediaUploadingProgress = ^(ZIMMediaMessage * _Nonnull message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
    // If the reply message is a media message, you can listen to the upload progress of the media attachment.
};

// Reply to a message, where the toOriginalMessage parameter refers to the source message obtained through queryHistoryMessageByConversationID, peerMessageReceived, or receiveGroupMessage.
[[ZIM getInstance] replyMessage:textMessage toOriginalMessage:toOriginalMessage config:config notification:notification callback:^(ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo) {
    // You can use this callback to listen for whether the message was sent successfully.
}];
1
Copied!

Determine if a message is a reply to another message

When receiving new messages in one-on-one and group conversations through the peerMessageReceived and groupMessageReceived callbacks, you need to determine if the message has repliedInfo (basic information of the source message):

  • If it exists, it means that this message is a reply to another message.
  • If it doesn't exist, it means that this message is an independent message.

When you have the repliedInfo, you can use it to display the sender, sending time, and message content of the source message.

Untitled
// Register ZIMEventHander callback
[zim setEventHandler:self];

// Callback for receiving one-on-one messages
- (void)zim:(ZIM *)zim
    peerMessageReceived:(NSArray<ZIMMessage *> *)messageList
                   info:(ZIMMessageReceivedInfo *)info
             fromUserID:(NSString *)fromUserID {
     for(ZIMMessage *message in messageList) {
         if(message.repliedInfo) {
           // Basic information of the source message referenced by this reply message, used to display the sender, sending time, and message content of the source message.
        }
    }
}   

// Callback for receiving group messages
- (void)zim:(ZIM *)zim
    groupMessageReceived:(NSArray<ZIMMessage *> *)messageList
                    info:(ZIMMessageReceivedInfo *)info
             fromGroupID:(NSString *)fromGroupID {
    for(ZIMMessage *message in messageList) {
         if(message.repliedInfo) {
           // Basic information of the source message referenced by this reply message, used to display the sender, sending time, and message content of the source message.
        }
}  
1
Copied!

Get the number of replies to a root message

ZIM supports actively or passively obtaining the number of replies to a root message.

Active retrieval

To actively retrieve the number of replies to a root message, you can directly use ZIMMessage > rootRepliedCount to get it.

Passive retrieval

To get real-time updates on how many replies a root message has received, you can listen for the messageRepliedCountChanged event.

Untitled
// Register ZIMEventHander callback
[zim setEventHandler:self];

// Listen for changes in the number of replies to a root message
// Event trigger: When a new message replied to another message successfully, the number of replies to the root message of its reply tree will increase by 1
- (void)zim:(ZIM *)zim messageRepliedCountChanged:(NSArray<ZIMMessageRootRepliedCountInfo *> *)infos {
    // Update the rootRepliedCount of the corresponding messageID in the conversation
}
1
Copied!

Listen for the deletion or recall of the source message

Listen for the messageRepliedInfoChanged callback to get the list of child messages of a message when it is deleted or recalled. You can display relevant prompts on the UI of the corresponding child messages.

Note

Even if the source message is deleted by the user on a device, causing the repliedInfo.state (the state of the source message) of its child message to be ZIMMessageRepliedInfoStateDeleted, you can still get the brief content of the source message in the repliedInfo.messageInfo of the child message. Therefore, you can choose whether to display the content of the source message on that device as needed.

Untitled
// Register ZIMEventHander callback
[zim setEventHandler:self];

// Listen for changes in the source message of a reply message
// Event trigger: When the source message is "deleted" or "recalled", the repliedInfo property of the reply referencing it will change
- (void)zim:(ZIM *)zim messageRepliedInfoChanged:(NSArray<ZIMMessage *> *)messageList {
    for(ZIMMessage *message in messageList) {
        if(message.repliedInfo.state == ZIMMessageRepliedInfoStateDeleted) {
            // The source message referenced by this reply message has been deleted, you can display "Message deleted" at this time
        } else if (message.repliedInfo.messageInfo.type == ZIMMessageTypeRevoke) {
            // The source message referenced by this reply message has been recalled, you can display "Message recalled" at this time
        }
    }
}
1
Copied!

Query the reply list

Call queryMessageRepliedListByMessage and pass in the root message or any reply to view the complete list of replies and get the complete message list related to the replies.

The results returned by this interface will distinguish between the root message (rootRepliedInfo) and the reply list (messageList), and the reply list will be sorted in chronological order based on the sending time of the replies.

Untitled
ZIMMessageRepliedListQueryConfig *config = [[ZIMMessageRepliedListQueryConfig alloc] init];
config.count = 10; // The number of queries, please do not exceed 100
config.nextFlag = 0; // Pagination flag, fill in 0 for the first query, and subsequent queries will be based on the nextFlag returned by the query result

// replyMessage can be a root message or any reply, generally obtained through the queryHistoryMessage interface or peerMessageReceived and receiveGroupMessage
[[ZIM getInstance] queryMessageRepliedListByMessage:replyMessage config:config callback:^(NSArray<ZIMMessage *> * _Nonnull messageList, long long nextFlag, ZIMMessageRootRepliedInfo * _Nonnull rootRepliedInfo, ZIMError * _Nonnull errorInfo){
        if(errorInfo.code == ZIMErrorCodeSuccess) {
            // Query successful
            // If nextFlag is not 0, it means there is more data to be queried
            // rootRepliedInfo is the information of the root message
            // messageList represents the reply list to the root message
        } else {
            // Query failed
        }
}];
1
Copied!
Note
  • When querying the reply list, no matter the message passed is the root message or not, as long as the nextFlag is set to 0, it means querying in ascending order of message sending time starting from the root message.
  • Since the message in rootRepliedInfo is a nullable object, when state is ZIMMessageRepliedInfoState.ZIMMessageRepliedInfoStateDeleted, it means the root message has been deleted. At this time, developers should prompt "The root message has been deleted" on the UI. When state is ZIMMessageRepliedInfoState.ZIMMessageRepliedInfoStateNotFound, it means that the root message cannot be found anymore. The possible reasons are that the message exceeded the server storage time, or the group users query the reply list after joining the group but the root message was sent before they joined the group, so the message may not be able to be required anymore. At this time, developers should prompt "The root message cannot be located" or other informative statements on the UI.

View the context of the source message

Since the repliedInfo of a child message (i.e., a reply message) only contains basic source message data that can be used for UI display, users may need to go to the original location of the source message to read other messages near the source message.

Therefore, to implement this scenario, you need to use the repliedInfo.messageInfo property of the child message (which is the sequence number of the source message in the conversation).

Note

The repliedInfo.messageInfo property of a child message (which is the sequence number of the source message in the conversation) corresponds to the messageSeq of the source message.

Depending on whether the source message and its surrounding messages are cached in the application's memory, ZIM provides two options.

Both the source message and its surrounding messages are cached in the application's memory

When a source message and its surrounding messages are saved in your application's memory (for example, by calling queryHistoryMessageByConversationID to retrieve and cache the conversation's message history), you can search the messageSeq of the source message in the memory and implement the business logic to go to the original location of the source message to view the context.

The source message or its surrounding messages are not cached in the application's memory

When the source message or its surrounding messages are not cached in the application's memory, if another user replies to the source message in the conversation, you can:

  1. From the repliedInfo.messageInfo of the reply, get the messageSeq of the source message. Pass it as a parameter to call the queryMessagesByMessageSeqs interface to get the complete ZIMMessage object of the source message.
Untitled
// messageSeq is the sequence number of the source message in the conversation
NSArray *messageSeqs = @[@(messageSeq)];
[[ZIM getInstance] queryMessagesByMessageSeqs:messageSeqs conversationID:@"YOUR_CONVERSATION_ID" conversationType:conversationType callback:^(NSString *conversationID, ZIMConversationType conversationType, NSArray<ZIMMessage *> *messageList, ZIMError *errorInfo) {
    if(error.code == ZIMErrorCodeSuccess) {
        // Query successful
    } else {
        // Query failed
    }
}];
1
Copied!
  1. Pass the source message object as the nextMessage parameter to queryHistoryMessageByConversationID, so that you can use the source message as an anchor point to retrieve messages from the messages forward or backward.
Untitled
// This example demonstrates querying forward from the source message
ZIMMessageQueryConfig *config = [[ZIMMessageQueryConfig alloc] init];
// originalMessage is the source message obtained through queryMessagesByMessageSeqs
config.nextMessage = originalMessage;
config.count = 20;
config.reverse = NO;
[[ZIM getInstance] queryHistoryMessageByConversationID:@"YOUR_CONVERSATION_ID" conversationType:conversationType config:config callback:^(NSString *conversationID, ZIMConversationType conversationType, NSArray<ZIMMessage *> *messageList, ZIMError *errorInfo) {
    if(error.code == ZIMErrorCodeSuccess) {
        // Query successful
    } else {
        // Query failed
    }
}];
1
Copied!

Previous

Geofencing

Next

Call invitation (signaling)