Feature Description
The addSimpleMsgListener
API is used to listen for and receive text and custom messages, with the callback defined in the V2TIMSimpleMsgListener
protocol.
The 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.
Setting a Message Listener
The SDK provides the V2TIMSimpleMsgListener
simple message listener and the V2TIMAdvancedMsgListener
advanced message listener.
They differ in that:
1. The simple message listener can only receive text and custom messages. You can use it if your business only requires these two types of messages.
2. The advanced message listener can receive all types of messages. You can use it if your business also requires rich media, merged, and other messages.
Note:
1. addSimpleMsgListener
and addAdvancedMsgListener
are exclusive. Do not use both of them; otherwise, unpredictable logic bugs will occur.
2. A message listener must be added first to receive the following types of messages.
Simple message listener
Adding a listener
The receiver calls the 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. Sample code:
V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);
V2TIMManager.shared.addSimpleMsgListener(listener: self)
[[V2TIMManager sharedInstance] addSimpleMsgListener:self];
class SimpleMsgListener final : public V2TIMSimpleMsgListener {
};
SimpleMsgListener simpleMsgListener;
V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
Listener callback event
After adding the simple message listener, the receiver can receive different types of messages in the callback of V2TIMSimpleMsgListener
(Java / Swift / Objective-C / C++), as described below: public abstract class V2TIMSimpleMsgListener {
public void onRecvC2CTextMessage(String msgID, V2TIMUserInfo sender, String text) {}
public void onRecvC2CCustomMessage(String msgID, V2TIMUserInfo sender, byte[] customData) {}
public void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {}
public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {}
}
public protocol V2TIMSimpleMsgListener : AnyObject {
func onRecvC2CTextMessage(msgID: String, sender: V2TIMUserInfo, text: String?)
func onRecvC2CCustomMessage(msgID: String, sender: V2TIMUserInfo, customData: Data?)
func onRecvGroupTextMessage(msgID: String, groupID: String, sender: V2TIMGroupMemberInfo, text: String?)
func onRecvGroupCustomMessage(msgID: String, groupID: String, sender: V2TIMGroupMemberInfo, customData: Data?)
}
@protocol V2TIMSimpleMsgListener <NSObject>
@optional
- (void)onRecvC2CTextMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info text:(NSString *)text;
- (void)onRecvC2CCustomMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info customData:(NSData *)data;
- (void)onRecvGroupTextMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info text:(NSString *)text;
- (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;
void OnRecvC2CTextMessage(const V2TIMString& msgID, const V2TIMUserFullInfo& sender,
const V2TIMString& text) override {}
void OnRecvC2CCustomMessage(const V2TIMString& msgID, const V2TIMUserFullInfo& sender,
const V2TIMBuffer& customData) override {}
void OnRecvGroupTextMessage(const V2TIMString& msgID, const V2TIMString& groupID,
const V2TIMGroupMemberFullInfo& sender, const V2TIMString& text) override {}
void OnRecvGroupCustomMessage(const V2TIMString& msgID, const V2TIMString& groupID,
const V2TIMGroupMemberFullInfo& sender,
const V2TIMBuffer& customData) override {}
};
Removing a listener
To stop receiving messages, the receiver can call removeSimpleMsgListener
(Java / Swift / Objective-C / C++) to remove the simple message listener. Sample code:
V2TIMManager.getInstance().removeSimpleMsgListener(simpleMsgListener);
V2TIMManager.shared.removeSimpleMsgListener(listener: self)
[[V2TIMManager sharedInstance] removeSimpleMsgListener:self];
class SimpleMsgListener final : public V2TIMSimpleMsgListener {
};
V2TIMManager::GetInstance()->RemoveSimpleMsgListener(&simpleMsgListener);
Advanced message listener
Adding a listener
The receiver calls the 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. Sample code:
V2TIMManager.getMessageManager().addAdvancedMsgListener(advancedMsgListener);
V2TIMManager.shared.addAdvancedMsgListener(listener: self)
[[V2TIMManager sharedInstance] addAdvancedMsgListener:self];
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
Listener callback event
After adding the advanced message listener, the receiver can receive different types of messages in the callback of V2TIMAdvancedMsgListener
(Java / Swift / Objective-C / C++), as described below: public abstract class V2TIMAdvancedMsgListener {
public void onRecvNewMessage(V2TIMMessage msg) {}
public void onRecvC2CReadReceipt(List<V2TIMMessageReceipt> receiptList) {}
public void onRecvMessageReadReceipts(List<V2TIMMessageReceipt> receiptList) {}
public void onRecvMessageRevoked(String msgID) {}
public void onRecvMessageModified(V2TIMMessage msg) {}
}
public protocol V2TIMAdvancedMsgListener: AnyObject {
func onRecvNewMessage(msg: V2TIMMessage)
func onRecvMessageReadReceipts(receiptList: Array<V2TIMMessageReceipt>)
func onRecvC2CReadReceipt(receiptList: Array<V2TIMMessageReceipt>)
func onRecvMessageRevoked(msgID: String, operateUser: V2TIMUserInfo, reason: String?)
func onRecvMessageModified(msg: V2TIMMessage)
}
@protocol V2TIMAdvancedMsgListener <NSObject>
@optional
- (void)onRecvNewMessage:(V2TIMMessage *)msg;
- (void)onRecvMessageReadReceipts:(NSArray<V2TIMMessageReceipt *> *)receiptList;
- (void)onRecvC2CReadReceipt:(NSArray<V2TIMMessageReceipt *> *)receiptList;
- (void)onRecvMessageRevoked:(NSString *)msgID;
- (void)onRecvMessageModified:(V2TIMMessage *)msg;
@end
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {
public:
AdvancedMsgListener() = default;
~AdvancedMsgListener() override = default;
void OnRecvNewMessage(const V2TIMMessage& message) override {}
void OnRecvC2CReadReceipt(const V2TIMMessageReceiptVector& receiptList) override {}
void OnRecvMessageReadReceipts(const V2TIMMessageReceiptVector& receiptList) override {}
void OnRecvMessageRevoked(const V2TIMString& messageID) override {}
void OnRecvMessageModified(const V2TIMMessage& message) override {}
};
Removing a listener
To stop receiving messages, the receiver can call removeAdvancedMsgListener
(Java / Swift / Objective-C / C++) to remove the advanced message listener. Sample code:
V2TIMManager.getMessageManager().removeAdvancedMsgListener(advancedMsgListener);
V2TIMManager.shared.removeAdvancedMsgListener(listener: self)
[[V2TIMManager sharedInstance] removeAdvancedMsgListener:self];
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {
};
V2TIMManager::GetInstance()->GetMessageManager()->RemoveAdvancedMsgListener(&advancedMsgListener);
Receiving a Text Message
Using simple message listener
One-to-one text message
The receiver can receive a one-to-one text message by using the simple message listener in the following steps:
1. Call addSimpleMsgListener
to set the event listener.
3. To stop receiving messages, call removeSimpleMsgListener
to remove the listener. This step is optional and can be performed as needed.
Sample code:
V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);
public void onRecvC2CTextMessage(String msgID, V2TIMUserInfo sender, String text) {
}
V2TIMManager.shared.addSimpleMsgListener(listener: self)
func onRecvC2CTextMessage(msgID: String, sender: V2TIMUserInfo, text: String?) {
}
[[V2TIMManager sharedInstance] addSimpleMsgListener:self];
- (void)onRecvC2CTextMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info text:(NSString *)text {
}
class SimpleMsgListener final : public V2TIMSimpleMsgListener {
public:
void OnRecvC2CTextMessage(const V2TIMString& msgID, const V2TIMUserFullInfo& sender,
const V2TIMString& text) override {
std::cout << "text:" << std::string{text.CString(), text.Size()} << std::endl;
}
};
SimpleMsgListener simpleMsgListener;
V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
Group text message
The receiver can receive a group text message by using the simple message listener in the following steps:
1. Call addSimpleMsgListener
to set the event listener.
3. To stop receiving messages, call removeSimpleMsgListener
to remove the listener. This step is optional and can be performed as needed.
Sample code:
V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);
public void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {
}
V2TIMManager.shared.addSimpleMsgListener(listener: self)
func onRecvGroupTextMessage(msgID: String, groupID: String, sender: V2TIMGroupMemberInfo, text:String?
{
}
[[V2TIMManager sharedInstance] addSimpleMsgListener:self];
- (void)onRecvGroupTextMessage:(NSString *)msgID groupID:(NSString *)groupID sender:(V2TIMGroupMemberInfo *)info text:(NSString *)text {
}
class SimpleMsgListener final : public V2TIMSimpleMsgListener {
public:
void OnRecvGroupTextMessage(const V2TIMString& msgID, const V2TIMString& groupID,
const V2TIMGroupMemberFullInfo& sender, const V2TIMString& text) override {
std::cout << "text:" << std::string{text.CString(), text.Size()} << std::endl;
}
};
SimpleMsgListener simpleMsgListener;
V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
Using advanced message listener
The receiver can receive a one-to-one or group text message by using the advanced message listener in the following steps:
1. Call addAdvancedMsgListener
to set the event listener.
3. To stop receiving messages, call removeAdvancedMsgListener
to remove the listener. This step is optional and can be performed as needed.
Sample code:
V2TIMManager.getMessageManager().addAdvancedMsgListener(advancedMsgListener);
public void onRecvNewMessage(V2TIMMessage msg) {
String groupID = msg.getGroupID();
String userID = msg.getUserID();
if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) {
V2TIMTextElem textElem = msg.getTextElem();
String text = textElem.getText();
Log.i("onRecvNewMessage", "text:" + text);
}
}
V2TIMManager.shared.addAdvancedMsgListener(listener: self)
func onRecvNewMessage(_ msg: V2TIMMessage) {
let groupID = msg.groupID
let userID = msg.userID
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.")
}
if msg.elemType == .V2TIM_ELEM_TYPE_TEXT {
if let textElem = msg.textElem {
let text = textElem.text
print("onRecvNewMessage, text: \(text)")
}
} else {
print("Received a non-text message.")
}
}
[[V2TIMManager sharedInstance] addAdvancedMsgListener:self];
- (void)onRecvNewMessage:(V2TIMMessage *)msg {
NSString *groupID = msg.groupID;
NSString *userID = msg.userID;
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:
void OnRecvNewMessage(const V2TIMMessage& message) override {
V2TIMString groupID = message.groupID;
V2TIMString userID = message.userID;
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;
std::cout << "text:" << std::string{text.CString(), text.Size()} << std::endl;
}
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
Receiving a Custom Message
Using simple message listener
Custom one-to-one message
The receiver can receive a custom one-to-one message by using the simple message listener in the following steps:
1. Call addSimpleMsgListener
to set the event listener.
2. Listen for the onRecvC2CCustomMessage
callback (Java / Swift / Objective-C / C++) to receive custom one-to-one messages. 3. To stop receiving messages, call removeSimpleMsgListener
to remove the listener. This step is optional and can be performed as needed.
Sample code:
public void onRecvC2CCustomMessage(String msgID, V2TIMUserInfo sender, byte[] customData) {
Log.i("onRecvC2CCustomMessage", "msgID:" + msgID + ", from:" + sender.getNickName() + ", content:" + new String(customData));
}
func onRecvC2CCustomMessage(msgID: String, sender: V2TIMUserInfo, customData: Data?) {
}
- (void)onRecvC2CCustomMessage:(NSString *)msgID sender:(V2TIMUserInfo *)info customData:(NSData *)data {
NSLog(@"onRecvC2CCustomMessage, msgID: %@, sender: %@, customData: %@", msgID, info, data);
}
class SimpleMsgListener final : public V2TIMSimpleMsgListener {
public:
void OnRecvC2CCustomMessage(const V2TIMString& msgID, const V2TIMUserFullInfo& sender,
const V2TIMBuffer& customData) override {
std::cout << "customData:"
<< std::string{reinterpret_cast<const char*>(customData.Data()), customData.Size()}
<< std::endl;
}
};
SimpleMsgListener simpleMsgListener;
V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
Custom group message
The receiver can receive a custom group message by using the simple message listener in the following steps:
1. Call addSimpleMsgListener
to set the event listener.
2. Listen for the onRecvGroupCustomMessage
callback (Java / Swift / Objective-C / C++) to receive custom group messages. 3. To stop receiving messages, call removeSimpleMsgListener
to remove the listener. This step is optional and can be performed as needed.
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));
}
func onRecvGroupCustomMessage(msgID: String, groupID: String, sender: V2TIMGroupMemberInfo, customData: Data?) {
}
- (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:
void OnRecvGroupCustomMessage(const V2TIMString& msgID, const V2TIMString& groupID,
const V2TIMGroupMemberFullInfo& sender,
const V2TIMBuffer& customData) override {
std::cout << "customData:"
<< std::string{reinterpret_cast<const char*>(customData.Data()), customData.Size()}
<< std::endl;
}
};
SimpleMsgListener simpleMsgListener;
V2TIMManager::GetInstance()->AddSimpleMsgListener(&simpleMsgListener);
Using advanced message listener
The receiver can receive a custom one-to-one or group message by using the advanced message listener in the following steps:
1. Call addAdvancedMsgListener
to set the event listener.
3. To stop receiving messages, call removeAdvancedMsgListener
to remove the listener. This step is optional and can be performed as needed.
Sample code:
V2TIMManager.getMessageManager().addAdvancedMsgListener(v2TIMAdvancedMsgListener);
public void onRecvNewMessage(V2TIMMessage msg) {
String groupID = msg.getGroupID();
String userID = msg.getUserID();
if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_CUSTOM) {
V2TIMCustomElem customElem = msg.getCustomElem();
String data = new String(customElem.getData());
Log.i("onRecvNewMessage", "customData:" + data);
}
}
V2TIMManager.shared.addAdvancedMsgListener(listener: self)
func onRecvNewMessage(_ msg: V2TIMMessage) {
let groupID = msg.groupID
let userID = msg.userID
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.")
}
if msg.elemType == .V2TIM_ELEM_TYPE_TEXT {
if let textElem = msg.textElem {
let text = textElem.text
print("onRecvNewMessage, text: \(text)")
}
} else {
print("Received a non-text message.")
}
}
[[V2TIMManager sharedInstance] addAdvancedMsgListener:self];
- (void)onRecvNewMessage:(V2TIMMessage *)msg {
NSString *groupID = msg.groupID;
NSString *userID = msg.userID;
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:
void OnRecvNewMessage(const V2TIMMessage& message) override {
V2TIMString groupID = message.groupID;
V2TIMString userID = message.userID;
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;
std::cout << "data:"
<< std::string{reinterpret_cast<const char*>(data.Data()), data.Size()}
<< std::endl;
}
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
The receiver can receive a rich media message only by using the advanced message listener in the following steps:
1. Call the addAdvancedMsgListener
API to set the advanced message listener.
2. Listen for the onRecvNewMessage
callback (Java / Swift / Objective-C / C++) to receive the V2TIMMessage
message. 3. Parse the 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.
4. To stop receiving messages, call removeAdvancedMsgListener
to remove the listener. This step is optional and can be performed as needed.
Image message
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.
After the image message is received, we recommend you call the SDK's downloadImage
(Java / Swift / Objective-C / C++) to download the image and then render it to the UI layer. To avoid repeated download and save resources, we recommend you set the uuid
attribute value of the V2TIMImage
object to the image download path to identify the image.
The following sample code demonstrates how to parse the image content from V2TIMMessage
:
public void onRecvNewMessage(V2TIMMessage msg) {
if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE) {
V2TIMImageElem v2TIMImageElem = msg.getImageElem();
List<V2TIMImageElem.V2TIMImage> imageList = v2TIMImageElem.getImageList();
for (V2TIMImageElem.V2TIMImage v2TIMImage : imageList) {
String uuid = v2TIMImage.getUUID();
int imageType = v2TIMImage.getType();
int size = v2TIMImage.getSize();
int width = v2TIMImage.getWidth();
int height = v2TIMImage.getHeight();
String url = v2TIMImage.getUrl();
String imagePath = "/sdcard/im/image/" + "myUserID" + uuid;
File imageFile = new File(imagePath);
if (!imageFile.exists()) {
v2TIMImage.downloadImage(imagePath, new V2TIMDownloadCallback() {
@Override
public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
}
@Override
public void onError(int code, String desc) {
}
@Override
public void onSuccess() {
}
});
} else {
}
}
}
}
func onRecvNewMessage(_ msg: V2TIMMessage) {
if msg.elemType == .V2TIM_ELEM_TYPE_IMAGE {
guard let imageElem = msg.imageElem else { return }
let imageList = imageElem.imageList
for timImage in imageList {
let uuid = timImage.uuid
let type = timImage.type
let size = timImage.size
let width = timImage.width
let height = timImage.height
let url = timImage.url
let imagePath = NSTemporaryDirectory().appending("testImage\(timImage.uuid)")
if !FileManager.default.fileExists(atPath: imagePath) {
timImage.downloadImage(path: imagePath, progress: { curSize, totalSize in
print("Image download progress:curSize:\(curSize), totalSize: \(totalSize)")
}, succ: {
print("Image download success")
}, fail: { code, msg in
print("failed:code:\(code), msg: \(msg)")
})
} else {
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;
NSArray<V2TIMImage *> *imageList = imageElem.imageList;
for (V2TIMImage *timImage in imageList) {
NSString *uuid = timImage.uuid;
V2TIMImageType type = timImage.type;
int size = timImage.size;
int width = timImage.width;
int height = timImage.height;
NSString * url = timImage.url;
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 downloaded");
} fail:^(int code, NSString *msg) {
NSLog(@"Failed to download the image: code: %d,msg:%@",code,msg);
}];
} else {
}
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) {
auto imageElem = static_cast<V2TIMImageElem*>(elem);
V2TIMImageVector imageList = imageElem->imageList;
for (size_t i = 0; i < imageList.Size(); ++i) {
V2TIMImage& image = imageList[i];
V2TIMString uuid = image.uuid;
V2TIMImageType type = image.type;
uint64_t size = image.size;
uint32_t width = image.width;
uint32_t height = image.height;
V2TIMString url = image.url;
std::filesystem::path imagePath = u8"./File/Image/"s + uuid.CString();
if (!std::filesystem::exists(imagePath)) {
std::filesystem::create_directories(imagePath.parent_path());
auto callback = new DownloadCallback{};
callback->SetCallback(
[=]() {
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
delete callback;
},
[=](uint64_t currentSize, uint64_t totalSize) {
});
image.DownloadImage(imagePath.string().c_str(), callback);
} else {
}
}
}
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
V2TIMString url = image.url;
Video message
After a video message is received, a video preview is displayed on the chat page, and the video is played back after the user clicks the message.
Two steps are required:
1. Download the video screenshot. We recommend you call the SDK's downloadSnapshot
(Java / Swift / Objective-C / C++) for download. 2. Download the video. We recommend you call the SDK's downloadVideo
(Java / Swift / Objective-C / C++) for download. To avoid repeated download and save resources, we recommend you set the videoUUID
attribute value of the V2TIMVideoElem
object to the video download path to identify the video.
The following sample code demonstrates how to parse the video content from V2TIMMessage
:
public void onRecvNewMessage(V2TIMMessage msg) {
if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_VIDEO) {
V2TIMVideoElem v2TIMVideoElem = msg.getVideoElem();
String snapshotUUID = v2TIMVideoElem.getSnapshotUUID();
int snapshotSize = v2TIMVideoElem.getSnapshotSize();
int snapshotWidth = v2TIMVideoElem.getSnapshotWidth();
int snapshotHeight = v2TIMVideoElem.getSnapshotHeight();
String videoUUID = v2TIMVideoElem.getVideoUUID();
int videoSize = v2TIMVideoElem.getVideoSize();
int duration = v2TIMVideoElem.getDuration();
String snapshotPath = "/sdcard/im/snapshot/" + "myUserID" + snapshotUUID;
File snapshotFile = new File(snapshotPath);
if (!snapshotFile.exists()) {
v2TIMVideoElem.downloadSnapshot(snapshotPath, new V2TIMDownloadCallback() {
@Override
public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
}
@Override
public void onError(int code, String desc) {
}
@Override
public void onSuccess() {
}
});
} else {
}
String videoPath = "/sdcard/im/video/" + "myUserID" + videoUUID;
File videoFile = new File(videoPath);
if (!videoFile.exists()) {
v2TIMVideoElem.downloadVideo(videoPath, new V2TIMDownloadCallback() {
@Override
public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
}
@Override
public void onError(int code, String desc) {
}
@Override
public void onSuccess() {
}
});
} else {
}
}
}
func onRecvNewMessage(_ msg: V2TIMMessage) {
if msg.elemType == .V2TIM_ELEM_TYPE_VIDEO {
let videoElem = msg.videoElem
let snapshotUUID = videoElem?.snapshotUUID
let snapshotSize = videoElem?.snapshotSize
let snapshotWidth = videoElem?.snapshotWidth
let snapshotHeight = videoElem?.snapshotHeight
let videoUUID = videoElem?.videoUUID
let videoSize = videoElem?.videoSize
let duration = videoElem?.duration
let snapshotPath = NSTemporaryDirectory().appending("testVideoSnapshot\(snapshotUUID)")
if !FileManager.default.fileExists(atPath: snapshotPath) {
videoElem?.downloadSnapshot(path: snapshotPath, progress: { curSize, totalSize in
print("progress:curSize:\(curSize), totalSize: \(totalSize)")
}, succ: {
print("succ")
}, fail: { code, msg in
print("failed code:\(code), msg: \(msg)")
})
} else {
}
print("video info:snapshotUUID: \(snapshotUUID), snapshotSize: \(snapshotSize), snapshotWidth: \(snapshotWidth), snapshotHeight: \(snapshotHeight), snapshotPath: \(snapshotPath)")
let videoPath = NSTemporaryDirectory().appending("testVideo\(videoUUID)")
if !FileManager.default.fileExists(atPath: videoPath) {
videoElem?.downloadVideo(path: videoPath, progress: { curSize, totalSize in
print("downloadVideo progress curSize:\(curSize), totalSize: \(totalSize)")
}, succ: {
print("downloadVideo success")
}, fail: { code, msg in
print("code:\(code), msg: \(msg)")
})
} else {
}
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;
NSString *snapshotUUID = videoElem.snapshotUUID;
int snapshotSize = videoElem.snapshotSize;
int snapshotWidth = videoElem.snapshotWidth;
int snapshotHeight = videoElem.snapshotHeight;
NSString *videoUUID = videoElem.videoUUID;
int videoSize = videoElem.videoSize;
int duration = videoElem.duration;
NSString *snapshotPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat: @"testVideoSnapshot%@",snapshotUUID]];
if (![[NSFileManager defaultManager] fileExistsAtPath:snapshotPath]) {
[videoElem downloadSnapshot:snapshotPath progress:^(NSInteger curSize, NSInteger totalSize) {
NSLog(@"%@", [NSString stringWithFormat:@"Video screenshot download progress: curSize: %lu,totalSize:%lu",curSize,totalSize]);
} succ:^{
NSLog(@"Video screenshot downloaded");
} fail:^(int code, NSString *msg) {
NSLog(@"%@", [NSString stringWithFormat:@"Failed to download the video screenshot: code: %d,msg:%@",code,msg]);
}];
} else {
}
NSLog(@"Video screenshot information: snapshotUUID:%@, snapshotSize:%d, snapshotWidth:%d, snapshotWidth:%d, snapshotPath:%@", snapshotUUID, snapshotSize, snapshotWidth, snapshotHeight, snapshotPath);
NSString *videoPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat: @"testVideo%@",videoUUID]];
if (![[NSFileManager defaultManager] fileExistsAtPath:videoPath]) {
[videoElem downloadVideo:videoPath progress:^(NSInteger curSize, NSInteger totalSize) {
NSLog(@"%@", [NSString stringWithFormat:@"Video download progress: curSize: %lu,totalSize:%lu",curSize,totalSize]);
} succ:^{
NSLog(@"Video downloaded");
} fail:^(int code, NSString *msg) {
NSLog(@"%@", [NSString stringWithFormat:@"Failed to download the video: code: %d,msg:%@",code,msg]);
}];
} else {
}
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) {
auto videoElem = static_cast<V2TIMVideoElem*>(elem);
V2TIMString videoUUID = videoElem->videoUUID;
uint64_t videoSize = videoElem->videoSize;
V2TIMString videoType = videoElem->videoType;
uint32_t duration = videoElem->duration;
V2TIMString snapshotUUID = videoElem->snapshotUUID;
uint64_t snapshotSize = videoElem->snapshotSize;
uint32_t snapshotWidth = videoElem->snapshotWidth;
uint32_t snapshotHeight = videoElem->snapshotHeight;
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(
[=]() {
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
delete callback;
},
[=](uint64_t currentSize, uint64_t totalSize) {
});
videoElem->DownloadVideo(videoPath.string().c_str(), callback);
} else {
}
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(
[=]() {
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
delete callback;
},
[=](uint64_t currentSize, uint64_t totalSize) {
});
videoElem->DownloadSnapshot(snapshotPath.string().c_str(), callback);
} else {
}
}
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
Audio message
After the audio message is received, we recommend you call the SDK's downloadSound
(Java / Swift / Objective-C / C++) to download the audio and then play it back. To avoid repeated download and save resources, we recommend you set the uuid
attribute value of the V2TIMSoundElem
object to the audio download path to identify the audio.
The following sample code demonstrates how to parse the audio content from V2TIMMessage
:
public void onRecvNewMessage(V2TIMMessage msg) {
if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_SOUND) {
V2TIMSoundElem v2TIMSoundElem = msg.getSoundElem();
String uuid = v2TIMSoundElem.getUUID();
int dataSize = v2TIMSoundElem.getDataSize();
int duration = v2TIMSoundElem.getDuration();
String soundPath = "/sdcard/im/sound/" + "myUserID" + uuid;
File imageFile = new File(soundPath);
if (!imageFile.exists()) {
v2TIMSoundElem.downloadSound(soundPath, new V2TIMDownloadCallback() {
@Override
public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
}
@Override
public void onError(int code, String desc) {
}
@Override
public void onSuccess() {
}
});
} else {
}
}
}
func onRecvNewMessage(_ msg: V2TIMMessage) {
if msg.elemType == .V2TIM_ELEM_TYPE_SOUND {
guard let soundElem = msg.soundElem else { return }
let uuid = soundElem.uuid
let dataSize = soundElem.dataSize
let duration = soundElem.duration
let soundPath = NSTemporaryDirectory().appending("testSound\(uuid)")
if !FileManager.default.fileExists(atPath: soundPath) {
soundElem.downloadSound(path: soundPath, progress: { curSize, totalSize in
print("Download progress:curSize:\(curSize), totalSize: \(totalSize)")
}, succ: {
print("Download success")
}, fail: { code, msg in
print("error code:\(code), msg: \(msg)")
})
} else {
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;
NSString *uuid = soundElem.uuid;
int dataSize = soundElem.dataSize;
int duration = soundElem.duration;
NSString *soundPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat: @"testSound%@",uuid]];
if (![[NSFileManager defaultManager] fileExistsAtPath:soundPath]) {
[soundElem downloadSound:soundPath progress:^(NSInteger curSize, NSInteger totalSize) {
NSLog(@"Audio download progress: curSize: %lu,totalSize:%lu",curSize,totalSize);
} succ:^{
NSLog(@"Audio downloaded");
} fail:^(int code, NSString *msg) {
NSLog(@"Failed to download the audio: code: %d,msg:%@",code,msg);
}];
} else {
}
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) {
auto soundElem = static_cast<V2TIMSoundElem*>(elem);
V2TIMString uuid = soundElem->uuid;
uint64_t dataSize = soundElem->dataSize;
uint32_t duration = soundElem->duration;
std::filesystem::path soundPath = u8"./File/Sound/"s + uuid.CString();
if (!std::filesystem::exists(soundPath)) {
std::filesystem::create_directories(soundPath.parent_path());
auto callback = new DownloadCallback{};
callback->SetCallback(
[=]() {
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
delete callback;
},
[=](uint64_t currentSize, uint64_t totalSize) {
});
soundElem->DownloadSound(soundPath.string().c_str(), callback);
} else {
}
}
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
File message
After the file message is received, we recommend you call the SDK's downloadFile
(Java / Swift / Objective-C / C++) to download the file and then display it. To avoid repeated download and save resources, we recommend you set the uuid
attribute value of the V2TIMFileElem
object to the file download path to identify the file.
The following sample code demonstrates how to parse the file content from V2TIMMessage
:
public void onRecvNewMessage(V2TIMMessage msg) {
if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_FILE) {
V2TIMFileElem v2TIMFileElem = msg.getFileElem();
String uuid = v2TIMFileElem.getUUID();
String fileName = v2TIMFileElem.getFileName();
int fileSize = v2TIMFileElem.getFileSize();
String filePath = "/sdcard/im/file/" + "myUserID" + uuid;
File file = new File(filePath);
if (!file.exists()) {
v2TIMFileElem.downloadFile(filePath, new V2TIMDownloadCallback() {
@Override
public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
}
@Override
public void onError(int code, String desc) {
}
@Override
public void onSuccess() {
}
});
} else {
}
}
}
func onRecvNewMessage(_ msg: V2TIMMessage) {
if msg.elemType == .V2TIM_ELEM_TYPE_FILE {
guard let fileElem = msg.fileElem else { return }
let uuid = fileElem.uuid
let filename = fileElem.filename
let fileSize = fileElem.fileSize
let filePath = NSTemporaryDirectory().appending("testFile\(uuid)")
if !FileManager.default.fileExists(atPath: filePath) {
fileElem.downloadFile(path: filePath, progress: { curSize, totalSize in
print("downloadFile progress:curSize:\(curSize), totalSize: \(totalSize)")
}, succ: {
print("downloadFile success")
}, fail: { code, msg in
print("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;
NSString *uuid = fileElem.uuid;
NSString *filename = fileElem.filename;
int fileSize = fileElem.fileSize;
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat: @"testFile%@",uuid]];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[fileElem downloadFile:filePath progress:^(NSInteger curSize, NSInteger totalSize) {
NSLog(@"%@", [NSString stringWithFormat:@"File download progress: curSize: %lu,totalSize:%lu",curSize,totalSize]);
} succ:^{
NSLog(@"File downloaded");
} fail:^(int code, NSString *msg) {
NSLog(@"%@", [NSString stringWithFormat:@"Failed to download the file: code: %d,msg:%@",code,msg]);
}];
} else {
}
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) {
auto fileElem = static_cast<V2TIMFileElem*>(elem);
V2TIMString uuid = fileElem->uuid;
V2TIMString filename = fileElem->filename;
uint64_t fileSize = fileElem->fileSize;
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(
[=]() {
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
delete callback;
},
[=](uint64_t currentSize, uint64_t totalSize) {
});
fileElem->DownloadFile(filePath.string().c_str(), callback);
} else {
}
}
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
Location message
After receiving the location message, the receiver can parse the latitude and longitude information directly from 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) {
V2TIMLocationElem v2TIMLocationElem = msg.getLocationElem();
String desc = v2TIMLocationElem.getDesc();
double longitude = v2TIMLocationElem.getLongitude();
double latitude = v2TIMLocationElem.getLatitude();
}
}
func onRecvNewMessage(_ msg: V2TIMMessage) {
if msg.elemType == .V2TIM_ELEM_TYPE_LOCATION {
let locationElem = msg.locationElem
let desc = locationElem?.desc
let longitude = locationElem?.longitude
let latitude = locationElem?.latitude
print("location info:desc:\(desc), longitude:\(longitude), latitude:\(latitude)")
}
}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {
if (msg.elemType == V2TIM_ELEM_TYPE_LOCATION) {
V2TIMLocationElem *locationElem = msg.locationElem;
NSString *desc = locationElem.desc;
double longitude = locationElem.longitude;
double 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) {
auto locationElem = static_cast<V2TIMLocationElem*>(elem);
V2TIMString desc = locationElem->desc;
double longitude = locationElem->longitude;
double latitude = locationElem->latitude;
}
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
Emoji message
The SDK provides a passthrough channel only for emoji messages. For message content fields, see the definition of V2TIMFaceElem
(Java / Swift / Objective-C / C++). Here, index
and data
can be customized. For example, the sender can set 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.
The following sample code demonstrates how to parse the emoji content from V2TIMMessage
:
public void onRecvNewMessage(V2TIMMessage msg) {
if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_FACE) {
V2TIMFaceElem v2TIMFaceElem = msg.getFaceElem();
int index = v2TIMFaceElem.getIndex();
byte[] data = v2TIMFaceElem.getData();
}
}
func onRecvNewMessage(_ msg: V2TIMMessage) {
guard msg.elemType == .V2TIM_ELEM_TYPE_FACE, let faceElem = msg.faceElem else {
return
}
let index = faceElem.index
guard 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;
int index = faceElem.index;
NSData *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) {
auto faceElem = static_cast<V2TIMFaceElem*>(elem);
uint32_t index = faceElem->index;
V2TIMBuffer data = faceElem->data;
}
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
Receiving a Broadcast Message
You can only use the Broadcast Message of Audio-Video Group to send broadcast messages to all AVChatRooms under the same AppID, and all online group members in the AVChatRooms can receive this message. The SDK cannot send broadcast messages, it can only receive messages from the REST API. The receiving of messages is still in the onRecvNewMessage
notification mentioned earlier. After receiving a message, you can determine whether the message is a broadcast message based on the isBroadcastMessage
property. Note:
2. This feature is available only in SDK enhanced edition v6.5.2803 or later.
3. Only AVChatRoom supports broadcast message, other types of group are temporarily not supported.
public void onRecvNewMessage(V2TIMMessage msg) {
if (msg.isBroadcastMessage) {
}
}
func onRecvNewMessage(_ msg: V2TIMMessage) {
if msg.isBroadcastMessage {
}
}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {
if (msg.isBroadcastMessage) {
}
}
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {
public:
void OnRecvNewMessage(const V2TIMMessage& message) override {
if (message.isBroadcastMessage) {
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);
Receiving a Message Containing Multiple Elements
1. Parse the first element object through the Message object.
2. Get the next element object through the nextElem
method of the first element object. If the next object exists, an element object instance is returned; otherwise, nil
or null
is returned.
Sample code:
@Override
public void onRecvNewMessage(V2TIMMessage msg) {
int elemType = msg.getElemType();
if (elemType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) {
V2TIMTextElem v2TIMTextElem = msg.getTextElem();
String text = v2TIMTextElem.getText();
V2TIMElem elem = v2TIMTextElem.getNextElem();
while (elem != null) {
if (elem instanceof V2TIMCustomElem) {
V2TIMCustomElem customElem = (V2TIMCustomElem) elem;
byte[] data = customElem.getData();
}
elem = elem.getNextElem();
}
}
}
func onRecvNewMessage(_ msg: V2TIMMessage) {
if msg.elemType == .V2TIM_ELEM_TYPE_TEXT {
let textElem = msg.textElem
let text = textElem?.text
print("text : \(text)")
var elem: V2TIMElem? = textElem?.getNextElem()
while elem != nil {
if let customElem = elem as? V2TIMCustomElem {
let customData = customElem.data
print("Custom information : \(customData)")
}
elem = elem?.getNextElem()
}
}
}
- (void)onRecvNewMessage:(V2TIMMessage *)msg {
if (msg.elemType == V2TIM_ELEM_TYPE_TEXT) {
V2TIMTextElem *textElem = msg.textElem;
NSString *text = textElem.text;
NSLog(@"Text information: %@", text);
V2TIMElem *elem = textElem.nextElem;
while (elem != nil) {
if ([elem isKindOfClass:[V2TIMCustomElem class]]) {
V2TIMCustomElem *customElem = (V2TIMCustomElem *)elem;
NSData *customData = customElem.data;
NSLog(@"Custom information: %@",customData);
}
elem = elem.nextElem;
}
}
}
class AdvancedMsgListener final : public V2TIMAdvancedMsgListener {
public:
void OnRecvNewMessage(const V2TIMMessage& message) override {
for (size_t i = 0; i < message.elemList.Size(); ++i) {
V2TIMElem* elem = message.elemList[i];
switch (elem->elemType) {
case V2TIMElemType::V2TIM_ELEM_TYPE_NONE: {
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_TEXT: {
auto textElem = static_cast<V2TIMTextElem*>(elem);
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_CUSTOM: {
auto customElem = static_cast<V2TIMCustomElem*>(elem);
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_IMAGE: {
auto imageElem = static_cast<V2TIMImageElem*>(elem);
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_SOUND: {
auto soundElem = static_cast<V2TIMSoundElem*>(elem);
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_VIDEO: {
auto videoElem = static_cast<V2TIMVideoElem*>(elem);
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_FILE: {
auto fileElem = static_cast<V2TIMFileElem*>(elem);
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_LOCATION: {
auto locationElem = static_cast<V2TIMLocationElem*>(elem);
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_FACE: {
auto faceElem = static_cast<V2TIMFaceElem*>(elem);
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_GROUP_TIPS: {
auto mergerElem = static_cast<V2TIMMergerElem*>(elem);
} break;
case V2TIMElemType::V2TIM_ELEM_TYPE_MERGER: {
auto groupTipsElem = static_cast<V2TIMGroupTipsElem*>(elem);
} break;
default: {
} break;
}
}
}
};
AdvancedMsgListener advancedMsgListener;
V2TIMManager::GetInstance()->GetMessageManager()->AddAdvancedMsgListener(&advancedMsgListener);