addSimpleMsgListener API is used to listen for and receive text and custom messages, with the callback defined in the V2TIMSimpleMsgListener protocol.addAdvancedMsgListener API is used to listen for and receive all types of messages (text, custom, and rich media messages), with the callback defined in the V2TIMAdvancedMsgListener protocol.V2TIMSimpleMsgListener simple message listener and the V2TIMAdvancedMsgListener advanced message listener.
They differ in that:addSimpleMsgListener and addAdvancedMsgListener are exclusive. Do not use both of them; otherwise, unpredictable logic bugs will occur.addSimpleMsgListener (Java / Swift / Objective-C / C++) to add the simple message listener. We recommend it be called early, such as after the chat page is initialized, to ensure timely message receiving in the application.V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);
V2TIMManager.shared.addSimpleMsgListener(listener: self)
// `self` is id<V2TIMSignalingListener>[[V2TIMManager sharedInstance] addSimpleMsgListener:self];
class SimpleMsgListener final : public V2TIMSimpleMsgListener {// Members ...};// Note that `simpleMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.SimpleMsgListener simpleMsgListener;V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
V2TIMSimpleMsgListener (Java / Swift / Objective-C / C++), as described below:public abstract class V2TIMSimpleMsgListener {// Received the one-to-one text messagepublic void onRecvC2CTextMessage(String msgID, V2TIMUserInfo sender, String text) {}// Received the custom one-to-one (signaling) messagepublic void onRecvC2CCustomMessage(String msgID, V2TIMUserInfo sender, byte[] customData) {}// Received the group text messagepublic void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {}// Received the custom group (signaling) messagepublic void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {}}
public protocol V2TIMSimpleMsgListener : AnyObject {// Received the one-to-one text messagefunc onRecvC2CTextMessage(msgID: String, sender: V2TIMUserInfo, text: String?)// Received the custom one-to-one (signaling) messagefunc onRecvC2CCustomMessage(msgID: String, sender: V2TIMUserInfo, customData: Data?)// Received the group text messagefunc onRecvGroupTextMessage(msgID: String, groupID: String, sender: V2TIMGroupMemberInfo, text: String?)// Received the custom group (signaling) messagefunc onRecvGroupCustomMessage(msgID: String, groupID: String, sender: V2TIMGroupMemberInfo, customData: Data?)}
/// Basic message callback of the IM SDK@protocol V2TIMSimpleMsgListener <NSObject>@optional/// Received a one-to-one text message- (void)onRecvC2CTextMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info text:(NSString *)text;/// Received a custom one-to-one (signaling) message- (void)onRecvC2CCustomMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info customData:(NSData *)data;/// Received a group text message- (void)onRecvGroupTextMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info text:(NSString *)text;/// Received a custom group (signaling) message- (void)onRecvGroupCustomMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info customData:(NSData *)data;@end
class SimpleMsgListener final : public V2TIMSimpleMsgListener {public:SimpleMsgListener() = default;~SimpleMsgListener() override = default;// Received the one-to-one text messagevoid OnRecvC2CTextMessage(const V2TIMString& msgID, const V2TIMUserFullInfo& sender,const V2TIMString& text) override {}// Received the custom one-to-one (signaling) messagevoid OnRecvC2CCustomMessage(const V2TIMString& msgID, const V2TIMUserFullInfo& sender,const V2TIMBuffer& customData) override {}// Received the group text messagevoid OnRecvGroupTextMessage(const V2TIMString& msgID, const V2TIMString& groupID,const V2TIMGroupMemberFullInfo& sender, const V2TIMString& text) override {}// Received the custom group (signaling) messagevoid OnRecvGroupCustomMessage(const V2TIMString& msgID, const V2TIMString& groupID,const V2TIMGroupMemberFullInfo& sender,const V2TIMBuffer& customData) override {}};
removeSimpleMsgListener (Java / Swift / Objective-C / C++) to remove the simple message listener.V2TIMManager.getInstance().removeSimpleMsgListener(simpleMsgListener);
V2TIMManager.shared.removeSimpleMsgListener(listener: self)
// `self` is id<V2TIMSignalingListener>[[V2TIMManager sharedInstance] removeSimpleMsgListener:self];
class SimpleMsgListener final : public V2TIMSimpleMsgListener {// Members ...};// `simpleMsgListener` is the instance of SimpleMsgListenerV2TIMManager::GetInstance()->RemoveSimpleMsgListener(&simpleMsgListener);
addAdvancedMsgListener (Java / Swift / Objective-C / C++) to add the advanced message listener. We recommend it be called early, such as after the chat page is initialized, to ensure timely message receiving in the application.V2TIMManager.getMessageManager().addAdvancedMsgListener(advancedMsgListener);
V2TIMManager.shared.addAdvancedMsgListener(listener: self)
// `self` is id<V2TIMAdvancedMsgListener>[[V2TIMManager sharedInstance] addAdvancedMsgListener:self];
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {// Members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
V2TIMAdvancedMsgListener (Java / Swift / Objective-C / C++), as described below:public abstract class V2TIMAdvancedMsgListener {// Received a new messagepublic void onRecvNewMessage(V2TIMMessage msg) {}// one-to-one message read notification (a notification is received when the receiver calls `markC2CMessageAsRead`)public void onRecvC2CReadReceipt(List<V2TIMMessageReceipt> receiptList) {}// Message read receipt notification (if read receipts are supported, the notification is received when the receiver calls `sendMessageReadReceipts`)public void onRecvMessageReadReceipts(List<V2TIMMessageReceipt> receiptList) {}// Received a message recall notificationpublic void onRecvMessageRevoked(String msgID) {}// The message content is modified.public void onRecvMessageModified(V2TIMMessage msg) {}}
public protocol V2TIMAdvancedMsgListener: AnyObject {// Received a new messagefunc onRecvNewMessage(msg: V2TIMMessage)// Message read receipt notification (if read receipts are supported, the notification is received when the receiver calls `sendMessageReadReceipts`)func onRecvMessageReadReceipts(receiptList: Array<V2TIMMessageReceipt>)// one-to-one message read notification (a notification is received when the receiver calls `markC2CMessageAsRead`)func onRecvC2CReadReceipt(receiptList: Array<V2TIMMessageReceipt>)// Received a message recall notificationfunc onRecvMessageRevoked(msgID: String, operateUser: V2TIMUserInfo, reason: String?)// The message content is modified.func onRecvMessageModified(msg: V2TIMMessage)}
/// Advanced message listener@protocol V2TIMAdvancedMsgListener <NSObject>@optional/// Received a new message- (void)onRecvNewMessage:(V2TIMMessage *)msg;/// Message read receipt notification (if read receipts are supported, the notification is received when the receiver calls `sendMessageReadReceipts`)- (void)onRecvMessageReadReceipts:(NSArray<V2TIMMessageReceipt *> *)receiptList;/// One-to-one message read notification (a notification is received when the receiver calls `markC2CMessageAsRead`)- (void)onRecvC2CReadReceipt:(NSArray<V2TIMMessageReceipt *> *)receiptList;/// Received a message recall notification- (void)onRecvMessageRevoked:(NSString *)msgID;/// The message content is modified- (void)onRecvMessageModified:(V2TIMMessage *)msg;@end
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:AdvancedMsgListener() = default;~AdvancedMsgListener() override = default;// Received a new messagevoid OnRecvNewMessage(const V2TIMMessage& message) override {}// one-to-one message read notification (a notification is received when the receiver calls `markC2CMessageAsRead`)void OnRecvC2CReadReceipt(const V2TIMMessageReceiptVector& receiptList) override {}// Message read receipt notification (if read receipts are supported, the notification is received when the receiver calls `sendMessageReadReceipts`)void OnRecvMessageReadReceipts(const V2TIMMessageReceiptVector& receiptList) override {}// Received a message recall notificationvoid OnRecvMessageRevoked(const V2TIMString& messageID) override {}// The message content is modified.void OnRecvMessageModified(const V2TIMMessage& message) override {}};
removeAdvancedMsgListener (Java / Swift / Objective-C / C++) to remove the advanced message listener.V2TIMManager.getMessageManager().removeAdvancedMsgListener(advancedMsgListener);
V2TIMManager.shared.removeAdvancedMsgListener(listener: self)
// `self` is id<V2TIMAdvancedMsgListener>[[V2TIMManager sharedInstance] removeAdvancedMsgListener:self];
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {// Members ...};// `advancedMsgListener` is the instance of AdvancedMsgListenerV2TIMManager::GetInstance()->GetMessageManager()->RemoveAdvancedMsgListener(&advancedMsgListener);
addSimpleMsgListener to set the event listener.onRecvC2CTextMessage callback (Java / Swift / Objective-C / C++) to receive text messages.removeSimpleMsgListener to remove the listener. This step is optional and can be performed as needed.// Set the event listenerV2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);// Receive the one-to-one text message/*** Received the one-to-one text message** @param msgID Unique message ID* @param sender Sender information* @param text The sent content*/public void onRecvC2CTextMessage(String msgID, V2TIMUserInfo sender, String text) {// Parse the message and display it on the UI}
// Set the event listenerV2TIMManager.shared.addSimpleMsgListener(listener: self)// Receive the one-to-one text message/*** Received the one-to-one text message** @param msgID Unique message ID* @param sender Sender information* @param text The sent content*/func onRecvC2CTextMessage(msgID: String, sender: V2TIMUserInfo, text: String?) {// Parse the message and display it on the UI}
// Set the event listener[[V2TIMManager sharedInstance] addSimpleMsgListener:self];/// Receive the one-to-one text message/// @param msgID Message ID/// @param info Sender information/// @param text Text content- (void)onRecvC2CTextMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info text:(NSString *)text {// Parse the message and display it on the UI}
class SimpleMsgListener final : public V2TIMSimpleMsgListener {public:/*** Receive the one-to-one text message** @param msgID Unique message ID* @param sender Sender information* @param text The sent content*/void OnRecvC2CTextMessage(const V2TIMString& msgID, const V2TIMUserFullInfo& sender,const V2TIMString& text) override {// Parse the message and display it on the UIstd::cout << "text:" << std::string{text.CString(), text.Size()} << std::endl;}// Other members ...};// Note that `simpleMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.SimpleMsgListener simpleMsgListener;V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
addSimpleMsgListener to set the event listener.onRecvGroupTextMessage callback (Java / Swift / Objective-C / C++) to receive text messages.removeSimpleMsgListener to remove the listener. This step is optional and can be performed as needed.// Set the event listenerV2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);// Receive the group text message/*** Received the group text message** @param msgID Unique message ID* @param groupID Group ID* @param sender The group member information of the sender* @param text The sent content*/public void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {// Parse the message and display it on the UI}
// Set the event listenerV2TIMManager.shared.addSimpleMsgListener(listener: self)// Receive the group text message/*** Received the group text message** @param msgID Unique message ID* @param groupID Group ID* @param sender The group member information of the sender* @param text The sent content*/func onRecvGroupTextMessage(msgID: String, groupID: String, sender: V2TIMGroupMemberInfo, text:String?{// Parse the message and display it on the UI}
// Set the event listener[[V2TIMManager sharedInstance] addSimpleMsgListener:self];/// Receive the group text message/// @param msgID Message ID/// @param groupID Group ID/// @param info Sender information/// @param text Text content- (void)onRecvGroupTextMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info text:(NSString *)text {// Parse the message and display it on the UI}
class SimpleMsgListener final : public V2TIMSimpleMsgListener {public:/*** Received the group text message** @param msgID Unique message ID* @param groupID Group ID* @param sender The group member information of the sender* @param text The sent content*/void OnRecvGroupTextMessage(const V2TIMString& msgID, const V2TIMString& groupID,const V2TIMGroupMemberFullInfo& sender, const V2TIMString& text) override {// Parse the message and display it on the UIstd::cout << "text:" << std::string{text.CString(), text.Size()} << std::endl;}// Other members ...};// Note that `simpleMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.SimpleMsgListener simpleMsgListener;V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
addAdvancedMsgListener to set the event listener.onRecvNewMessage callback (Java / Swift / Objective-C / C++) to receive text messages.removeAdvancedMsgListener to remove the listener. This step is optional and can be performed as needed.// Set the event listenerV2TIMManager.getMessageManager().addAdvancedMsgListener(advancedMsgListener);/*** Received a new message* @param msg Message*/public void onRecvNewMessage(V2TIMMessage msg) {// Parse the `groupID` and `userID`String groupID = msg.getGroupID();String userID = msg.getUserID();// Determine whether it's a one-to-one chat or group chat// If `groupID` is not empty, the message is from a group chat; if `userID` is not empty, the message is from a one-to-one chat.// Parse the text message in `msg`if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) {V2TIMTextElem textElem = msg.getTextElem();String text = textElem.getText();Log.i("onRecvNewMessage", "text:" + text);}}
// Set the event listenerV2TIMManager.shared.addAdvancedMsgListener(listener: self)/*** Received a new message* @param msg Message*/func onRecvNewMessage(_ msg: V2TIMMessage) {// Parse the `groupID` and `userID`let groupID = msg.groupIDlet userID = msg.userID// Determine whether it's a one-to-one chat or group chat// If `groupID` is not empty, the message is from a group chat; if `userID` is not empty, the message is from a one-to-one chat.if !groupID.isEmpty {print("Received a group message in group: \\(groupID)")} else if !userID.isEmpty {print("Received a one-on-one message from user: \\(userID)")} else {print("Received a message with no identifiable sender.")}// Parse the text message in `msg`if msg.elemType == .V2TIM_ELEM_TYPE_TEXT {if let textElem = msg.textElem {let text = textElem.textprint("onRecvNewMessage, text: \\(text)")}} else {print("Received a non-text message.")}}
// Set the event listener[[V2TIMManager sharedInstance] addAdvancedMsgListener:self];/// Receive the message/// @param msg Message object- (void)onRecvNewMessage:(V2TIMMessage *)msg {// Parse the `groupID` and `userID`NSString *groupID = msg.groupID;NSString *userID = msg.userID;// Determine whether it's a one-to-one chat or group chat// If `groupID` is not empty, the message is from a group chat; if `userID` is not empty, the message is from a one-to-one chat.// Parse the text message in `msg`if (msg.elemType == V2TIM_ELEM_TYPE_TEXT) {V2TIMTextElem *textElem = msg.textElem;NSString *text = textElem.text;NSLog(@"onRecvNewMessage, text: %@", text);}}
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:/*** Received a new message** @param message Message*/void OnRecvNewMessage(const V2TIMMessage& message) override {// Parse the `groupID` and `userID`V2TIMString groupID = message.groupID;V2TIMString userID = message.userID;// Determine whether it's a one-to-one chat or group chat// If `groupID` is not empty, the message is from a group chat;// if `userID` is not empty, the message is from a one-to-one chat.// Parse the text message in `message`if (message.elemList.Size() == 1) {V2TIMElem* elem = message.elemList[0];if (elem->elemType == V2TIMElemType::V2TIM_ELEM_TYPE_TEXT) {auto textElem = static_cast<V2TIMTextElem*>(elem);V2TIMString text = textElem->text;// Parse the message and display it on the UIstd::cout << "text:" << std::string{text.CString(), text.Size()} << std::endl;}}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
addSimpleMsgListener to set the event listener.onRecvC2CCustomMessage callback (Java / Swift / Objective-C / C++) to receive custom one-to-one messages.removeSimpleMsgListener to remove the listener. This step is optional and can be performed as needed./*** Receive the custom one-to-one message* @param msgID Message ID* @param sender Sender information* @param customData The sent content*/public void onRecvC2CCustomMessage(String msgID, V2TIMUserInfo sender, byte[] customData) {Log.i("onRecvC2CCustomMessage", "msgID:" + msgID + ", from:" + sender.getNickName() + ", content:" + new String(customData));}
/*** Receive the custom one-to-one message* @param msgID Message ID* @param sender Sender information* @param customData The sent content*/func onRecvC2CCustomMessage(msgID: String, sender: V2TIMUserInfo, customData: Data?) {}
/// Receive the custom one-to-one message/// @param msgID Message ID/// @param info Sender information/// @param data The binary content of the custom message- (void)onRecvC2CCustomMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info customData:(NSData *)data {NSLog(@"onRecvC2CCustomMessage, msgID: %@, sender: %@, customData: %@", msgID, info, data);}
class SimpleMsgListener final : public V2TIMSimpleMsgListener {public:/*** Receive the custom one-to-one message** @param msgID Message ID* @param sender Sender information* @param customData The sent content*/void OnRecvC2CCustomMessage(const V2TIMString& msgID, const V2TIMUserFullInfo& sender,const V2TIMBuffer& customData) override {// Parse the message and display it on the UIstd::cout << "customData:"<< std::string{reinterpret_cast<const char*>(customData.Data()), customData.Size()}<< std::endl;}// Other members ...};// Note that `simpleMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.SimpleMsgListener simpleMsgListener;V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
addSimpleMsgListener to set the event listener.onRecvGroupCustomMessage callback (Java / Swift / Objective-C / C++) to receive custom group messages.removeSimpleMsgListener to remove the listener. This step is optional and can be performed as needed./*** Receive the custom group message* @param msgID Message ID* @param groupID Group ID* @param sender The group member information of the sender* @param customData The sent content*/public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {Log.i("onRecvGroupCustomMessage", "msgID:" + msgID + ", groupID:" + groupID + ", from:" + sender.getNickName() + ", content:" + new String(customData));}
/*** Receive the custom group message* @param msgID Message ID* @param groupID Group ID* @param sender The group member information of the sender* @param customData The sent content*/func onRecvGroupCustomMessage(msgID: String, groupID: String, sender: V2TIMGroupMemberInfo, customData: Data?) {}
/// Receive the custom group message/// @param msgID Message ID/// @param groupID Group ID/// @param info Sender information/// @param text The binary content of the custom message- (void)onRecvGroupCustomMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info customData:(NSData *)data {NSLog(@"onRecvGroupCustomMessage, msgID: %@, groupID: %@, sender: %@, customData: %@", msgID, groupID, info, data);}
class SimpleMsgListener final : public V2TIMSimpleMsgListener {public:/*** Receive the custom group message** @param msgID Message ID* @param groupID Group ID* @param sender The group member information of the sender* @param customData The sent content*/void OnRecvGroupCustomMessage(const V2TIMString& msgID, const V2TIMString& groupID,const V2TIMGroupMemberFullInfo& sender,const V2TIMBuffer& customData) override {// Parse the message and display it on the UIstd::cout << "customData:"<< std::string{reinterpret_cast<const char*>(customData.Data()), customData.Size()}<< std::endl;}// Other members ...};// Note that `simpleMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.SimpleMsgListener simpleMsgListener;V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
addAdvancedMsgListener to set the event listener.onRecvNewMessage callback (Java / Swift / Objective-C / C++) to receive custom messages.removeAdvancedMsgListener to remove the listener. This step is optional and can be performed as needed.// Set the event listenerV2TIMManager.getMessageManager().addAdvancedMsgListener(v2TIMAdvancedMsgListener);// Receive the messagepublic void onRecvNewMessage(V2TIMMessage msg) {// Parse the `groupID` and `userID`String groupID = msg.getGroupID();String userID = msg.getUserID();// Determine whether it's a one-to-one chat or group chat// If `groupID` is not empty, the message is from a group chat; if `userID` is not empty, the message is from a one-to-one chat.// Parse the custom message in `msg`if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_CUSTOM) {V2TIMCustomElem customElem = msg.getCustomElem();String data = new String(customElem.getData());Log.i("onRecvNewMessage", "customData:" + data);}}
// Set the event listenerV2TIMManager.shared.addAdvancedMsgListener(listener: self)// Receive the messagefunc onRecvNewMessage(_ msg: V2TIMMessage) {// Parse the `groupID` and `userID`let groupID = msg.groupIDlet userID = msg.userID// Determine whether it's a one-to-one chat or group chat// If `groupID` is not empty, the message is from a group chat; if `userID` is not empty, the message is from a one-to-one chat.if !groupID.isEmpty {print("Received a group message in group: \\(groupID)")} else if !userID.isEmpty {print("Received a one-on-one message from user: \\(userID)")} else {print("Received a message with no identifiable sender.")}// Parse the custom message in `msg`if msg.elemType == .V2TIM_ELEM_TYPE_TEXT {if let textElem = msg.textElem {let text = textElem.textprint("onRecvNewMessage, text: \\(text)")}} else {print("Received a non-text message.")}}
// Set the event listener[[V2TIMManager sharedInstance] addAdvancedMsgListener:self];/// Receive the message/// @param msg Message object- (void)onRecvNewMessage:(V2TIMMessage *)msg {// Parse the `groupID` and `userID`NSString *groupID = msg.groupID;NSString *userID = msg.userID;// Determine whether it's a one-to-one chat or group chat// If `groupID` is not empty, the message is from a group chat; if `userID` is not empty, the message is from a one-to-one chat.// Parse the custom message in `msg`if (msg.elemType == V2TIM_ELEM_TYPE_CUSTOM) {V2TIMCustomElem *customElem = msg.customElem;NSData *customData = customElem.data;NSLog(@"onRecvNewMessage, customData: %@", customData);}}
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:/*** Receive the message** @param message Message*/void OnRecvNewMessage(const V2TIMMessage& message) override {// Parse the `groupID` and `userID`V2TIMString groupID = message.groupID;V2TIMString userID = message.userID;// Determine whether it's a one-to-one chat or group chat// If `groupID` is not empty, the message is from a group chat;// if `userID` is not empty, the message is from a one-to-one chat.// Parse the custom message in `message`if (message.elemList.Size() == 1) {V2TIMElem* elem = message.elemList[0];if (elem->elemType == V2TIMElemType::V2TIM_ELEM_TYPE_CUSTOM) {auto customElem = static_cast<V2TIMCustomElem*>(elem);V2TIMBuffer data = customElem->data;// Parse the message and display it on the UIstd::cout << "data:"<< std::string{reinterpret_cast<const char*>(data.Data()), data.Size()}<< std::endl;}}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
addAdvancedMsgListener API to set the advanced message listener.onRecvNewMessage callback (Java / Swift / Objective-C / C++) to receive the V2TIMMessage message.elemType attribute in the V2TIMMessage message and then parse the message again according to the type to get the specific content of the elements in the message.removeAdvancedMsgListener to remove the listener. This step is optional and can be performed as needed.downloadImage (Java / Swift / Objective-C / C++) to download the image and then render it to the UI layer.uuid attribute value of the V2TIMImage object to the image download path to identify the image.V2TIMMessage:public void onRecvNewMessage(V2TIMMessage msg) {if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE) {// Image messageV2TIMImageElem v2TIMImageElem = msg.getImageElem();// The image in an image message can be in three formats: original, large, and thumbnail. The latter two are automatically generated by the SDK during message sending and can be ignored.// Large image: A large image is an image obtained after the original image is proportionally compressed. After the compression, the height or width (whichever is shorter) is equal to 720 pixels.// Thumbnail: A thumbnail is an image obtained after the original image is proportionally compressed. After the compression, the height or width (whichever is shorter) is equal to 198 pixels.List<V2TIMImageElem.V2TIMImage> imageList = v2TIMImageElem.getImageList();for (V2TIMImageElem.V2TIMImage v2TIMImage : imageList) {// Image ID, which is an internal ID and can be used as an external cache keyString uuid = v2TIMImage.getUUID();// Image types, encompassing three distinct varieties: V2TIM_IMAGE_TYPE_ORIGIN (Original), V2TIM_IMAGE_TYPE_THUMB (Thumbnail), and V2TIM_IMAGE_TYPE_LARGE (Large).int imageType = v2TIMImage.getType();// Image size (bytes)int size = v2TIMImage.getSize();// Image widthint width = v2TIMImage.getWidth();// Image heightint height = v2TIMImage.getHeight();// Image download urlString url = v2TIMImage.getUrl();// Set the image download path `imagePath`. Here, `uuid` can be used as an identifier to avoid repeated download.String imagePath = "/sdcard/im/image/" + "myUserID" + uuid;File imageFile = new File(imagePath);// Determine whether there is a downloaded image file in `imagePath`if (!imageFile.exists()) {// Download the imagev2TIMImage.downloadImage(imagePath, new V2TIMDownloadCallback() {@Overridepublic void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {// Callback for download progress. `v2ProgressInfo.getCurrentSize()` indicates the downloaded file size, and `v2ProgressInfo.getTotalSize()` indicates the total file size.}@Overridepublic void onError(int code, String desc) {// Download failed}@Overridepublic void onSuccess() {// Downloaded}});} else {// The image already exists.}}}}
func onRecvNewMessage(_ msg: V2TIMMessage) {if msg.elemType == .V2TIM_ELEM_TYPE_IMAGE {guard let imageElem = msg.imageElem else { return }// The image in an image message can be in three formats: original, large, and thumbnail. The latter two are automatically generated by the SDK during message sending and can be ignored.// Large image: A large image is an image obtained after the original image is proportionally compressed. After the compression, the height or width (whichever is shorter) is equal to 720 pixels.// Thumbnail: A thumbnail is an image obtained after the original image is proportionally compressed. After the compression, the height or width (whichever is shorter) is equal to 198 pixels.let imageList = imageElem.imageListfor timImage in imageList {// Image ID, which is an internal ID and can be used as an external cache keylet uuid = timImage.uuid// Image typelet type = timImage.type// Image size (bytes)let size = timImage.sizelet width = timImage.widthlet height = timImage.height// Image download urllet url = timImage.url// Set the image download path `imagePath`. Here, `uuid` can be used as an identifier to avoid repeated download.let imagePath = NSTemporaryDirectory().appending("testImage\\(timImage.uuid)")// Determine whether there is a downloaded image file in `imagePath`if !FileManager.default.fileExists(atPath: imagePath) {// Download the imagetimImage.downloadImage(path: imagePath, progress: { curSize, totalSize inprint("Image download progress:curSize:\\(curSize), totalSize: \\(totalSize)")}, succ: {print("Image download success")}, fail: { code, msg in// Download failedprint("failed:code:\\(code), msg: \\(msg)")})} else {// The image already exists.print(" The image already exists.:\\(imagePath)")}print("Image info:uuid: \\(uuid), type: \\(type.rawValue), size: \\(size), width: \\(width), height: \\(height)")}}}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {if (msg.elemType == V2TIM_ELEM_TYPE_IMAGE) {V2TIMImageElem *imageElem = msg.imageElem;// The list of original images, large images, and thumbnailsNSArray<V2TIMImage *> *imageList = imageElem.imageList;for (V2TIMImage *timImage in imageList) {// Image ID, which is an internal ID and can be used as an external cache keyNSString *uuid = timImage.uuid;// Image typeV2TIMImageType type = timImage.type;// Image size (bytes)int size = timImage.size;// Image widthint width = timImage.width;// Image heightint height = timImage.height;// Image download urlNSString * url = timImage.url;// 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]];// Determine whether there is a downloaded image file in `imagePath`if (![[NSFileManager defaultManager] fileExistsAtPath:imagePath]) {// Download the image[timImage downloadImage:imagePath progress:^(NSInteger curSize, NSInteger totalSize) {// Download progressNSLog(@"Image download progress: curSize: %lu,totalSize:%lu",curSize,totalSize);} succ:^{// Downloaded successfullyNSLog(@"Image downloaded");} fail:^(int code, NSString *msg) {// Download failedNSLog(@"Failed to download the image: code: %d,msg:%@",code,msg);}];} else {// The image already exists.}NSLog(@"Image information: uuid:%@, type:%ld, size:%d, width:%d, height:%d", uuid, (long)type, size, width, height);}}}
class DownloadCallback final : public V2TIMDownloadCallback {public:using SuccessCallback = std::function<void()>;using ErrorCallback = std::function<void(int, const V2TIMString&)>;using DownLoadProgressCallback = std::function<void(uint64_t, uint64_t)>;DownloadCallback() = default;~DownloadCallback() override = default;void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback,DownLoadProgressCallback download_progress_callback) {success_callback_ = std::move(success_callback);error_callback_ = std::move(error_callback);download_progress_callback_ = std::move(download_progress_callback);}void OnSuccess() override {if (success_callback_) {success_callback_();}}void OnError(int error_code, const V2TIMString& error_message) override {if (error_callback_) {error_callback_(error_code, error_message);}}void OnDownLoadProgress(uint64_t currentSize, uint64_t totalSize) override {if (download_progress_callback_) {download_progress_callback_(currentSize, totalSize);}}private:SuccessCallback success_callback_;ErrorCallback error_callback_;DownLoadProgressCallback download_progress_callback_;};class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:void OnRecvNewMessage(const V2TIMMessage& message) override {if (message.elemList.Size() == 1) {V2TIMElem* elem = message.elemList[0];if (elem->elemType == V2TIMElemType::V2TIM_ELEM_TYPE_IMAGE) {// Image messageauto imageElem = static_cast<V2TIMImageElem*>(elem);// The image in an image message can be in three formats: original, large, and thumbnail.// The latter two are automatically generated by the SDK during message sending and can be ignored.// Large image: A large image is an image obtained after the original image is proportionally compressed.// After the compression, the height or width (whichever is shorter) is equal to 720 pixels.// Thumbnail: A thumbnail is an image obtained after the original image is proportionally compressed.// After the compression, the height or width (whichever is shorter) is equal to 198 pixels.V2TIMImageVector imageList = imageElem->imageList;for (size_t i = 0; i < imageList.Size(); ++i) {V2TIMImage& image = imageList[i];// Image ID, which is an internal ID and can be used as an external cache keyV2TIMString uuid = image.uuid;// Image typeV2TIMImageType type = image.type;// Image size (bytes) when type == V2TIMImageType::V2TIM_IMAGE_TYPE_ORIGINuint64_t size = image.size;// Image widthuint32_t width = image.width;// Image heightuint32_t height = image.height;// Image download urlV2TIMString url = image.url;// Set the image download path `imagePath`.// Here, `uuid` can be used as an identifier to avoid repeated download.std::filesystem::path imagePath = u8"./File/Image/"s + uuid.CString();// Determine whether there is a downloaded image file in `imagePath`if (!std::filesystem::exists(imagePath)) {std::filesystem::create_directories(imagePath.parent_path());auto callback = new DownloadCallback{};callback->SetCallback([=]() {// Downloadeddelete callback;},[=](int error_code, const V2TIMString& error_message) {// Download faileddelete callback;},[=](uint64_t currentSize, uint64_t totalSize) {// Callback for download progress.// `currentSize` indicates the downloaded file size,// and `totalSize` indicates the total file size.});image.DownloadImage(imagePath.string().c_str(), callback);} else {// The image already exists.}}}}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener); // Image download urlV2TIMString url = image.url;
downloadSnapshot (Java / Swift / Objective-C / C++) for download.downloadVideo (Java / Swift / Objective-C / C++) for download.videoUUID attribute value of the V2TIMVideoElem object to the video download path to identify the video.V2TIMMessage:public void onRecvNewMessage(V2TIMMessage msg) {if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_VIDEO) {// Video messageV2TIMVideoElem v2TIMVideoElem = msg.getVideoElem();// Video screenshot ID, which is an internal ID and can be used as an external cache keyString snapshotUUID = v2TIMVideoElem.getSnapshotUUID();// Video screenshot file sizeint snapshotSize = v2TIMVideoElem.getSnapshotSize();// Video screenshot widthint snapshotWidth = v2TIMVideoElem.getSnapshotWidth();// Video screenshot heightint snapshotHeight = v2TIMVideoElem.getSnapshotHeight();// Video ID, which is an internal ID and can be used as an external cache keyString videoUUID = v2TIMVideoElem.getVideoUUID();// Video file sizeint videoSize = v2TIMVideoElem.getVideoSize();// Video durationint duration = v2TIMVideoElem.getDuration();// Set the video screenshot file path. Here, `uuid` can be used as an identifier to avoid repeated download.String snapshotPath = "/sdcard/im/snapshot/" + "myUserID" + snapshotUUID;File snapshotFile = new File(snapshotPath);if (!snapshotFile.exists()) {v2TIMVideoElem.downloadSnapshot(snapshotPath, new V2TIMDownloadCallback() {@Overridepublic void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {// Callback for download progress. `v2ProgressInfo.getCurrentSize()` indicates the downloaded file size, and `v2ProgressInfo.getTotalSize()` indicates the total file size.}@Overridepublic void onError(int code, String desc) {// Download failed}@Overridepublic void onSuccess() {// Downloaded}});} else {// The file already exists.}// Set the video file path. Here, `uuid` can be used as an identifier to avoid repeated download.String videoPath = "/sdcard/im/video/" + "myUserID" + videoUUID;File videoFile = new File(videoPath);if (!videoFile.exists()) {v2TIMVideoElem.downloadVideo(videoPath, new V2TIMDownloadCallback() {@Overridepublic void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {// Callback for download progress. `v2ProgressInfo.getCurrentSize()` indicates the downloaded file size, and `v2ProgressInfo.getTotalSize()` indicates the total file size.}@Overridepublic void onError(int code, String desc) {// Download failed}@Overridepublic void onSuccess() {// Downloaded}});} else {// The file already exists.}}}
func onRecvNewMessage(_ msg: V2TIMMessage) {if msg.elemType == .V2TIM_ELEM_TYPE_VIDEO {let videoElem = msg.videoElem// Video screenshot ID, which is an internal ID and can be used as an external cache keylet snapshotUUID = videoElem?.snapshotUUID// Video screenshot file sizelet snapshotSize = videoElem?.snapshotSizelet snapshotWidth = videoElem?.snapshotWidthlet snapshotHeight = videoElem?.snapshotHeight// Video ID, which is an internal ID and can be used as an external cache keylet videoUUID = videoElem?.videoUUIDlet videoSize = videoElem?.videoSizelet duration = videoElem?.duration// Set the video screenshot file path. Here, `uuid` can be used as an identifier to avoid repeated download.let snapshotPath = NSTemporaryDirectory().appending("testVideoSnapshot\\(snapshotUUID)")if !FileManager.default.fileExists(atPath: snapshotPath) {// Download the video screenshotvideoElem?.downloadSnapshot(path: snapshotPath, progress: { curSize, totalSize inprint("progress:curSize:\\(curSize), totalSize: \\(totalSize)")}, succ: {print("succ")}, fail: { code, msg inprint("failed code:\\(code), msg: \\(msg)")})} else {// The video Snapshot already exists.}print("video info:snapshotUUID: \\(snapshotUUID), snapshotSize: \\(snapshotSize), snapshotWidth: \\(snapshotWidth), snapshotHeight: \\(snapshotHeight), snapshotPath: \\(snapshotPath)")// Set the video file path. Here, `uuid` can be used as an identifier to avoid repeated download.let videoPath = NSTemporaryDirectory().appending("testVideo\\(videoUUID)")if !FileManager.default.fileExists(atPath: videoPath) {// downloadVideovideoElem?.downloadVideo(path: videoPath, progress: { curSize, totalSize inprint("downloadVideo progress curSize:\\(curSize), totalSize: \\(totalSize)")}, succ: {print("downloadVideo success")}, fail: { code, msg inprint("code:\\(code), msg: \\(msg)")})} else {// The video already exists.}print("video info:videoUUID: \\(videoUUID), videoSize: \\(videoSize), duration: \\(duration), videoPath: \\(videoPath)")}}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {if (msg.elemType == V2TIM_ELEM_TYPE_VIDEO) {V2TIMVideoElem *videoElem = msg.videoElem;// Video screenshot ID, which is an internal ID and can be used as an external cache keyNSString *snapshotUUID = videoElem.snapshotUUID;// Video screenshot file sizeint snapshotSize = videoElem.snapshotSize;// Video screenshot widthint snapshotWidth = videoElem.snapshotWidth;// Video screenshot heightint snapshotHeight = videoElem.snapshotHeight;// Video ID, which is an internal ID and can be used as an external cache keyNSString *videoUUID = videoElem.videoUUID;// Video file sizeint videoSize = videoElem.videoSize;// Video durationint duration = videoElem.duration;// Set the video screenshot file path. Here, `uuid` can be used as an identifier to avoid repeated download.NSString *snapshotPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat: @"testVideoSnapshot%@",snapshotUUID]];if (![[NSFileManager defaultManager] fileExistsAtPath:snapshotPath]) {// Download the video screenshot[videoElem downloadSnapshot:snapshotPath progress:^(NSInteger curSize, NSInteger totalSize) {// Download progressNSLog(@"%@", [NSString stringWithFormat:@"Video screenshot download progress: curSize: %lu,totalSize:%lu",curSize,totalSize]);} succ:^{// Downloaded successfullyNSLog(@"Video screenshot downloaded");} fail:^(int code, NSString *msg) {// Download failedNSLog(@"%@", [NSString stringWithFormat:@"Failed to download the video screenshot: code: %d,msg:%@",code,msg]);}];} else {// The video screenshot already exists.}NSLog(@"Video screenshot information: snapshotUUID:%@, snapshotSize:%d, snapshotWidth:%d, snapshotWidth:%d, snapshotPath:%@", snapshotUUID, snapshotSize, snapshotWidth, snapshotHeight, snapshotPath);// Set the video file path. Here, `uuid` can be used as an identifier to avoid repeated download.NSString *videoPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat: @"testVideo%@",videoUUID]];if (![[NSFileManager defaultManager] fileExistsAtPath:videoPath]) {// Download the video[videoElem downloadVideo:videoPath progress:^(NSInteger curSize, NSInteger totalSize) {// Download progressNSLog(@"%@", [NSString stringWithFormat:@"Video download progress: curSize: %lu,totalSize:%lu",curSize,totalSize]);} succ:^{// Downloaded successfullyNSLog(@"Video downloaded");} fail:^(int code, NSString *msg) {// Download failedNSLog(@"%@", [NSString stringWithFormat:@"Failed to download the video: code: %d,msg:%@",code,msg]);}];} else {// The video already exists.}NSLog(@"Video information: videoUUID:%@, videoSize:%d, duration:%d, videoPath:%@", videoUUID, videoSize, duration, videoPath);}}
class DownloadCallback final : public V2TIMDownloadCallback {public:using SuccessCallback = std::function<void()>;using ErrorCallback = std::function<void(int, const V2TIMString&)>;using DownLoadProgressCallback = std::function<void(uint64_t, uint64_t)>;DownloadCallback() = default;~DownloadCallback() override = default;void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback,DownLoadProgressCallback download_progress_callback) {success_callback_ = std::move(success_callback);error_callback_ = std::move(error_callback);download_progress_callback_ = std::move(download_progress_callback);}void OnSuccess() override {if (success_callback_) {success_callback_();}}void OnError(int error_code, const V2TIMString& error_message) override {if (error_callback_) {error_callback_(error_code, error_message);}}void OnDownLoadProgress(uint64_t currentSize, uint64_t totalSize) override {if (download_progress_callback_) {download_progress_callback_(currentSize, totalSize);}}private:SuccessCallback success_callback_;ErrorCallback error_callback_;DownLoadProgressCallback download_progress_callback_;};class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:void OnRecvNewMessage(const V2TIMMessage& message) override {if (message.elemList.Size() == 1) {V2TIMElem* elem = message.elemList[0];if (elem->elemType == V2TIMElemType::V2TIM_ELEM_TYPE_VIDEO) {// Video messageauto videoElem = static_cast<V2TIMVideoElem*>(elem);// Video ID, which is an internal ID and can be used as an external cache keyV2TIMString videoUUID = videoElem->videoUUID;// Video file sizeuint64_t videoSize = videoElem->videoSize;// Video typeV2TIMString videoType = videoElem->videoType;// Video durationuint32_t duration = videoElem->duration;// Video screenshot ID, which is an internal ID and can be used as an external cache keyV2TIMString snapshotUUID = videoElem->snapshotUUID;// Video screenshot file sizeuint64_t snapshotSize = videoElem->snapshotSize;// Video screenshot widthuint32_t snapshotWidth = videoElem->snapshotWidth;// Video screenshot heightuint32_t snapshotHeight = videoElem->snapshotHeight;// Set the video file path. Here, `uuid` can be used as an identifier to avoid repeated download.std::filesystem::path videoPath = u8"./File/Video/"s + videoUUID.CString();if (!std::filesystem::exists(videoPath)) {std::filesystem::create_directories(videoPath.parent_path());auto callback = new DownloadCallback{};callback->SetCallback([=]() {// Downloadeddelete callback;},[=](int error_code, const V2TIMString& error_message) {// Download faileddelete callback;},[=](uint64_t currentSize, uint64_t totalSize) {// Callback for download progress.// `currentSize` indicates the downloaded file size,// and `totalSize` indicates the total file size.});videoElem->DownloadVideo(videoPath.string().c_str(), callback);} else {// The file already exists.}// Set the video screenshot file path. Here, `uuid` can be used as an identifier to avoid repeated download.std::filesystem::path snapshotPath = u8"./File/Snapshot/"s + snapshotUUID.CString();if (!std::filesystem::exists(snapshotPath)) {std::filesystem::create_directories(snapshotPath.parent_path());auto callback = new DownloadCallback{};callback->SetCallback([=]() {// Downloadeddelete callback;},[=](int error_code, const V2TIMString& error_message) {// Download faileddelete callback;},[=](uint64_t currentSize, uint64_t totalSize) {// Callback for download progress.// `currentSize` indicates the downloaded file size,// and `totalSize` indicates the total file size.});videoElem->DownloadSnapshot(snapshotPath.string().c_str(), callback);} else {// The file already exists.}}}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
downloadSound (Java / Swift / Objective-C / C++) to download the audio and then play it back.uuid attribute value of the V2TIMSoundElem object to the audio download path to identify the audio.V2TIMMessage:public void onRecvNewMessage(V2TIMMessage msg) {if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_SOUND) {// Audio messageV2TIMSoundElem v2TIMSoundElem = msg.getSoundElem();// Audio ID, which is an internal ID and can be used as an external cache keyString uuid = v2TIMSoundElem.getUUID();// Audio file sizeint dataSize = v2TIMSoundElem.getDataSize();// Audio durationint duration = v2TIMSoundElem.getDuration();// Set the audio file path `soundPath`. Here, `uuid` can be used as an identifier to avoid repeated downloadString soundPath = "/sdcard/im/sound/" + "myUserID" + uuid;File imageFile = new File(soundPath);// Determine whether there is a downloaded audio file in `soundPath`if (!imageFile.exists()) {v2TIMSoundElem.downloadSound(soundPath, new V2TIMDownloadCallback() {@Overridepublic void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {// Callback for download progress. `v2ProgressInfo.getCurrentSize()` indicates the downloaded file size, and `v2ProgressInfo.getTotalSize()` indicates the total file size.}@Overridepublic void onError(int code, String desc) {// Download failed}@Overridepublic void onSuccess() {// Downloaded}});} else {// The file already exists.}}}
func onRecvNewMessage(_ msg: V2TIMMessage) {if msg.elemType == .V2TIM_ELEM_TYPE_SOUND {guard let soundElem = msg.soundElem else { return }// Audio ID, which is an internal ID and can be used as an external cache keylet uuid = soundElem.uuid// Audio file sizelet dataSize = soundElem.dataSize// Audio durationlet duration = soundElem.duration// Set the audio file path `soundPath`. Here, `uuid` can be used as an identifier to avoid repeated downloadlet soundPath = NSTemporaryDirectory().appending("testSound\\(uuid)")// Determine whether there is a downloaded audio file in `soundPath`if !FileManager.default.fileExists(atPath: soundPath) {// downloadSoundsoundElem.downloadSound(path: soundPath, progress: { curSize, totalSize in// Download progressprint("Download progress:curSize:\\(curSize), totalSize: \\(totalSize)")}, succ: {print("Download success")}, fail: { code, msg inprint("error code:\\(code), msg: \\(msg)")})} else {// The audio already exists.print("The audio already exists:\\(soundPath)")}print("audio info:uuid: \\(uuid), dataSize: \\(dataSize), duration: \\(duration), soundPath: \\(soundPath)")}}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {if (msg.elemType == V2TIM_ELEM_TYPE_SOUND) {V2TIMSoundElem *soundElem = msg.soundElem;// Audio ID, which is an internal ID and can be used as an external cache keyNSString *uuid = soundElem.uuid;// Audio file sizeint dataSize = soundElem.dataSize;// Audio durationint duration = soundElem.duration;// Set the audio file path `soundPath`. Here, `uuid` can be used as an identifier to avoid repeated downloadNSString *soundPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat: @"testSound%@",uuid]];// Determine whether there is a downloaded audio file in `soundPath`if (![[NSFileManager defaultManager] fileExistsAtPath:soundPath]) {// Download the audio[soundElem downloadSound:soundPath progress:^(NSInteger curSize, NSInteger totalSize) {// Download progressNSLog(@"Audio download progress: curSize: %lu,totalSize:%lu",curSize,totalSize);} succ:^{// Downloaded successfullyNSLog(@"Audio downloaded");} fail:^(int code, NSString *msg) {// Download failedNSLog(@"Failed to download the audio: code: %d,msg:%@",code,msg);}];} else {// The audio already exists.}NSLog(@"Audio information: uuid:%@, dataSize:%d, duration:%d, soundPath:%@", uuid, dataSize, duration, soundPath);}}
class DownloadCallback final : public V2TIMDownloadCallback {public:using SuccessCallback = std::function<void()>;using ErrorCallback = std::function<void(int, const V2TIMString&)>;using DownLoadProgressCallback = std::function<void(uint64_t, uint64_t)>;DownloadCallback() = default;~DownloadCallback() override = default;void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback,DownLoadProgressCallback download_progress_callback) {success_callback_ = std::move(success_callback);error_callback_ = std::move(error_callback);download_progress_callback_ = std::move(download_progress_callback);}void OnSuccess() override {if (success_callback_) {success_callback_();}}void OnError(int error_code, const V2TIMString& error_message) override {if (error_callback_) {error_callback_(error_code, error_message);}}void OnDownLoadProgress(uint64_t currentSize, uint64_t totalSize) override {if (download_progress_callback_) {download_progress_callback_(currentSize, totalSize);}}private:SuccessCallback success_callback_;ErrorCallback error_callback_;DownLoadProgressCallback download_progress_callback_;};class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:void OnRecvNewMessage(const V2TIMMessage& message) override {if (message.elemList.Size() == 1) {V2TIMElem* elem = message.elemList[0];if (elem->elemType == V2TIMElemType::V2TIM_ELEM_TYPE_SOUND) {// Audio messageauto soundElem = static_cast<V2TIMSoundElem*>(elem);// Audio ID, which is an internal ID and can be used as an external cache keyV2TIMString uuid = soundElem->uuid;// Audio file sizeuint64_t dataSize = soundElem->dataSize;// Audio duration(seconds)uint32_t duration = soundElem->duration;// Set the audio file path `soundPath`. Here, `uuid` can be used as an identifier to avoid repeated downloadstd::filesystem::path soundPath = u8"./File/Sound/"s + uuid.CString();// Determine whether there is a downloaded audio file in `soundPath`if (!std::filesystem::exists(soundPath)) {std::filesystem::create_directories(soundPath.parent_path());auto callback = new DownloadCallback{};callback->SetCallback([=]() {// Downloadeddelete callback;},[=](int error_code, const V2TIMString& error_message) {// Download faileddelete callback;},[=](uint64_t currentSize, uint64_t totalSize) {// Callback for download progress.// `currentSize` indicates the downloaded file size,// and `totalSize` indicates the total file size.});soundElem->DownloadSound(soundPath.string().c_str(), callback);} else {// The file already exists.}}}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
downloadFile (Java / Swift / Objective-C / C++) to download the file and then display it.uuid attribute value of the V2TIMFileElem object to the file download path to identify the file.V2TIMMessage:public void onRecvNewMessage(V2TIMMessage msg) {if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_FILE) {// File messageV2TIMFileElem v2TIMFileElem = msg.getFileElem();// File ID, which is an internal ID and can be used as an external cache keyString uuid = v2TIMFileElem.getUUID();// FilenameString fileName = v2TIMFileElem.getFileName();// File sizeint fileSize = v2TIMFileElem.getFileSize();// Set the file path. Here, `uuid` can be used as an identifier to avoid repeated download.String filePath = "/sdcard/im/file/" + "myUserID" + uuid;File file = new File(filePath);if (!file.exists()) {v2TIMFileElem.downloadFile(filePath, new V2TIMDownloadCallback() {@Overridepublic void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {// Callback for download progress. `v2ProgressInfo.getCurrentSize()` indicates the downloaded file size, and `v2ProgressInfo.getTotalSize()` indicates the total file size.}@Overridepublic void onError(int code, String desc) {// Download failed}@Overridepublic void onSuccess() {// Downloaded}});} else {// The file already exists.}}}
func onRecvNewMessage(_ msg: V2TIMMessage) {if msg.elemType == .V2TIM_ELEM_TYPE_FILE {guard let fileElem = msg.fileElem else { return }// File ID, which is an internal ID and can be used as an external cache keylet uuid = fileElem.uuidlet filename = fileElem.filenamelet fileSize = fileElem.fileSize// Set the file path. Here, `uuid` can be used as an identifier to avoid repeated download.let filePath = NSTemporaryDirectory().appending("testFile\\(uuid)")if !FileManager.default.fileExists(atPath: filePath) {// downloadFilefileElem.downloadFile(path: filePath, progress: { curSize, totalSize inprint("downloadFile progress:curSize:\\(curSize), totalSize: \\(totalSize)")}, succ: {print("downloadFile success")}, fail: { code, msg inprint("error code:\\(code), msg: \\(msg)")})} else {print("file exist \\(filePath)")}print("file info:uuid: \\(uuid), filename: \\(filename), fileSize: \\(fileSize), filePath: \\(filePath)")}}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {if (msg.elemType == V2TIM_ELEM_TYPE_FILE) {V2TIMFileElem *fileElem = msg.fileElem;// File ID, which is an internal ID and can be used as an external cache keyNSString *uuid = fileElem.uuid;// FilenameNSString *filename = fileElem.filename;// File sizeint fileSize = fileElem.fileSize;// Set the file path. Here, `uuid` can be used as an identifier to avoid repeated download.NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat: @"testFile%@",uuid]];if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {// Download the file[fileElem downloadFile:filePath progress:^(NSInteger curSize, NSInteger totalSize) {// Download progressNSLog(@"%@", [NSString stringWithFormat:@"File download progress: curSize: %lu,totalSize:%lu",curSize,totalSize]);} succ:^{// Downloaded successfullyNSLog(@"File downloaded");} fail:^(int code, NSString *msg) {// Download failedNSLog(@"%@", [NSString stringWithFormat:@"Failed to download the file: code: %d,msg:%@",code,msg]);}];} else {// The file already exists.}NSLog(@"File information: uuid:%@, filename:%@, fileSize:%d, filePath:%@", uuid, filename, fileSize, filePath);}}
class DownloadCallback final : public V2TIMDownloadCallback {public:using SuccessCallback = std::function<void()>;using ErrorCallback = std::function<void(int, const V2TIMString&)>;using DownLoadProgressCallback = std::function<void(uint64_t, uint64_t)>;DownloadCallback() = default;~DownloadCallback() override = default;void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback,DownLoadProgressCallback download_progress_callback) {success_callback_ = std::move(success_callback);error_callback_ = std::move(error_callback);download_progress_callback_ = std::move(download_progress_callback);}void OnSuccess() override {if (success_callback_) {success_callback_();}}void OnError(int error_code, const V2TIMString& error_message) override {if (error_callback_) {error_callback_(error_code, error_message);}}void OnDownLoadProgress(uint64_t currentSize, uint64_t totalSize) override {if (download_progress_callback_) {download_progress_callback_(currentSize, totalSize);}}private:SuccessCallback success_callback_;ErrorCallback error_callback_;DownLoadProgressCallback download_progress_callback_;};class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:void OnRecvNewMessage(const V2TIMMessage& message) override {if (message.elemList.Size() == 1) {V2TIMElem* elem = message.elemList[0];if (elem->elemType == V2TIMElemType::V2TIM_ELEM_TYPE_FILE) {// File messageauto fileElem = static_cast<V2TIMFileElem*>(elem);// File ID, which is an internal ID and can be used as an external cache keyV2TIMString uuid = fileElem->uuid;// FilenameV2TIMString filename = fileElem->filename;// File sizeuint64_t fileSize = fileElem->fileSize;// Set the file path. Here, `uuid` can be used as an identifier to avoid repeated download.std::filesystem::path filePath = u8"./File/File/"s + uuid.CString();if (!std::filesystem::exists(filePath)) {std::filesystem::create_directories(filePath.parent_path());auto callback = new DownloadCallback{};callback->SetCallback([=]() {// Downloadeddelete callback;},[=](int error_code, const V2TIMString& error_message) {// Download faileddelete callback;},[=](uint64_t currentSize, uint64_t totalSize) {// Callback for download progress.// `currentSize` indicates the downloaded file size,// and `totalSize` indicates the total file size.});fileElem->DownloadFile(filePath.string().c_str(), callback);} else {// The file already exists.}}}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
V2TIMLocationElem.
The following sample code demonstrates how to parse the location content from V2TIMMessage:public void onRecvNewMessage(V2TIMMessage msg) {if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_LOCATION) {// Geographical location messageV2TIMLocationElem v2TIMLocationElem = msg.getLocationElem();// Geographical location information descriptionString desc = v2TIMLocationElem.getDesc();// Longitudedouble longitude = v2TIMLocationElem.getLongitude();// Latitudedouble latitude = v2TIMLocationElem.getLatitude();}}
func onRecvNewMessage(_ msg: V2TIMMessage) {if msg.elemType == .V2TIM_ELEM_TYPE_LOCATION {let locationElem = msg.locationElem// Geographical location information descriptionlet desc = locationElem?.desc// Longitudelet longitude = locationElem?.longitude// Latitudelet latitude = locationElem?.latitudeprint("location info:desc:\\(desc), longitude:\\(longitude), latitude:\\(latitude)")}}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {if (msg.elemType == V2TIM_ELEM_TYPE_LOCATION) {V2TIMLocationElem *locationElem = msg.locationElem;// Geographical location information descriptionNSString *desc = locationElem.desc;// Longitudedouble longitude = locationElem.longitude;// Latitudedouble latitude = locationElem.latitude;NSLog(@"Geographical location information: desc: %@, longitude:%f, latitude:%f", desc, longitude, latitude);}}
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:void OnRecvNewMessage(const V2TIMMessage& message) override {if (message.elemList.Size() == 1) {V2TIMElem* elem = message.elemList[0];if (elem->elemType == V2TIMElemType::V2TIM_ELEM_TYPE_LOCATION) {// Geographical location messageauto locationElem = static_cast<V2TIMLocationElem*>(elem);// Geographical location information descriptionV2TIMString desc = locationElem->desc;// Longitudedouble longitude = locationElem->longitude;// Latitudedouble latitude = locationElem->latitude;}}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
V2TIMFaceElem (Java / Swift / Objective-C / C++). Here, index and data can be customized.index to 1 and data to x12345 to indicate the smile emoji.
The receiver parses the received emoji message as 1 and x12345 and displays the message as the smile emoji according to the preset rules.V2TIMMessage:public void onRecvNewMessage(V2TIMMessage msg) {if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_FACE) {// Emoji messageV2TIMFaceElem v2TIMFaceElem = msg.getFaceElem();// Emoji locationint index = v2TIMFaceElem.getIndex();// Custom emoji databyte[] data = v2TIMFaceElem.getData();}}
func onRecvNewMessage(_ msg: V2TIMMessage) {guard msg.elemType == .V2TIM_ELEM_TYPE_FACE, let faceElem = msg.faceElem else {return}// Emoji locationlet index = faceElem.index// Custom emoji dataguard let data = faceElem.data else {print("Emoji empty")return}print("Emoji information index: \\(index), data: \\(data)")}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {if (msg.elemType == V2TIM_ELEM_TYPE_FACE) {V2TIMFaceElem *faceElem = msg.faceElem;// Emoji locationint index = faceElem.index;// Custom emoji dataNSData *data = faceElem.data;NSLog(@"Emoji information: index: %d, data: %@", index, data);}}
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:void OnRecvNewMessage(const V2TIMMessage& message) override {if (message.elemList.Size() == 1) {V2TIMElem* elem = message.elemList[0];if (elem->elemType == V2TIMElemType::V2TIM_ELEM_TYPE_FACE) {// Emoji messageauto faceElem = static_cast<V2TIMFaceElem*>(elem);// Emoji locationuint32_t index = faceElem->index;// Custom emoji dataV2TIMBuffer data = faceElem->data;}}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
onRecvNewMessage notification mentioned earlier. After receiving a message, you can determine whether the message is a broadcast message based on the isBroadcastMessage property.public void onRecvNewMessage(V2TIMMessage msg) {if (msg.isBroadcastMessage) {// Received the broadcast message}}
func onRecvNewMessage(_ msg: V2TIMMessage) {if msg.isBroadcastMessage {// Received the broadcast message}}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {if (msg.isBroadcastMessage) {// Received the broadcast message}}
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:void OnRecvNewMessage(const V2TIMMessage& message) override {if (message.isBroadcastMessage) {// Received the broadcast message}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
nextElem method of the first element object. If the next object exists, an element object instance is returned; otherwise, nil or null is returned.@Overridepublic void onRecvNewMessage(V2TIMMessage msg) {// View the first elementint elemType = msg.getElemType();if (elemType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) {// Text messageV2TIMTextElem v2TIMTextElem = msg.getTextElem();String text = v2TIMTextElem.getText();// Check whether `v2TIMTextElem` is followed by more elementsV2TIMElem elem = v2TIMTextElem.getNextElem();while (elem != null) {// Identify the element type. Here, `V2TIMCustomElem` is used as an example.if (elem instanceof V2TIMCustomElem) {V2TIMCustomElem customElem = (V2TIMCustomElem) elem;byte[] data = customElem.getData();}// Further check whether the current element is followed by more elementselem = elem.getNextElem();}// If the element is `null`, all the elements have been parsed.}}
func onRecvNewMessage(_ msg: V2TIMMessage) {// View the first elementif msg.elemType == .V2TIM_ELEM_TYPE_TEXT {let textElem = msg.textElemlet text = textElem?.textprint("text : \\(text)")var elem: V2TIMElem? = textElem?.getNextElem()while elem != nil {// Identify the element typeif let customElem = elem as? V2TIMCustomElem {let customData = customElem.dataprint("Custom information : \\(customData)")}// Further check whether the current element is followed by more elementselem = elem?.getNextElem()}// If the element is `nil`, all the elements have been parsed.}}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {// View the first elementif (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 elementsV2TIMElem *elem = textElem.nextElem;while (elem != nil) {// Identify the element typeif ([elem isKindOfClass:[V2TIMCustomElem class]]) {V2TIMCustomElem *customElem = (V2TIMCustomElem *)elem;NSData *customData = customElem.data;NSLog(@"Custom information: %@",customData);}// Further check whether the current element is followed by more elementselem = elem.nextElem;}// If the element is `nil`, all the elements have been parsed.}}
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {public:void OnRecvNewMessage(const V2TIMMessage& message) override {// View the first elementfor (size_t i = 0; i < message.elemList.Size(); ++i) {V2TIMElem* elem = message.elemList[i];switch (elem->elemType) {case V2TIMElemType::V2TIM_ELEM_TYPE_NONE: {// Unknown message} break;case V2TIMElemType::V2TIM_ELEM_TYPE_TEXT: {// Text messageauto textElem = static_cast<V2TIMTextElem*>(elem);} break;case V2TIMElemType::V2TIM_ELEM_TYPE_CUSTOM: {// Custom messageauto customElem = static_cast<V2TIMCustomElem*>(elem);} break;case V2TIMElemType::V2TIM_ELEM_TYPE_IMAGE: {// Image messageauto imageElem = static_cast<V2TIMImageElem*>(elem);} break;case V2TIMElemType::V2TIM_ELEM_TYPE_SOUND: {// Audio messageauto soundElem = static_cast<V2TIMSoundElem*>(elem);} break;case V2TIMElemType::V2TIM_ELEM_TYPE_VIDEO: {// Video messageauto videoElem = static_cast<V2TIMVideoElem*>(elem);} break;case V2TIMElemType::V2TIM_ELEM_TYPE_FILE: {// File messageauto fileElem = static_cast<V2TIMFileElem*>(elem);} break;case V2TIMElemType::V2TIM_ELEM_TYPE_LOCATION: {// Geographical location messageauto locationElem = static_cast<V2TIMLocationElem*>(elem);} break;case V2TIMElemType::V2TIM_ELEM_TYPE_FACE: {// Emoji messageauto faceElem = static_cast<V2TIMFaceElem*>(elem);} break;case V2TIMElemType::V2TIM_ELEM_TYPE_GROUP_TIPS: {// Group @ messageauto mergerElem = static_cast<V2TIMMergerElem*>(elem);} break;case V2TIMElemType::V2TIM_ELEM_TYPE_MERGER: {// Merged messageauto groupTipsElem = static_cast<V2TIMGroupTipsElem*>(elem);} break;default: {} break;}}}// Other members ...};// Note that `advancedMsgListener` should not be released before the IM SDK is uninitialized,// otherwise the message callback cannot be called.AdvancedMsgListener advancedMsgListener;V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
フィードバック