Message Sending and Receiving (iOS)

Last updated: 2021-10-19 15:53:50

    Message Classification

    IM messages are classified by message destination into two types: one-to-one messages (also called C2C messages) and group messages.

    Message Type API Keyword Description
    One-to-one message C2CMessage Also called C2C message. When sending a one-to-one message, you must specify the UserID of the message recipient, and only the recipient can receive this message.
    Group message GroupMessage When sending a group message, you must specify the groupID of the target group, and all users in this group can receive this message.

    IM messages can also be classified by content into text messages, custom (signaling) messages, image messages, video messages, voice messages, file messages, location messages, combined messages, and group tips.

    Message Type API Keyword Description
    Text message TextElem It refers to a common text message. Sensitive words of text messages will be filtered out in the IM service. If a message containing sensitive words is sent, the 80001 error code is returned.
    Custom message CustomElem It is a section of the binary buffer, which is often used to transfer custom signaling in your application. Its content is not filtered for sensitive words.
    Image message ImageElem When the IM SDK sends an original image, it automatically generates two images in different sizes. The three images are called the original image, large image, and thumbnail.
    Video message VideoElem A video message contains a video file and an image.
    Voice message SoundElem Supports displaying a red dot upon playback of the voice message.
    File message FileElem A file message cannot exceed 100 MB.
    Location message LocationElem A location message contains three fields: location description, longitude, and latitude.
    Combined message MergerElem Up to 300 messages can be combined.
    Group tip GroupTipsElem A group tip is often used to carry a system notification in a group, for example, a notification indicating that a member joins or leaves the group, the group description is modified, or the profile of a group member is changed.

    Sending and Receiving Simple Messages

    V2TIMManager.h provides a set of simple APIs for sending and receiving messages. Although these APIs can be used to send or receive text messages and custom (signaling) messages, they are easy to use and only a few minutes are needed to complete interfacing.

    Sending text and signaling messages (simplified APIs)

    To send text messages, call sendC2CTextMessage or sendGroupTextMessage. Text messages will be filtered by IM for sensitive words. If a message containing sensitive words is sent, the 80001 error code is returned.
    To send one-to-one custom (signaling) messages, call sendC2CCustomMessage or sendGroupCustomMessage. A custom message is essentially a section of the binary buffer, and is often used to transfer custom signaling in your application. Its content is not filtered for sensitive words.

    Receiving text and signaling messages (simplified APIs)

    To listen to simple text and signaling messages, call addSimpleMsgListener. To listen to image, video, and voice messages, call addAdvancedMsgListener defined in V2TIMManager + Message.h.

    Note:

    Do not use addSimpleMsgListener together with addAdvancedMsgListener; otherwise, logic bugs may occur.

    Typical example: sending and receiving on-screen comments in an audio-video group

    In the live streaming scenario, it is a common way of communication to send or receive on-screen comments in an audio-video group. This can be easily implemented through the simple message APIs.

    1. The anchor can call createGroup to create an audio-video group (AVChatRoom) and record the group ID in the list of rooms in "Broadcasting" state.
    2. A viewer can select an anchor that he/she likes, and call joinGroup to join the audio-video group created by this anchor.
    3. The message sender can call sendGroupTextMessage to send a group text message as an on-screen comment.
    4. The message recipient can call addSimpleMsgListener to register a simple message listener, and use the listener callback function onRecvGroupTextMessage to obtain text messages.

    "FlyHeart" is an instruction. To configure the "FlyHeart" feature for a live room, perform the steps below:

    1. Define a custom message type, for example, a JSON string { "command": "favor", "value": 101 }.
    2. Call sendGroupCustomMessage to send a message, and call onRecvGroupCustomMessage to receive the message.

    Sending and Receiving Rich Media Messages

    Image, video, voice, file, and location messages are called rich media messages. Compared with simple messages, it is more complex to send or receive rich media messages.

    • Before sending a rich media message, use the create function to create a V2TIMMessage object. Then, call the corresponding send API to send this message.
    • When receiving the rich media message, check elemType and perform secondary parsing on Elem obtained based on elemType.

    Sending rich media messages

    The following takes an image message as an example to describe the process of sending a rich media message.

    1. The sender calls createImageMessage to create an image message and obtain the V2TIMMessage message object.
    2. The sender calls sendMessage to send the created message object.

    Receiving rich media messages

    1. The recipient calls addAdvancedMsgListener to set the advanced message listener.
    2. The recipient obtains theV2TIMMessage image message through the onRecvNewMessage listener callback.
    3. The recipient parses elemType in V2TIMMessage, and performs secondary parsing based on the message type to obtain the content of Elem in the message.

    Typical example: sending and receiving image messages

    The sender creates and sends an image message.

    // Obtain the local image path
    NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"png"];
    // Create an image message
    V2TIMMessage *msg = [[V2TIMManager sharedInstance] createImageMessage:imagePath];
    // Send the image message
    [[V2TIMManager sharedInstance] sendMessage:msg receiver:@"userA" groupID:nil 
    priority:V2TIM_PRIORITY_DEFAULT 
    onlineUserOnly:NO offlinePushInfo:nil progress:^(uint32_t progress) {
      // Image upload progress (0-100)
    } succ:^{
      // The image message is successfully sent
    } fail:^(int code, NSString *msg) {
      // The image message fails to be sent
    }];
    

    The recipient identifies the image message, and parses the message to obtain the original image, large image, and thumbnail contained in the message.

    - (void)onRecvNewMessage:(V2TIMMessage *)msg {
     if (msg.elemType == V2TIM_ELEM_TYPE_IMAGE) {
       V2TIMImageElem *imageElem = msg.imageElem;
       // An image message contains an image in three different sizes: original image, large image, and thumbnail. (The SDK automatically generates a large image and a thumbnail.)
       // A large image is an image obtained after the original image is proportionally compressed. After the compression, the smaller one of the height and width is equal to 720 pixels.
       // A thumbnail is an image obtained after the original image is proportionally compressed. After the compression, the smaller one of the height and width is equal to 198 pixels.
       NSArray<V2TIMImage *> *imageList = imageElem.imageList;
       for (V2TIMImage *timImage in imageList) {
           NSString *uuid = timImage.uuid; // Image ID
           V2TIMImageType type = timImage.type; // Image type
           int size = timImage.size; // Image size (bytes)
           int width = timImage.width; // Image width
           int height = timImage.height; // Image height
           // Set the image download path `imagePath`. Here, `uuid` can be used as an identifier to avoid repeated download.
           NSString *imagePath = [NSTemporaryDirectory() stringByAppendingPathComponent:
                               [NSString stringWithFormat: @"testImage%@",timImage.uuid]];
           if (![[NSFileManager defaultManager] fileExistsAtPath:imagePath]) {
                   [timImage downloadImage:imagePath 
                                   progress:^(NSInteger curSize, NSInteger totalSize) {
                       NSLog(@"Image download progress: curSize: %lu,totalSize:%lu",curSize,totalSize);
                   } succ:^{
                       NSLog(@"Image download completed");
                   } fail:^(int code, NSString *msg) {
                       NSLog(@"Image download failed: code: %d,msg:%@",code,msg);
                   }];
           } else {
                   // The image already exists
           }
       }
     }
    }
    
    Note:

    For more information on the message parsing sample code, see FAQs > 5. How can I parse different types of messages.

    Sending and Receiving Group @ Messages

    For a group @ message, the sender can listen to the input of the @ character in the input box and call the group member selection interface. After selection is completed, the input box displays the content in the format of "@A @B @C......",and then the sender can continue to edit the message content and send the message. On the group chat list of the recipient's conversation interface, the identifier "someone@me" or "@all members" will be displayed to remind the user that the user was mentioned by someone in the group.

    Note:

    Currently, only text @ messages are supported.

    Sending group @ messages

    1. The sender listens to the text input box on the chat interface and launches the group member selection interface. After selection is completed, the ID and nickname of the selected member are returned. The ID is used to construct the message object V2TIMMessage, and the nickname is to be displayed in the text box.
    2. The sender calls createTextAtMessage of V2TIMManager+Message to create an @ text message and obtain the message object V2TIMMessage.
    3. The sender calls sendMessage to send the created @ message object.

    Receiving group @ messages

    1. During conversation loading and update, you need to call the groupAtInfolist API of V2TIMConversation to obtain the @ data list of the conversation.
    2. Obtain and update the @ data type to the @ information of the current conversation through the atType API of the V2TIMGroupAtInfo object on the list.

    Typical example: sending and receiving group @ messages

    • Sending a group @ message:
      The sender creates and sends a group @ message.
    // Obtain the ID data of the @ group member
    TUITextMessageCellData *text = (TUITextMessageCellData *)data;
    NSMutableArray<NSString *> *atUserList = text.atUserList;
    // Create a group @ message
    V2TIMMessage *atMsg = [[V2TIMManager sharedInstance] createTextAtMessage:text.content atUserList:atUserList];
    // Send the group @ message
    [[V2TIMManager sharedInstance] sendMessage:atMsg
                                    receiver:nil
                                     groupID:@"toGroupId"
                                    priority:V2TIM_PRIORITY_DEFAULT
                              onlineUserOnly:NO
                             offlinePushInfo:nil
                                    progress:nil
                                        succ:^{
      NSLog(@"group @ message is sent successfully");
    }
                                        fail:^(int code, NSString *desc) {
      NSLog(@"group @ message fails to be sent");
    }];
    
    • Receiving a group @ message:
      During conversation loading and update, obtain the group @ data list, parse the current @ type, and display the prompt text based on the @ type.
    // Obtain the group @ data list
    NSArray<V2TIMGroupAtInfo *> *atInfoList = conversation.groupAtInfolist;
    // Parse the @ type (@me, @all members, @me and @all members)
    BOOL atMe = NO;         // Whether it's @me
    BOOL atAll = NO;        // Whether it's @all members
    NSString *atTipsStr = @"";
    for (V2TIMGroupAtInfo *atInfo in atInfoList) {
      switch (atInfo.atType) {
          case V2TIM_AT_ME:
              atMe = YES;
              break;
          case V2TIM_AT_ALL:
              atAll = YES;
              break;
          case V2TIM_AT_ALL_AT_ME:
              atMe = YES;
              atAll = YES;
              break;
          default:
              break;
      }
    }
    // Based on the @ type, prompt:
    if (atMe && !atAll) {
      atTipsStr = @"[someone@me]";
    }
    if (!atMe && atAll) {
      atTipsStr = @"[@all members]";
    }
    if (atMe && atAll) {
      atTipsStr = @"[someone@me][@all members]";
    }
    

    Sending and Receiving Combined Messages (Only Available in Lite Edition v5.2.210 and Above)

    To implement the combined forward feature similar to that in WeChat, it is necessary to create a combined message according to the original message list, and then send the combined message to the opposite end. After the opposite end receives the combined message, it will parse out the original message list. The display of the combined message also requires the title and abstract information.

    • Sending combined messages
      Usually when we receive a combined message, the chat screen will look like this:
    Chat History of Vinson and Lynx Title
    Vinson: When is the new version of SDK scheduled to go online? abstract1
    Lynx: Next Monday. The specific time depends on the system test result in these two days. abstract2
    Vinson: OK abstract3

    The chat interface will display only the title and abstract information of the combined message, and the combined message list will be displayed only when the user clicks the combined message. When we create a combined message, we need to set not only the combined message list, but also the title and abstract information. The implementation process is as follows:

    1. Call the createMergerMessage API to create a combined message.
    2. Call the sendMessage API to send the combined message.

    Typical example: sending and receiving combined messages

    • Sending combined messages
      The sender creates a combined message and sends it.
    // List of messages that need to be forwarded, which can contain combined messages and cannot contain group tips
    NSArray *msgs = @[message1,message2...];  
    // Title of the combined message
    NSString *title = @"Chat History of Vinson and Lynx";  
    // Abstract list of the combined message
    NSArray *abstactList = @[@"abstract1",@"abstract2",@"abstract3"]; 
    // Combined messages are compatible with text. SDKs of early versions do not support combined messages, and they will send a text message with the content `compatibleText` by default.
    NSString *compatibleText = @"Please upgrade to the latest version to check the combined message"; 
    // Create a combined message
    V2TIMMessage *mergeMessage = [[V2TIMManager sharedInstance] createMergerMessage:msgs title:title 
    abstractList:abstactList compatibleText:compatibleText];
    // Send the combined message to the user Denny
    [[V2TIMManager sharedInstance] sendMessage:mergeMessage receiver:@"denny"  groupID:nil
    priority:V2TIM_PRIORITY_NORMAL  onlineUserOnly:NO  offlinePushInfo:nil progress:nil succ:nil fail:nil];
    
    • Receiving combined messages
      The recipient receives the combined message and parses it:
      - (void)onRecvNewMessage:(V2TIMMessage *)msg {
       if (msg.elemType == V2TIM_ELEM_TYPE_MERGER) {
               // Get the combined message elements
               V2TIMMergerElem *mergerElem = msg.mergerElem;
               // Get the title
               NSString *title = mergerElem.title;
               // Get the abstract list
               NSArray *abstractList = mergerElem.abstractList;
               // Download the combined message list when a user clicks the combined message
               [msg.mergerElem downloadMergerMessage:^(NSArray<V2TIMMessage *> *msgs) {
                   // Download succeeded. `msgs` is the combined message list
                   for (V2TIMMessage *subMsg in msgs) {
                       // If the combined message list still contains combined messages, you can continue parsing
                       if (subMsg.elemType == V2TIM_ELEM_TYPE_MERGER) {
                           V2TIMMergerElem *mergerElem = subMsg.mergerElem;
                           // Get the title
                           NSString *title = mergerElem.title;
                           // Get the abstract list
                           NSArray *abstractList = mergerElem.abstractList;
                           // Download the combined message list when a user clicks the combined message
                           [msg.mergerElem downloadMergerMessage:nil fail:nil];
                       }
                   }
               } fail:^(int code, NSString *desc) {
                   // Download failed
               }];
           }
      }
      

    Sending Messages That Are Excluded from the Unread Count (Only Available in Lite Edition v5.3.425 and Above)

    Normally, when you send one-to-one messages and group messages, the messages are included in the unread count (you can get the unread message count of a conversation via the unreadCount API of the V2TIMConversation conversation object). If you need to send messages that are excluded from the unread count, such as tips and control messages, send them as follows:

    // Create the message object
    V2TIMMessage *message = [[V2TIMManager sharedInstance] createTextMessage:@"This is a signaling message"];
    // Set the identifier for excluding from the unread message count
    message.isExcludedFromUnreadCount = YES;
    // Send the message
    [[V2TIMManager sharedInstance] sendMessage:msg receiver:@"userA" groupID:nil
    priority:V2TIM_PRIORITY_DEFAULT onlineUserOnly:YES offlinePushInfo:nil progress:^(uint32_t progress) {
    } succ:^{
      // The message is sent successfully
    } fail:^(int code, NSString *msg) {
      // The message fails to be sent
    }];
    

    Sending Messages That Are Excluded from the Conversation lastMsg (Only Available in Enhanced Edition v5.4.666 and Above)

    In certain scenarios, if you need to send messages that are excluded from the conversation lastMsg, send them as follows:

    // Create the message object
    V2TIMMessage *message = [V2TIMManager.sharedInstance createTextMessage:content];
    // Set the identifier for excluding from the conversation lastMsg
    message.isExcludedFromLastMessage = YES;
    // Send the message
    [V2TIMManager.sharedInstance sendMessage:message receiver:@"userA" groupID:nil priority:V2TIM_PRIORITY_NORMAL onlineUserOnly:NO offlinePushInfo:nil progress:^(uint32_t progress) {
        // Sending progress
    } succ:^{
        // The message is sent successfully
    } fail:^(int code, NSString *desc) {
        // The message fails to be sent
    }];
    

    Setting APNs Offline Push (offlinePushInfo)

    When the recipient's app is killed or when the recipient switches to the backend, the IM SDK cannot receive new messages through the normal network connection. In this scenario, the APNs service provided by Apple must be used to notify the recipient of new messages. For more information, see Offline Push (iOS).

    Setting the title and voice for APNs offline push

    When sending messages, you can use the offlinePushInfo field in the sendMessage API to set the title and voice for APNs offline push.

    // Create and send an image message to groupA, and customize the title and voice for offline push.
    NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"png"];
    // Create an image message
    V2TIMMessage *msg = [[V2TIMManager sharedInstance] createImageMessage:imagePath];
    V2TIMOfflinePushInfo *pushInfo = [[V2TIMOfflinePushInfo alloc] init];
    // Customize the title and voice for offline push. `01.caf` is a sample file, which must be linked to the Xcode project. Here, you only need to enter the file name with the extension.
    pushInfo.title = @"Customize the title displayed";
    pushInfo.iOSSound = @"01.caf";
    [[V2TIMManager sharedInstance] sendMessage:msg receiver:nil groupID:@"groupA" priority:V2TIM_PRIORITY_DEFAULT 
    onlineUserOnly:NO offlinePushInfo:pushInfo progress:^(uint32_t progress) {
    } succ:^{
      // The message is sent successfully
    } fail:^(int code, NSString *msg) {
      // The message fails to be sent
    }];
    

    Clicking a pushed message to go to the corresponding chat window

    To implement this feature, the sender needs to set the extended field ext of the offline push object offlinePushInfo, when sending a message. When the recipient opens the app, the recipient can obtain ext through the didReceiveRemoteNotification system callback, and then go to the corresponding chat window based on the content of ext.

    The following example assumes that Denny sends a message to Vinson.

    • Sender: Denny needs to set ext before sending a message.

      // Denny sets `offlinePushInfo` and specifies `ext` before sending a message
      V2TIMMessage *msg = [[V2TIMManager sharedInstance] createTextMessage:@"Text message"];
      V2TIMOfflinePushInfo *info = [[V2TIMOfflinePushInfo alloc] init];
      info.ext = @"jump to denny";
      [[V2TIMManager sharedInstance] sendMessage:msg receiver:@"vinson" groupID:nil priority:V2TIM_PRIORITY_DEFAULT
      onlineUserOnly:NO offlinePushInfo:info progress:^(uint32_t progress) {
      } succ:^{
      } fail:^(int code, NSString *msg) {
      }];
      
    • Recipient: although Vinson's app is not online, it can still receive an APNs offline message notification. When Vinson clicks this notification, the app is started.

      // Vinson receives the following callback after starting the app.
      - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo 
      fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
        // Parse `desc`, which is the extended field for online push.
        if ([userInfo[@"ext"] isEqualToString:@"jump to denny"]) {
            // Go to the chat window with Denny.
        }
      }

    Setting onlineUserOnly so that Messages Can Be Received Only Online

    In some scenarios, you may wish that sent messages can only be received by online users or that a recipient is not aware of the message when the recipient is offline. For this purpose, you can set
    onlineUserOnly to YES when calling sendMessage. After the setting, the sent messages differ from common messages in the following ways:

    • Messages cannot be stored offline. That is, the recipient cannot receive messages unless he/she is online.
    • Messages do not support multi-device roaming. That is, if the recipient has received messages on one terminal, these messages cannot be received on any other terminal no matter whether these messages are read or not.
    • Messages cannot be stored locally. That is, these messages cannot be retrieved from the local historical messages in the cloud.

    **Typical example: displaying "The other party is typing..."
    In the one-to-one chat scenario, you can call sendMessage to send the "I am typing..." message. When the recipient receives this message, "The other party is typing..." is displayed on the UI. The sample code is as follows:

    // Send the "I am typing..." message to userA
    NSString *customStr = @"{\"command\": \"textInput\"}";
    NSData *customData = [customStr dataUsingEncoding:NSUTF8StringEncoding];
    V2TIMMessage *msg = [[V2TIMManager sharedInstance] createCustomMessage:customData];
    [[V2TIMManager sharedInstance] sendMessage:msg receiver:@"userA" groupID:nil
    priority:V2TIM_PRIORITY_DEFAULT onlineUserOnly:YES offlinePushInfo:nil progress:^(uint32_t progress) {
    } succ:^{
       // The message is sent successfully
    } fail:^(int code, NSString *msg) {
       // The message fails to be sent
    }];
    

    Setting "Mute Notifications" for Message Receiving (Only Available in Lite Edition v5.3.425 and Above)

    The SDK supports the following types of message receiving options:

    • V2TIM_RECEIVE_MESSAGE: messages will be received when the user is online, and offline push notifications will be received when the user is offline.
    • V2TIM_NOT_RECEIVE_MESSAGE: messages will not be received no matter whether the user is online or offline.
    • V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE: messages will be received when the user is online, and offline push notifications will not be received when the user is offline.

    You can call the setC2CReceiveMessageOpt API to set the Mute Notifications option for one-to-one messages and call the setGroupReceiveMessageOpt API to set the Mute Notifications option for group messages.

    Recalling Messages

    The sender can call the revokeMessage API to recall a successfully sent message. By default, the sender can recall a message that is sent within 2 minutes. You can change the time limit for message recall. For detailed operations, see Message recall settings.
    Message recall requires cooperation of the UI code at the recipient side. When the sender recalls a message, the recipient will receive a message recall notification, onRecvMessageRevoked. This notification contains the msgID of the recalled message. Based on this msgID, you can identify the message that has been recalled and change the corresponding message bubble to the "Message recalled" state on the UI.

    The sender recalls a message

    [[V2TIMManager sharedInstance] revokeMessage:msg succ:^{
       // The message is successfully recalled
    } fail:^(int code, NSString *msg) {
       // The message fails to be recalled
    }];
    

    The recipient learns that the message is recalled

    1. Call addAdvancedMsgListener to set the advanced message listener.
    2. Call onRecvMessageRevoked to receive the message recall notification.
    - (void)onRecvMessageRevoked:(NSString *)msgID {
        // `msgList` is the message list on the current chat interface
        for(V2TIMMessage *msg in msgList){
           if ([msg.msgID isEqualToString:msgID]) {
               // `msg` is the recalled message. You need to change the corresponding message bubble state on the UI.
           }
       }
    }
    

    Adding Read Receipts for Messages

    In the one-to-one chat scenario, when the recipient calls the markC2CMessageAsRead API to mark an incoming message as read, the message sender will receive a read receipt, indicating that the recipient has read his/her message.

    Note:

    Currently, only one-to-one chats support the read receipt feature, and group chats do not support this feature. Although the markGroupMessageAsRead API is also available to group chats, the group message senders currently cannot receive any read receipts.

    The recipient marks messages as read

    // Mark messages coming from Haven as read
    [[V2TIMManager sharedInstance] markC2CMessageAsRead:@"haven" succ:^{
    } fail:^(int code, NSString *msg) {
    }];
    

    The sender learns that the messages are read

    The event notification of the message receipt is located in the advanced message listener V2TIMAdvancedMsgListener. To learn that a message is already read, the sender must call addAdvancedMsgListener to set the listener. Then, the sender can receive a read receipt from the recipient through the onRecvC2CReadReceipt callback.

    - (void)onRecvC2CReadReceipt:(NSArray<V2TIMMessageReceipt *> *)receiptList {
        // The sender may receive multiple read receipts at a time. Therefore, the array callback mode is used here.
        for (V2TIMMessageReceipt *receipt in receiptList) {
            // Message recipient
            NSString * receiver = receipt.userID;
            // Time of the read receipt. A message is considered as read if the timestamp in the chat window is not later than `timestamp` here
            time_t timestamp = receipt.timestamp;
        }
    }
    @end
    

    Viewing Historical Messages

    You can call getC2CHistoryMessageList to obtain historical messages of one-to-one chats, or call getGroupHistoryMessageList to obtain historical messages of group chats. If the network connection of the current device is normal, the IM SDK pulls historical messages from the server by default. If the network connection is unavailable, the IM SDK directly reads historical messages from the local database.

    Pulling historical messages by page

    The IM SDK supports the feature of pulling historical messages by page. The number of messages pulled per page cannot be too large; otherwise, the pulling speed is affected. We recommend that you pull 20 messages per page.
    The following example assumes that historical messages of groupA are pulled by page, and the number of messages per page is 20. The sample code is as follows:

    // The value `nil` of `lastMsg` is passed in for the first pulling, indicating that starting from the latest message, a total of 20 messages are pulled
    [[V2TIMManager sharedInstance] getGroupHistoryMessageList:@"groupA" count:20 
    lastMsg:nil succ:^(NSArray<V2TIMMessage *> *msgs) {
      // Messages that are pulled by page are listed from new to old by default
      if (msgs.count > 0) {
          // Obtain the start message for the next pulling by page
          V2TIMMessage *lastMsg = msgs.lastObject;
          // Pull the remaining 20 messages
          [[V2TIMManager sharedInstance] getGroupHistoryMessageList:@"groupA" count:20 
                  lastMsg:lastMsg succ:^(NSArray<V2TIMMessage *> *msgs) {
              // Message pulling is completed
          } fail:^(int code, NSString *msg) {
              // Messages fail to be pulled
          }];
      }
    } fail:^(int code, NSString *msg) {
      // Messages fail to be pulled
    }];
    

    In actual scenarios, pulling by page is often triggered by your swipe operation. Each time when you swipe on the message list, pulling by page is triggered once. However, the principle is similar to the preceding sample code. In either case, lastMsg specifies the start message for pulling, and count specifies the number of messages pulled each time.

    Precautions

    • The storage period of historical messages is as follows:
      • Trial edition: free storage for 7 days, no extension supported.
      • Pro edition: free storage for 7 days, extension supported.
      • Flagship edition: free storage for 30 days, extension supported.
      It is a value-added service to extend the storage period of historical messages. You can log in to the IM console to modify the relevant configuration. For information about billing, see Value-added Service Pricing.
    • Only the meeting group (corresponding to the ChatRoom of the earlier version) supports pulling historical messages of members before they join the group.
    • Messages in an audio-video group (AVChatRoom) do not support local storage and multi-device roaming. Therefore, the getGroupHistoryMessageList API does not take effect on an audio-video group.

    Deleting Messages

    You can call the deleteMessages API to delete historical messages. After deletion, historical messages cannot be recovered.

    Setting Message Permissions

    Allowing message sending and receiving only among friends

    By default, the IM SDK does not prevent message sending and receiving among strangers. If you wish that one-to-one messages can be sent or received only among friends, you can log in to the IM console, choose Feature Configuration -> Login and Message -> Relationship Check, and enable Check Relationship for One-to-One Messages. After this feature is enabled, you can send messages only to friends. When you try to send messages to strangers, the IM SDK returns the 20009 error code.

    Not receiving messages from a specific user

    To avoid receiving messages from a specific user, you can blocklist the user or set the Mute Notifications option for messages from the user. After setting the Mute Notifications option, you can change the Mute Notifications status.
    Blocklisting a user:
    Call the addToBlackList API to add the user to the blocklist. When the user is blocklisted, the user does not know that he/she is in the blocklist by default. That is, after this user sends a message, the prompt still indicates that the message is sent successfully, but in fact the recipient will not receive the message. If you want a user on the blocklist to know that his/her message fails to be sent, you can log in to the IM console, choose Feature Configuration -> Login and Message -> Blocklist Check, and disable Show "Sent successfully" After Sending Messages. After this feature is disabled, the IM SDK will return the 20007 error code when a user in the blocklist sends a message.

    Setting "Mute Notifications" for messages from a specified user (only available in Lite Edition v5.3.425 and above):
    Call the setC2CReceiveMessageOpt API to set the message receiving option to V2TIM_NOT_RECEIVE_MESSAGE.

    Not receiving messages from a specified group

    For Lite Edition v5.3.425 and above, call the setGroupReceiveMessageOpt API to set the message receiving option to V2TIM_NOT_RECEIVE_MESSAGE.
    For SDKs of other versions, call the setReceiveMessageOpt API to set the message receiving option to V2TIM_GROUP_NOT_RECEIVE_MESSAGE.

    Filtering Sensitive Words

    Text messages sent by the IM SDK are filtered by IM for sensitive words. If a sent text message contains sensitive words, the IM SDK will return the 80001 error code.

    FAQs

    1. Why am I receiving duplicate messages?

    2. Why do the read receipts become invalid after the app is uninstalled and then reinstalled?

    In the one-to-one chat scenario, if the recipient calls markC2CMessageAsRead to mark a message as read, the read receipt received by the sender contains timestamp. Based on timestamp, the SDK determines whether the other party reads the message. Currently, timestamp is stored locally, and will be lost when the app is reinstalled.

    3. How can I send a message containing multiple Elem objects?

    You can call appendElem after creating a Message object via the Elem member of the Message object to add the next Elem member.
    Below is an example of text message + custom message:

    V2TIMMessage *msg = [[V2TIMManager sharedInstance] createTextMessage:@"text"];
    V2TIMCustomElem *customElem = [[V2TIMCustomElem alloc] init];
    customElem.data = [@"custom message" dataUsingEncoding:NSUTF8StringEncoding];
    [msg.textElem appendElem:customElem];
    

    4. How can I parse a message containing multiple Elem objects?

    1. Use the Message object to parse the first Elem object.
    2. Use the nextElem method of the first Elem object to obtain the next Elem object. If the next Elem object exists, the Elem object instance is returned. Otherwise, nil is returned.
    - (void)onRecvNewMessage:(V2TIMMessage *)msg {
      // View the first `Elem` object
      if (msg.elemType == V2TIM_ELEM_TYPE_TEXT) {
          V2TIMTextElem *textElem = msg.textElem;
          NSString *text = textElem.text;
          NSLog(@"Text information: %@", text);
          // Check whether `textElem` is followed by more `Elem` objects
          V2TIMElem *elem = textElem.nextElem;
          while (elem != nil) {
              // Identify the `Elem` type
              if ([elem isKindOfClass:[V2TIMCustomElem class]]) {
                  V2TIMCustomElem *customElem = (V2TIMCustomElem *)elem;
                  NSData *customData = customElem.data;
                  NSLog(@"Custom information: %@",customData);
              }
              // Continue to check whether the current `Elem` is followed by more `Elem` objects
              elem = elem.nextElem;
          }
          // If `elem` is `nil`, all `Elem` objects have been parsed
      }
    }
    

    5. How are different types of messages parsed?

    It is complex to parse a message. We provide the sample code for parsing different types of messages. You can copy the code to your project, and perform secondary development based on your actual needs.