收发消息
功能简介
本文档适用于开发以下平台的应用:iOS、Android、macOS、Windows、Web。
ZIM SDK 支持单聊消息、群组消息、房间消息等的收发,以及查询历史消息、删除消息等功能。可广泛应用于娱乐社交、电商购物、在线教育、互动直播等多种场景下。
本文档介绍了如何使用 ZIM SDK 的接口,实现各类消息的收发功能与监听消息的状态。
消息类型
目前 ZIM 支持的消息类型如下:
| 消息类型 | 说明 | 特性及适用场景 | 
|---|---|---|
| ZIMCommandMessage(2) | 开发者可自定义数据内容的信令消息。消息大小不超过 5 KB。 | 限频:单个客户端发送频率限制为 10 次/秒(两次之间间隔 100 毫秒)。 不可存储,一般适用于“语聊房”、“在线课堂”等房间内的信令传输,比如上下麦操作、送礼物,发送在线课堂课件等。 支持更高的并发,但不可靠,不保证消息送达和消息顺序。 相关接口:sendMessage | 
| ZIMBarrageMessage(20) | 房间内弹幕文本消息。消息大小不超过 5 KB。 | 限频:单个客户端发送频率无限制。 不可存储,专门用于房间内的高频、不可靠、允许丢掉的消息,一般适用于发送“弹幕消息”的场景中。 支持高并发,但不可靠,不保证消息送达。 相关接口:sendMessage | 
| ZIMTextMessage(1) | 文本消息。消息大小上限默认为 2 KB。如有需要,请联系 ZEGO 技术支持配置,最大可达 32 KB。 | 限频:单个客户端发送频率限制为 10 次/秒(两次之间间隔 100 毫秒)。 消息可靠有序,可存储为历史消息(保存时间请参考 计费说明 - 版本差异 中“历史消息存储天数”)。 
 相关接口:sendMessage、replyMessage | 
| ZIMMultipleMessage(10) | 组合消息,即包含多个 item 的消息,可包括多条文本、至多 10 张图片、1 个文件、1 个音频、1 个视频和 1 条自定义消息。 说明 
 | |
| ZIMImageMessage(11) | 图片消息。支持主流图片格式,包括 JPG、PNG、BMP、TIFF、GIF、WebP,大小不超过 10 MB。 | |
| ZIMFileMessage(12) | 文件消息。消息内容为文件,格式不限,大小不超过 100 MB。 | |
| ZIMAudioMessage(13) | 语音消息。支持 MP3、M4A 格式的语音文件,时长不超过 300 秒,大小不超过 6 MB。 | |
| ZIMVideoMessage(14) | 视频消息。支持 MP4、MOV 格式的视频文件,大小不超过 100 MB。 说明 若要在消息发送成功后获取视频首帧的宽高信息,视频必须使用 H.264 或 H.265 编码格式。 | |
| ZIMCombineMessage(100) | 合并消息,消息大小无限制。 | |
| ZIMCustomMessage(200) | 自定义消息。消息大小上限默认为 2 KB。如有需要,请联系 ZEGO 技术支持配置,最大可达 32 KB。开发者可自定义消息的类型,并自行完成消息的解析,ZIM SDK 不负责定义和解析自定义消息的具体内容。 | 
发送消息
以客户端 A 向客户端 B 发送消息为例:

- 客户端 A、B 分别创建自己的 ZIM 实例,并注册 on 监听的 peerMessageReceived 回调接口,用于接收单聊消息通知。
- 客户端 A、B 分别创建自己的 ZIM 实例,并监听 peerMessageReceived 回调接口,用于接收单聊消息通知。
- 客户端 A、B 分别登录 ZIM SDK。
- 客户端 A 调用 sendMessage 接口,设置 conversationType为ZIMConversationType.Peer发送一条单聊消息到客户端 B。
- 客户端 B 将通过 peerMessageReceived 回调接口,收到客户端 A 的消息。
发送消息时,统一使用 sendMessage 接口,并根据会话类型传入对应的 conversationType 取值。
目前,ZIM SDK 对于 sendMessage 接口有以下限制:
- 不支持向自己发送消息:即 toConversationID不能设置为调用者自己的用户 ID。
- 不支持发送空白消息:消息内容不能为空或空白。 当出现上述两种情况时,ZIM SDK 会返回错误 6000001,并提示传入参数错误。
普通消息
普通消息是指消息内容为文本的消息,包含 ZIMTextMessage、ZIMBarrageMessage 消息类型。
示例代码
// 发送单聊 `Text` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
String toConversationID = "xxxx1";
ZIMTextMessage zimMessage = new ZIMTextMessage();
zimMessage.message = "消息内容";
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 设置消息的离线推送配置
ZIMPushConfig pushConfig = new ZIMPushConfig();
pushConfig.title = "离线推送的标题";
pushConfig.content= "离线推送的内容";
pushConfig.extendedData = "离线推送的扩展信息";
config.pushConfig = pushConfig;
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(zimMessage, toConversationID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});// 发送单聊 `Text` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
String toConversationID = "xxxx1";
ZIMTextMessage zimMessage = new ZIMTextMessage();
zimMessage.message = "消息内容";
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 设置消息的离线推送配置
ZIMPushConfig pushConfig = new ZIMPushConfig();
pushConfig.title = "离线推送的标题";
pushConfig.content= "离线推送的内容";
pushConfig.extendedData = "离线推送的扩展信息";
config.pushConfig = pushConfig;
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(zimMessage, toConversationID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});示例代码
// 发送单聊 `Text` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
NSString *toConversationID = @"xxxx1";
ZIMTextMessage *textMessage = [[ZIMTextMessage alloc] init];
textMessage.message = @"消息内容";
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
// 设置消息优先级
config.priority = ZIMMessagePriorityLow;
// 设置消息的离线推送配置。若使用该功能,需要先开通离线推送服务
ZIMPushConfig *pushConfig = [[ZIMPushConfig alloc] init];
pushConfig.title = @"离线推送的标题";
pushConfig.content= @"离线推送的内容";
pushConfig.extendedData = @"离线推送的扩展信息";
config.pushConfig = pushConfig
ZIMMessageSendNotification *notification = [[ZIMMessageSendNotification alloc] init];
notification.onMessageAttached = ^(ZIMMessage * _Nonnull message) {
    // 发送前的回调,客户可以在这里获取一个临时对象,该对象与开发者创建的 zimMessage 对象属于同一对象,开发者可利用此特性做一些业务逻辑,如提前展示 UI 等
};
ZIMConversationType type = ZIMConversationTypePeer;
[self.zim sendMessage:textMessage toConversationID:toConversationID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];// 发送单聊 `Text` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
NSString *toConversationID = @"xxxx1";
ZIMTextMessage *textMessage = [[ZIMTextMessage alloc] init];
textMessage.message = @"消息内容";
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
// 设置消息优先级
config.priority = ZIMMessagePriorityLow;
// 设置消息的离线推送配置。若使用该功能,需要先开通离线推送服务
ZIMPushConfig *pushConfig = [[ZIMPushConfig alloc] init];
pushConfig.title = @"离线推送的标题";
pushConfig.content= @"离线推送的内容";
pushConfig.extendedData = @"离线推送的扩展信息";
config.pushConfig = pushConfig
ZIMMessageSendNotification *notification = [[ZIMMessageSendNotification alloc] init];
notification.onMessageAttached = ^(ZIMMessage * _Nonnull message) {
    // 发送前的回调,客户可以在这里获取一个临时对象,该对象与开发者创建的 zimMessage 对象属于同一对象,开发者可利用此特性做一些业务逻辑,如提前展示 UI 等
};
ZIMConversationType type = ZIMConversationTypePeer;
[self.zim sendMessage:textMessage toConversationID:toConversationID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];示例代码
// 发送单聊 `Text` 信息
zim::ZIMMessage* message = nullptr;
zim::ZIMTextMessage text_message;
text_message.message = "message";
// 设置消息优先级
zim::ZIMMessageSendConfig config;
config.priority = zim::ZIM_MESSAGE_PRIORITY_LOW;
message = &text_message;
zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { int i = 0; });
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
zim_->sendMessage(message, "toConversationID", type, config, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                              const zim::ZIMError &errorInfo) { int i = 0; });// 发送单聊 `Text` 信息
zim::ZIMMessage* message = nullptr;
zim::ZIMTextMessage text_message;
text_message.message = "message";
// 设置消息优先级
zim::ZIMMessageSendConfig config;
config.priority = zim::ZIM_MESSAGE_PRIORITY_LOW;
message = &text_message;
zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { int i = 0; });
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
zim_->sendMessage(message, "toConversationID", type, config, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                              const zim::ZIMError &errorInfo) { int i = 0; });示例代码
// 发送单聊 `Text` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageTextObj: ZIMMessage = {
    type: 1,
    message: 'xxxx'
};
zim.sendMessage(messageTextObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 发送单聊 `Text` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageTextObj: ZIMMessage = {
    type: 1,
    message: 'xxxx'
};
zim.sendMessage(messageTextObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });示例代码
// 发送单聊 `Text` 信息
// conversationType 设置为 ZIMConversationType.peer
ZIMTextMessage textMessage = ZIMTextMessage(message: "message");
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
// 设置消息优先级
sendConfig.priority = ZIMMessagePriority.low;
ZIMPushConfig pushConfig = ZIMPushConfig();
pushConfig.title = "离线推送的标题";
pushConfig.content = "离线推送的内容";
pushConfig.extendedData = "离线推送的扩展信息";
sendConfig.pushConfig = pushConfig;
ZIMMessageSendNotification notification = ZIMMessageSendNotification(onMessageAttached: (message){
    // 发送前的回调,开发者可以在这里获取一个临时对象,该对象与开发者创建的 zimMessage 对象属于同一对象,开发者可利用此特性做一些业务逻辑,如提前展示 UI 等
});
// 设置会话类型,选择其一向对应的会话类型发送消息
ZIMConversationType type = ZIMConversationType.peer;
ZIM.getInstance()!.sendMessage(textMessage, toConversationID, type, sendConfig).then((value) => {
    // 开发者可以通过该回调监听消息是否发送成功。
}).catchError((onError){
    // 开发者可以捕获发送失败的异常。
});// 发送单聊 `Text` 信息
// conversationType 设置为 ZIMConversationType.peer
ZIMTextMessage textMessage = ZIMTextMessage(message: "message");
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
// 设置消息优先级
sendConfig.priority = ZIMMessagePriority.low;
ZIMPushConfig pushConfig = ZIMPushConfig();
pushConfig.title = "离线推送的标题";
pushConfig.content = "离线推送的内容";
pushConfig.extendedData = "离线推送的扩展信息";
sendConfig.pushConfig = pushConfig;
ZIMMessageSendNotification notification = ZIMMessageSendNotification(onMessageAttached: (message){
    // 发送前的回调,开发者可以在这里获取一个临时对象,该对象与开发者创建的 zimMessage 对象属于同一对象,开发者可利用此特性做一些业务逻辑,如提前展示 UI 等
});
// 设置会话类型,选择其一向对应的会话类型发送消息
ZIMConversationType type = ZIMConversationType.peer;
ZIM.getInstance()!.sendMessage(textMessage, toConversationID, type, sendConfig).then((value) => {
    // 开发者可以通过该回调监听消息是否发送成功。
}).catchError((onError){
    // 开发者可以捕获发送失败的异常。
});富媒体消息
ZIM SDK 支持发送多种类型的富媒体消息,包含图片、文件、音频、视频等消息类型,开发者可以通过以下步骤实现富媒体文件消息的收发。
- 用户登录成功后,指定消息类型(图片、文件、音频、视频)、会话类型(单聊、房间、群组)等,向指定会话发送富媒体消息。
- 接收方用户登录成功后,根据会话类型(单聊、房间、群组)的相关回调监听,接收富媒体消息的相关通知,以及下载富媒体消息文件到本地。
- 用户登录成功后,指定消息类型(图片、文件、音频、视频)、会话类型(单聊、房间、群组)等,向指定会话发送富媒体消息。
- 接收方用户登录成功后,根据会话类型(单聊、房间、群组)的相关回调监听,接收富媒体消息的相关通知。
- 发送富媒体消息时,填写的待发送文件路径,必须使用 UTF-8编码格式和本地文件的绝对路径。
- 如果需要向房间/群组内发送富媒体消息,消息发送者必须要在这个房间/群组内。
- 本地图片(通过 fileLocalPath发送) 图片将上传至 ZEGO 服务器,并自动生成fileDownloadURL(发送方需在消息发送成功的回调中,通过 ZIMMessage 对象获取该 URL)。发送方和接收方均能通过fileDownloadURL下载原图(即使发送方本地图片已删除,仍可通过该 URL 重新获取)。
- 网络图片(通过 fileDownloadURL直接发送) 不会经过 ZEGO 服务器中转,SDK 仅透传该 URL,不会生成新的服务端下载地址。需要确保该 URL 是公网可访问的有效地址,接收方需自行处理图片加载(如缓存、防失效等)。
- 若发送方发送本地图片后删除了手机中的原图,可通过 fileDownloadURL 重新下载;
- 若需降低服务器存储成本,或图片需实时更新(如动态生成的海报),可直接发送网络图片 URL。
图片消息
// 发送富媒体消息消息示例 - 单聊 发送图片消息
ZIMImageMessage message = new ZIMImageMessage("/storage/emulated/0/Android/data/packagename/picture/xxx.jpg");
// 如果此处填了网络 URL,SDK 则会透传该路径,而不会经过 ZIM 后台服务处理,同时填入网络 URL 与本地路径,SDK 会优先认为用户想要使用网络 URL
message.setLargeImageDownloadUrl("url");
message.setFileDownloadUrl("url");
message.setThumbnailDownloadUrl("url");
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 设置消息的离线推送配置
// 不支持设置房间消息的离线推送配置,如果需要发送房间离线消息,请联系 ZEGO 技术支持开通相关权限
ZIMPushConfig pushConfig = new ZIMPushConfig();
pushConfig.title = "离线推送的标题";
pushConfig.content= "离线推送的内容";
pushConfig.extendedData = "离线推送的扩展信息";
config.pushConfig = pushConfig;
zim.sendMessage(message, toConversationID, ZIMConversationType.PEER, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage message) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage message, ZIMError errorInfo){
        // 开发者可以通过该回调监听消息是否发送成功。
    }
    @Override
    public void onMediaUploadingProgress(ZIMMediaMessage message, long currentFileSize, long totalFileSize, ) {
        // 开发者可以通过该回调监听文件上传进度。               
    }
});// 发送富媒体消息消息示例 - 单聊 发送图片消息
ZIMImageMessage message = new ZIMImageMessage("/storage/emulated/0/Android/data/packagename/picture/xxx.jpg");
// 如果此处填了网络 URL,SDK 则会透传该路径,而不会经过 ZIM 后台服务处理,同时填入网络 URL 与本地路径,SDK 会优先认为用户想要使用网络 URL
message.setLargeImageDownloadUrl("url");
message.setFileDownloadUrl("url");
message.setThumbnailDownloadUrl("url");
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 设置消息的离线推送配置
// 不支持设置房间消息的离线推送配置,如果需要发送房间离线消息,请联系 ZEGO 技术支持开通相关权限
ZIMPushConfig pushConfig = new ZIMPushConfig();
pushConfig.title = "离线推送的标题";
pushConfig.content= "离线推送的内容";
pushConfig.extendedData = "离线推送的扩展信息";
config.pushConfig = pushConfig;
zim.sendMessage(message, toConversationID, ZIMConversationType.PEER, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage message) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage message, ZIMError errorInfo){
        // 开发者可以通过该回调监听消息是否发送成功。
    }
    @Override
    public void onMediaUploadingProgress(ZIMMediaMessage message, long currentFileSize, long totalFileSize, ) {
        // 开发者可以通过该回调监听文件上传进度。               
    }
});图片
// 发送多媒体消息示例 - 单聊 发送图片消息
ZIMImageMessage *imgMsg = [[ZIMImageMessage alloc] init];
//需填入 UTF-8 格式的本地路径(建议填写 app 本地图片的路径)
//此处以一个相册图片临时路径为例
imgMsg.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/C142EFE6-9DEC-449D-89B7-BF99F2578F98/tmp/D1513E30-2641-440B-B897-48CD43BE1D04.jpeg";
//如果此处填入了网络 URL, SDK 会透传该路径,而不会经过 ZIM 后台服务处理, 同时填入网络 URL 与本地路径,SDK 会优先认为用户想要使用网路 URL
imgMsg.fileDownloadUrl = @"";
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc] init];
sendConfig.priority = 1;
        
ZIMMessageSendNotification *notification = [[ZIMMessageSendNotification alloc] init];
notification.onMessageAttached = ^(ZIMMessage * _Nonnull message) {
    // 开发者可以监听这个回调执行消息发送前的业务逻辑
};
        
notification.onMediaUploadingProgress = ^(ZIMMediaMessage * _Nonnull message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
    // 开发者可以监听这个回调获取多媒体上传的进度
};
[[ZIM getInstance] sendMessage:imgMsg toConversationID:@"conversationID" conversationType:ZIMConversationTypePeer config:sendConfig notification:notification callback:^(ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo) {
        
}];// 发送多媒体消息示例 - 单聊 发送图片消息
ZIMImageMessage *imgMsg = [[ZIMImageMessage alloc] init];
//需填入 UTF-8 格式的本地路径(建议填写 app 本地图片的路径)
//此处以一个相册图片临时路径为例
imgMsg.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/C142EFE6-9DEC-449D-89B7-BF99F2578F98/tmp/D1513E30-2641-440B-B897-48CD43BE1D04.jpeg";
//如果此处填入了网络 URL, SDK 会透传该路径,而不会经过 ZIM 后台服务处理, 同时填入网络 URL 与本地路径,SDK 会优先认为用户想要使用网路 URL
imgMsg.fileDownloadUrl = @"";
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc] init];
sendConfig.priority = 1;
        
ZIMMessageSendNotification *notification = [[ZIMMessageSendNotification alloc] init];
notification.onMessageAttached = ^(ZIMMessage * _Nonnull message) {
    // 开发者可以监听这个回调执行消息发送前的业务逻辑
};
        
notification.onMediaUploadingProgress = ^(ZIMMediaMessage * _Nonnull message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
    // 开发者可以监听这个回调获取多媒体上传的进度
};
[[ZIM getInstance] sendMessage:imgMsg toConversationID:@"conversationID" conversationType:ZIMConversationTypePeer config:sendConfig notification:notification callback:^(ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo) {
        
}];图片
// 发送多媒体消息示例 - 单聊 发送图片消息
zim::ZIMMediaMessage *message = nullptr;
auto imageMessage = zim::ZIMImageMessage();
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
// 离线推送标题,需要离线推送时,请填入该字段
pushConfig.title = "win_push_title";
// 离线推送内容,需要离线推送时,请填入该字段
pushConfig.content = "win_push_content";
// 离线推送附加字段,需要离线推送带上额外信息时,可酌情填入该字段
pushConfig.extendedData = "win_push_extended_data";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
// 需要离线推送时赋值;如不需要,可赋值为 nullptr
sendConfig.pushConfig = &pushConfig;
// 需填入 UTF-8 格式的本地路径
imageMessage.fileLocalPath = "D:\\image\\img.jpg";
// 如果此处填入了网络 URL,SDK 则会透传该路径,而不会经过 ZIM 后台服务处理。同时填入网络 URL 与本地路径,SDK 会优先认为用户想要使用网络 URL
imageMessage.fileDownloadUrl = "";
imageMessage.largeImageDownloadUrl = "";
imageMessage.thumbnailDownloadUrl = "";
message = &imageMessage;
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { 
                // 开发者可监听此回调,执行消息发送前的逻辑
            },
            [=](const std::shared_ptr<zim::ZIMMediaMessage> &message,
                unsigned long long currentFileSize,
                unsigned long long totalFileSize) { 
                // 开发者可监听此回调,获取文件上传的进度
            });
zim_->sendMessage(message, receiver_id, zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
    sendConfig,notification,
    [=](const std::shared_ptr<zim::ZIMMessage> &message, const zim::ZIMError &errorInfo) {
        
    });// 发送多媒体消息示例 - 单聊 发送图片消息
zim::ZIMMediaMessage *message = nullptr;
auto imageMessage = zim::ZIMImageMessage();
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
// 离线推送标题,需要离线推送时,请填入该字段
pushConfig.title = "win_push_title";
// 离线推送内容,需要离线推送时,请填入该字段
pushConfig.content = "win_push_content";
// 离线推送附加字段,需要离线推送带上额外信息时,可酌情填入该字段
pushConfig.extendedData = "win_push_extended_data";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
// 需要离线推送时赋值;如不需要,可赋值为 nullptr
sendConfig.pushConfig = &pushConfig;
// 需填入 UTF-8 格式的本地路径
imageMessage.fileLocalPath = "D:\\image\\img.jpg";
// 如果此处填入了网络 URL,SDK 则会透传该路径,而不会经过 ZIM 后台服务处理。同时填入网络 URL 与本地路径,SDK 会优先认为用户想要使用网络 URL
imageMessage.fileDownloadUrl = "";
imageMessage.largeImageDownloadUrl = "";
imageMessage.thumbnailDownloadUrl = "";
message = &imageMessage;
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { 
                // 开发者可监听此回调,执行消息发送前的逻辑
            },
            [=](const std::shared_ptr<zim::ZIMMediaMessage> &message,
                unsigned long long currentFileSize,
                unsigned long long totalFileSize) { 
                // 开发者可监听此回调,获取文件上传的进度
            });
zim_->sendMessage(message, receiver_id, zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
    sendConfig,notification,
    [=](const std::shared_ptr<zim::ZIMMessage> &message, const zim::ZIMError &errorInfo) {
        
    });// 发送“本地文件”富媒体消息示例 - 单聊
// conversationID 为 消息需要发送的会话 ID
// 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
const conversationID = 'xxxx';
const config: ZIMMessageSendConfig = { priority: 1 };
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {
    
    },
    onMediaUploadingProgress: (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) {
        // 开发者可以在这里展示上传进度
    }
};
function sendMessage(file: File) {
    /* 以下代码仅为示例:实际开发时请结合需求和文件类型,创建对应的 `媒体消息对象` */
    // 如果是 `图片` 消息
    let mediaMessageObj: ZIMMediaMessage = {
        fileLocalPath: file,
        type: 11,
    };
    // 如果是 `文件` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 12,
    };
    // 如果是 `音频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 13,
        audioDuration: 100, // 请填写音频文件播放时长,单位秒(必填)
    };
    // 如果是 `视频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 14,
        videoDuration: 100, // 请填写视频文件播放时长,单位秒(必填)
    };
  
    zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification);  
}
const input = document.createElement('input');
input.type = 'file';
input.onchange = (ev) {
    sendMessage(ev.files[0]);
}// 发送“本地文件”富媒体消息示例 - 单聊
// conversationID 为 消息需要发送的会话 ID
// 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
const conversationID = 'xxxx';
const config: ZIMMessageSendConfig = { priority: 1 };
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {
    
    },
    onMediaUploadingProgress: (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) {
        // 开发者可以在这里展示上传进度
    }
};
function sendMessage(file: File) {
    /* 以下代码仅为示例:实际开发时请结合需求和文件类型,创建对应的 `媒体消息对象` */
    // 如果是 `图片` 消息
    let mediaMessageObj: ZIMMediaMessage = {
        fileLocalPath: file,
        type: 11,
    };
    // 如果是 `文件` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 12,
    };
    // 如果是 `音频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 13,
        audioDuration: 100, // 请填写音频文件播放时长,单位秒(必填)
    };
    // 如果是 `视频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 14,
        videoDuration: 100, // 请填写视频文件播放时长,单位秒(必填)
    };
  
    zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification);  
}
const input = document.createElement('input');
input.type = 'file';
input.onchange = (ev) {
    sendMessage(ev.files[0]);
}// 发送“本地文件”富媒体消息示例 - 单聊
// conversationID 为 消息需要发送的会话 ID
// 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
const conversationID = 'xxxx';
const config: ZIMMessageSendConfig = { priority: 1 };
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {
    },
    onMediaUploadingProgress: (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) {
        // 您可以在这里展示上传进度
    }
};
function sendMessage(file: string) {
    /* 以下代码仅为示例:实际开发时请结合需求和文件类型,创建对应的 `媒体消息对象` */
    // 如果是 `图片` 消息
    let mediaMessageObj: ZIMMediaMessage = {
        fileLocalPath: file,
        type: 11,
    };
    // 如果是 `文件` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 12,
    };
    // 如果是 `音频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 13,
        audioDuration: 100, // 请填写音频文件播放时长,单位秒(必填)
    };
    // 如果是 `视频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 14,
        videoDuration: 100, // 请填写视频文件播放时长,单位秒(必填)
    };
  
    zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification);  
}
// 拍摄或从手机相册中选择图片或视频
// 请参考小程序官方文档:https://developers.weixin.qq.com/miniprogram/dev/api/media/video/wx.chooseMedia.html
wx.chooseMedia({
    count: 1,
    success(res) {
        sendMessage(res.tempFiles[0].tempFilePath);
    }
})
// 从微信客户端会话选择文件
// 请参考小程序官方文档:https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseMessageFile.html
wx.chooseMessageFile({
    count: 1,
    success(res) {
        sendMessage(res.tempFiles[0].path);
    }
})// 发送“本地文件”富媒体消息示例 - 单聊
// conversationID 为 消息需要发送的会话 ID
// 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
const conversationID = 'xxxx';
const config: ZIMMessageSendConfig = { priority: 1 };
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {
    },
    onMediaUploadingProgress: (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) {
        // 您可以在这里展示上传进度
    }
};
function sendMessage(file: string) {
    /* 以下代码仅为示例:实际开发时请结合需求和文件类型,创建对应的 `媒体消息对象` */
    // 如果是 `图片` 消息
    let mediaMessageObj: ZIMMediaMessage = {
        fileLocalPath: file,
        type: 11,
    };
    // 如果是 `文件` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 12,
    };
    // 如果是 `音频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 13,
        audioDuration: 100, // 请填写音频文件播放时长,单位秒(必填)
    };
    // 如果是 `视频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 14,
        videoDuration: 100, // 请填写视频文件播放时长,单位秒(必填)
    };
  
    zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification);  
}
// 拍摄或从手机相册中选择图片或视频
// 请参考小程序官方文档:https://developers.weixin.qq.com/miniprogram/dev/api/media/video/wx.chooseMedia.html
wx.chooseMedia({
    count: 1,
    success(res) {
        sendMessage(res.tempFiles[0].tempFilePath);
    }
})
// 从微信客户端会话选择文件
// 请参考小程序官方文档:https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseMessageFile.html
wx.chooseMessageFile({
    count: 1,
    success(res) {
        sendMessage(res.tempFiles[0].path);
    }
})// 发送“本地文件”富媒体消息示例 - 单聊
// conversationID 为 消息需要发送的会话 ID
// 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
const conversationID = 'xxxx';
const config: ZIMMessageSendConfig = { priority: 1 };
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {
        
    },
    onMediaUploadingProgress: (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) {
        // 您可以在这里展示上传进度
    }
};
function sendMessage(file: string) {
    /* 以下代码仅为示例:实际开发时请结合需求和文件类型,创建对应的 `媒体消息对象` */
    // 如果是 `图片` 消息
    let mediaMessageObj: ZIMMessage = {
        fileLocalPath: file,
        type: 11,
    };
    // 如果是 `文件` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 12,
    };
    // 如果是 `音频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 13,
        audioDuration: 100, // 请填写音频文件播放时长,单位秒(必填)
    };
    // 如果是 `视频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 14,
        videoDuration: 100, // 请填写视频文件播放时长,单位秒(必填)
    };
  
    zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification);  
}
// Android 文件绝对路径 示例
const file = '/storage/emulated/0/Android/data/packagename/picture/xxx.jpg';
// iOS 文件绝对路径 示例  
const file = '/var/mobile/Containers/Data/Application/C142EFE6-9DEC-449D-89B7-BF99F2578F98/tmp/D1513E30-2641-440B-B897-48CD43BE1D04.jpeg';
// 注意:必须是文件的绝对路径,不能是 file://xxxx 等形式的字符串(某些跨平台框架提供的获取本地文件返回的文件路径)
sendMessage(file);// 发送“本地文件”富媒体消息示例 - 单聊
// conversationID 为 消息需要发送的会话 ID
// 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
const conversationID = 'xxxx';
const config: ZIMMessageSendConfig = { priority: 1 };
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {
        
    },
    onMediaUploadingProgress: (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) {
        // 您可以在这里展示上传进度
    }
};
function sendMessage(file: string) {
    /* 以下代码仅为示例:实际开发时请结合需求和文件类型,创建对应的 `媒体消息对象` */
    // 如果是 `图片` 消息
    let mediaMessageObj: ZIMMessage = {
        fileLocalPath: file,
        type: 11,
    };
    // 如果是 `文件` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 12,
    };
    // 如果是 `音频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 13,
        audioDuration: 100, // 请填写音频文件播放时长,单位秒(必填)
    };
    // 如果是 `视频` 消息
    mediaMessageObj = {
        fileLocalPath: file,
        type: 14,
        videoDuration: 100, // 请填写视频文件播放时长,单位秒(必填)
    };
  
    zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification);  
}
// Android 文件绝对路径 示例
const file = '/storage/emulated/0/Android/data/packagename/picture/xxx.jpg';
// iOS 文件绝对路径 示例  
const file = '/var/mobile/Containers/Data/Application/C142EFE6-9DEC-449D-89B7-BF99F2578F98/tmp/D1513E30-2641-440B-B897-48CD43BE1D04.jpeg';
// 注意:必须是文件的绝对路径,不能是 file://xxxx 等形式的字符串(某些跨平台框架提供的获取本地文件返回的文件路径)
sendMessage(file);// 发送“网络文件”富媒体消息示例 - 单聊
/* 发送网络文件消息时,ZIM SDK 仅透传相关字段到后台,ZIM 后台不会保存网络文件 */
// conversationID 为 消息需要发送的会话 ID
// 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
const conversationID = 'xxxx';
const config: ZIMMessageSendConfig = { priority: 1 };
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
};
/* 以下代码仅为示例:实际开发时请结合需求和文件类型,创建对应的 `媒体消息对象` */
// 如果是 `图片` 消息
let mediaMessageObj: ZIMMessage = {
    fileDownloadUrl: 'https://xxxx.jpeg', // 原图
    thumbnailDownloadUrl: 'https://xxxx-thumbnail.jpeg', // 缩略图
    largeImageDownloadUrl: 'https://xxxx-large.jpeg', // 大图
    type: 11,
};
// 如果是 `文件` 消息
mediaMessageObj = {
    fileDownloadUrl: 'https://xxxx.pdf',
    type: 12,
};
// 如果是 `音频` 消息
mediaMessageObj = {
    fileDownloadUrl: 'https://xxxx.mp3',
    type: 13,
    audioDuration: 100, // 请填写音频文件播放时长,单位秒(必填)
};
// 如果是 `视频` 消息
mediaMessageObj = {
    fileDownloadUrl: 'https://xxxx.mp4',
    videoFirstFrameDownloadUrl: 'https://xxxx-firstframe.jpeg', // 视频首帧图片
    type: 14,
    videoDuration: 100, // 请填写视频文件播放时长,单位秒(必填)
};
  
zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification);// 发送“网络文件”富媒体消息示例 - 单聊
/* 发送网络文件消息时,ZIM SDK 仅透传相关字段到后台,ZIM 后台不会保存网络文件 */
// conversationID 为 消息需要发送的会话 ID
// 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
const conversationID = 'xxxx';
const config: ZIMMessageSendConfig = { priority: 1 };
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
};
/* 以下代码仅为示例:实际开发时请结合需求和文件类型,创建对应的 `媒体消息对象` */
// 如果是 `图片` 消息
let mediaMessageObj: ZIMMessage = {
    fileDownloadUrl: 'https://xxxx.jpeg', // 原图
    thumbnailDownloadUrl: 'https://xxxx-thumbnail.jpeg', // 缩略图
    largeImageDownloadUrl: 'https://xxxx-large.jpeg', // 大图
    type: 11,
};
// 如果是 `文件` 消息
mediaMessageObj = {
    fileDownloadUrl: 'https://xxxx.pdf',
    type: 12,
};
// 如果是 `音频` 消息
mediaMessageObj = {
    fileDownloadUrl: 'https://xxxx.mp3',
    type: 13,
    audioDuration: 100, // 请填写音频文件播放时长,单位秒(必填)
};
// 如果是 `视频` 消息
mediaMessageObj = {
    fileDownloadUrl: 'https://xxxx.mp4',
    videoFirstFrameDownloadUrl: 'https://xxxx-firstframe.jpeg', // 视频首帧图片
    type: 14,
    videoDuration: 100, // 请填写视频文件播放时长,单位秒(必填)
};
  
zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification);// 需要使用 HTTPS 协议
if (navigator.mediaDevices) {
    const chunks = [];
    navigator.mediaDevices
        .getUserMedia({ audio: true })
        .then((stream) => {
            const duration = 10; // 录制时长,单位秒
            const mediaRecorder = new MediaRecorder(stream);
            mediaRecorder.onstop = (ev) => {
                // 录制结束后,发送音频消息
                // conversationID 为 消息需要发送的会话 ID
                // 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
                const conversationID = 'xxxx';
                const config: ZIMMessageSendConfig = { priority: 1 };
                const notification: ZIMMessageSendNotification = {
                    onMessageAttached: (message: ZIMMessage) => {
                        
                    },
                    onMediaUploadingProgress: (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) {
                        // 您可以在这里展示上传进度
                    }
                };
                const mediaMessageObj: ZIMAudioMessage = {
                    fileLocalPath: new File(chunks, '文件名xxxx.mp3'),
                    type: 13,
                    audioDuration: duration
                };
    
                zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification)
                    .then((res: ZIMMessageSentResult) => {
                        // 发送成功
                    })
                    .catch((err: ZIMError) => {
                        // 发送失败
                    });
                // 重置 chunks  
                chunks = [];
            };
            mediaRecorder.ondataavailable = (ev) => {
                chunks.push(ev.data);
            };
            // 开始录制
            mediaRecorder.start();
            // 停止录制 
            setTimeout(() => mediaRecorder.stop(), duration * 1000);
        })
        .catch((err) => {
            console.log('The following error occured: ' + err);
        });
}// 需要使用 HTTPS 协议
if (navigator.mediaDevices) {
    const chunks = [];
    navigator.mediaDevices
        .getUserMedia({ audio: true })
        .then((stream) => {
            const duration = 10; // 录制时长,单位秒
            const mediaRecorder = new MediaRecorder(stream);
            mediaRecorder.onstop = (ev) => {
                // 录制结束后,发送音频消息
                // conversationID 为 消息需要发送的会话 ID
                // 单聊时,conversationID 即是对方的 userID;群组时,conversationID 即是群组的 groupID;房间时,conversationID 即是房间的 roomID
                const conversationID = 'xxxx';
                const config: ZIMMessageSendConfig = { priority: 1 };
                const notification: ZIMMessageSendNotification = {
                    onMessageAttached: (message: ZIMMessage) => {
                        
                    },
                    onMediaUploadingProgress: (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) {
                        // 您可以在这里展示上传进度
                    }
                };
                const mediaMessageObj: ZIMAudioMessage = {
                    fileLocalPath: new File(chunks, '文件名xxxx.mp3'),
                    type: 13,
                    audioDuration: duration
                };
    
                zim.sendMessage(mediaMessageObj, conversationID, 0, config, notification)
                    .then((res: ZIMMessageSentResult) => {
                        // 发送成功
                    })
                    .catch((err: ZIMError) => {
                        // 发送失败
                    });
                // 重置 chunks  
                chunks = [];
            };
            mediaRecorder.ondataavailable = (ev) => {
                chunks.push(ev.data);
            };
            // 开始录制
            mediaRecorder.start();
            // 停止录制 
            setTimeout(() => mediaRecorder.stop(), duration * 1000);
        })
        .catch((err) => {
            console.log('The following error occured: ' + err);
        });
}图片
// 发送多媒体消息示例 - 单聊 发送图片消息
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:universal_io/io.dart';
final XFile? photo = await pickImage(source: ImageSource.gallery);
final String fileName = photo!.name;
var fileLocalPath;
if (kIsWeb) {
  // Web 平台:本地文件内容
  final bytes = await photo!.readAsBytes();  
  fileLocalPath = bytes; // Uint8List
} else {
  // 其他平台:本地文件绝对路径
  final String path = (await getApplicationDocumentsDirectory()).path;
  File photoFile = File(photo!.path);
  final File copyPhotoFile = await photoFile.copy('$path/${fileName}');  
  fileLocalPath = copyPhotoFile.path;
}
ZIMImageMessage imageMessage = ZIMImageMessage(fileLocalPath);
imageMessage.fileName = fileName;
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
ZIMMessageSendNotification notification = ZIMMessageSendNotification(onMessageAttached: (message){
    // 开发者可以监听这个回调执行消息发送前的业务逻辑
},onMediaUploadingProgress: (message,currentFileSize,totalFileSize){
    // 开发者可以监听这个回调获取多媒体上传的进度
});
ZIM.getInstance()!.sendMessage(
    imageMessage,
    'toConversationID',
    ZIMConversationType.peer,
    sendConfig, notification).then((value) => {
        //成功触发此处
    }).catchError((onError){
        //失败触发此处
    });// 发送多媒体消息示例 - 单聊 发送图片消息
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:universal_io/io.dart';
final XFile? photo = await pickImage(source: ImageSource.gallery);
final String fileName = photo!.name;
var fileLocalPath;
if (kIsWeb) {
  // Web 平台:本地文件内容
  final bytes = await photo!.readAsBytes();  
  fileLocalPath = bytes; // Uint8List
} else {
  // 其他平台:本地文件绝对路径
  final String path = (await getApplicationDocumentsDirectory()).path;
  File photoFile = File(photo!.path);
  final File copyPhotoFile = await photoFile.copy('$path/${fileName}');  
  fileLocalPath = copyPhotoFile.path;
}
ZIMImageMessage imageMessage = ZIMImageMessage(fileLocalPath);
imageMessage.fileName = fileName;
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
ZIMMessageSendNotification notification = ZIMMessageSendNotification(onMessageAttached: (message){
    // 开发者可以监听这个回调执行消息发送前的业务逻辑
},onMediaUploadingProgress: (message,currentFileSize,totalFileSize){
    // 开发者可以监听这个回调获取多媒体上传的进度
});
ZIM.getInstance()!.sendMessage(
    imageMessage,
    'toConversationID',
    ZIMConversationType.peer,
    sendConfig, notification).then((value) => {
        //成功触发此处
    }).catchError((onError){
        //失败触发此处
    });上传文件进度回调
- 
通过 onMediaUploadingProgress 回调,接收富媒体消息的上传文件进度的相关通知。 - message:正在发送的消息对象。
- currentFileSize:当前已上传文件的大小。
- totalFileSize:上传文件的总体大小。
 
void onMediaUploadingProgress(ZIMMediaMessage message, long currentFileSize, long totalFileSize);void onMediaUploadingProgress(ZIMMediaMessage message, long currentFileSize, long totalFileSize);typedef void (^ZIMMediaUploadingProgress)(ZIMMediaMessage *message, unsigned long long currentFileSize, unsigned long long totalFileSize);typedef void (^ZIMMediaUploadingProgress)(ZIMMediaMessage *message, unsigned long long currentFileSize, unsigned long long totalFileSize);using ZIMMediaUploadingProgress = std::function<void(const std::shared_ptr<ZIMMediaMessage> &message, long long currentSize, long long totalSize)>;using ZIMMediaUploadingProgress = std::function<void(const std::shared_ptr<ZIMMediaMessage> &message, long long currentSize, long long totalSize)>;type onMediaUploadingProgress = (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) => void;type onMediaUploadingProgress = (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) => void;type onMediaUploadingProgress = (message: ZIMMessage, currentFileSize: number, totalFileSize: number) => void;type onMediaUploadingProgress = (message: ZIMMessage, currentFileSize: number, totalFileSize: number) => void;type onMediaUploadingProgress = (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) => void;type onMediaUploadingProgress = (message: ZIMMediaMessage, currentFileSize: number, totalFileSize: number) => void;typedef ZIMMediaUploadingProgress = void Function(ZIMMediaMessage message, int currentFileSize, int totalFileSize);typedef ZIMMediaUploadingProgress = void Function(ZIMMediaMessage message, int currentFileSize, int totalFileSize);信令消息
ZIM SDK 支持开发者实现信令类型的消息收发,开发者可以通过 ZIMCommandMessage 对象定义自己的消息类型,例如位置消息等。
信令消息不支持离线推送和本地存储。
//向指定用户发送信令消息
String userID = "xxxx";
ZIMCommandMessage zimCustomMessage = new ZIMCommandMessage();
zimCustomMessage.message = new byte[]{0x1,0x2,0x1,0x2};
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 设置消息的离线推送配置
// 不支持设置房间消息的离线推送配置,如果需要发送房间离线消息,请联系 ZEGO 技术支持开通相关权限
ZIMPushConfig pushConfig = new ZIMPushConfig();
pushConfig.title = "离线推送的标题";
pushConfig.content= "离线推送的内容";
pushConfig.extendedData = "离线推送的扩展信息";
config.pushConfig = pushConfig;
// 发送单聊信息
ZIMConversationType type = ZIMConversationType.Peer;
// 发送群聊信息
// ZIMConversationType type = ZIMConversationType.Gourp;
// 发送房间信息
// ZIMConversationType type = ZIMConversationType.Room;
zim.sendMessage(zimCustomMessage, toConversationID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});//向指定用户发送信令消息
String userID = "xxxx";
ZIMCommandMessage zimCustomMessage = new ZIMCommandMessage();
zimCustomMessage.message = new byte[]{0x1,0x2,0x1,0x2};
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 设置消息的离线推送配置
// 不支持设置房间消息的离线推送配置,如果需要发送房间离线消息,请联系 ZEGO 技术支持开通相关权限
ZIMPushConfig pushConfig = new ZIMPushConfig();
pushConfig.title = "离线推送的标题";
pushConfig.content= "离线推送的内容";
pushConfig.extendedData = "离线推送的扩展信息";
config.pushConfig = pushConfig;
// 发送单聊信息
ZIMConversationType type = ZIMConversationType.Peer;
// 发送群聊信息
// ZIMConversationType type = ZIMConversationType.Gourp;
// 发送房间信息
// ZIMConversationType type = ZIMConversationType.Room;
zim.sendMessage(zimCustomMessage, toConversationID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});//向指定用户发送信令消息
NSData *anyData = [[NSData alloc] init];
NSString *toUserID = @"toUserID";
ZIMCommandMessage * cmdMsg = [[ZIMCommandMessage alloc] initWithMessage:anyData];
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc] init];
sendConfig.priority = ZIMMessagePriorityMedium;
[self.zim sendMessage:cmdMsg toUserID:toUserID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];//向指定用户发送信令消息
NSData *anyData = [[NSData alloc] init];
NSString *toUserID = @"toUserID";
ZIMCommandMessage * cmdMsg = [[ZIMCommandMessage alloc] initWithMessage:anyData];
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc] init];
sendConfig.priority = ZIMMessagePriorityMedium;
[self.zim sendMessage:cmdMsg toUserID:toUserID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];// 向指定用户发送信令消息
zim::ZIMMessage *message = nullptr;
zim::ZIMCommandMessage commandMessage;
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
pushConfig.content = "win_push_content";
pushConfig.extendedData = "win_push_extended_data";
pushConfig.title = "win_push_title";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
sendConfig.pushConfig = &pushConfig;
std::vector<uint8_t> uint8Message;
uint8Message.assign(strMessage.begin(), strMessage.end());
commandMessage.message = uint8Message;
message = &commandMessage;
// 发送单聊信息 
zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER
// 发送群聊信息
// zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_GROUP
// 发送房间信息
// zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_ROOM
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { int i = 0; });
// 发送消息
zim_->sendMessage(message, "toConversationID", type, config, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                              const zim::ZIMError &errorInfo) { int i = 0; });// 向指定用户发送信令消息
zim::ZIMMessage *message = nullptr;
zim::ZIMCommandMessage commandMessage;
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
pushConfig.content = "win_push_content";
pushConfig.extendedData = "win_push_extended_data";
pushConfig.title = "win_push_title";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
sendConfig.pushConfig = &pushConfig;
std::vector<uint8_t> uint8Message;
uint8Message.assign(strMessage.begin(), strMessage.end());
commandMessage.message = uint8Message;
message = &commandMessage;
// 发送单聊信息 
zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER
// 发送群聊信息
// zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_GROUP
// 发送房间信息
// zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_ROOM
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { int i = 0; });
// 发送消息
zim_->sendMessage(message, "toConversationID", type, config, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                              const zim::ZIMError &errorInfo) { int i = 0; });// 发送单聊 `Command` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
// 这里以 JSON 字符串 为例,需要将字符串转换为 Uint8Array
// peerMessageReceived 收到 type 为 2 的 Command 消息时,需要将 Uint8Array 转换为 JSON 字符串
const jsonText = JSON.stringify({ id: '111', name: '张三' });
const uint8Array = new Uint8Array(Array.from(unescape(encodeURIComponent(jsonText))).map((val) => val.charCodeAt(0)));
const messageCommandObj: ZIMMessage = { type: 2, message: uint8Array };
zim.sendMessage(messageCommandObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 发送单聊 `Command` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
// 这里以 JSON 字符串 为例,需要将字符串转换为 Uint8Array
// peerMessageReceived 收到 type 为 2 的 Command 消息时,需要将 Uint8Array 转换为 JSON 字符串
const jsonText = JSON.stringify({ id: '111', name: '张三' });
const uint8Array = new Uint8Array(Array.from(unescape(encodeURIComponent(jsonText))).map((val) => val.charCodeAt(0)));
const messageCommandObj: ZIMMessage = { type: 2, message: uint8Array };
zim.sendMessage(messageCommandObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 发送单聊 `Command` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageCommandObj: ZIMMessage = { type: 2, message: [1, 2, 128, 255] };
zim.sendMessage(messageCommandObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 发送单聊 `Command` 信息
// toConversationID 为 消息需要发送的会话 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageCommandObj: ZIMMessage = { type: 2, message: [1, 2, 128, 255] };
zim.sendMessage(messageCommandObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 向指定用户发送信令消息
Uint8List cmdMessage = Uint8List.fromList([1, 2, 3]);
ZIMCommandMessage commandMessage = ZIMCommandMessage(message: cmdMessage);
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
ZIM.getInstance()!.sendMessage(cmdMsg, 'toUserID', ZIMConversationType.peer, sendConfig)
    .then((value) => {
        //成功触发此处
    })
    .catchError((onError) {
        //失败触发此处
    });// 向指定用户发送信令消息
Uint8List cmdMessage = Uint8List.fromList([1, 2, 3]);
ZIMCommandMessage commandMessage = ZIMCommandMessage(message: cmdMessage);
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
ZIM.getInstance()!.sendMessage(cmdMsg, 'toUserID', ZIMConversationType.peer, sendConfig)
    .then((value) => {
        //成功触发此处
    })
    .catchError((onError) {
        //失败触发此处
    });自定义消息
ZIM SDK 支持开发者实现自定义类型的消息收发,开发者可以通过 ZIMCustomMessage 对象创建自定义类型消息,例如投票类型、接龙类型、视频卡片类型等。
- 仅 2.8.0 及以上版本的 ZIM SDK 支持发送自定义类型消息,接收并查看自定义类型消息的内容。
- 如果接收端的 SDK 版本介乎 [2.0.0, 2.8.0) 区间,可以收到自定义消息时,但会显示此消息类型为未知,且无法获取信息内容。如需获取此条消息,请将 SDK 升级为 2.8.0 或以上版本。
- 如果接收端的 SDK 版本为 1.x.x 版本,则无法收到自定义消息,也不会收到未知消息。
// 在单聊会话中向指定用户发送自定义消息
String userID = "xxxx";
// 自定义消息的文本内容
String message = "";
// 具体的自定义类型
int subType = 100; 
// 自定义消息的检索字段。
String searchedContent = "";
ZIMCustomMessage zimCustomMessage = new ZIMCustomMessage(message,subType);
// 发送消息的高级属性配置
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(zimCustomMessage, userID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});// 在单聊会话中向指定用户发送自定义消息
String userID = "xxxx";
// 自定义消息的文本内容
String message = "";
// 具体的自定义类型
int subType = 100; 
// 自定义消息的检索字段。
String searchedContent = "";
ZIMCustomMessage zimCustomMessage = new ZIMCustomMessage(message,subType);
// 发送消息的高级属性配置
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(zimCustomMessage, userID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});// 向指定用户发送自定义消息
NSString *message = @"message";
NSString *toUserID = @"toUserID";
ZIMCustomMessage * customMessage = [[ZIMCustomMessage alloc] init];
customMessage.message = message;
customMessage.subType = 1; // 开发者自定义的类型
customMessage.searchContent="";
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc] init];
sendConfig.priority = ZIMMessagePriorityMedium;
[self.zim sendMessage:customMessage toUserID:toUserID conversationType: ZIMConversationTypePeer config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];// 向指定用户发送自定义消息
NSString *message = @"message";
NSString *toUserID = @"toUserID";
ZIMCustomMessage * customMessage = [[ZIMCustomMessage alloc] init];
customMessage.message = message;
customMessage.subType = 1; // 开发者自定义的类型
customMessage.searchContent="";
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc] init];
sendConfig.priority = ZIMMessagePriorityMedium;
[self.zim sendMessage:customMessage toUserID:toUserID conversationType: ZIMConversationTypePeer config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];// 向指定用户发送自定义消息
zim::ZIMMessage *message = nullptr;
zim::ZIMCustomMessage customMessage;
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
pushConfig.content = "win_push_content";
pushConfig.extendedData = "win_push_extended_data";
pushConfig.title = "win_push_title";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
sendConfig.pushConfig = &pushConfig;
std::string message = "message";
unsigned int subType = 1;
std::string searchedContent = "searchedContent";
customMessage.message = message;
customMessage.subType = subType;
customMessage.searchedContent = searchedContent;
message = &customMessage;
zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { int i = 0; });
zim_->sendMessage(message, "toConversationID", type, config, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                              const zim::ZIMError &errorInfo) { int i = 0; });// 向指定用户发送自定义消息
zim::ZIMMessage *message = nullptr;
zim::ZIMCustomMessage customMessage;
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
pushConfig.content = "win_push_content";
pushConfig.extendedData = "win_push_extended_data";
pushConfig.title = "win_push_title";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
sendConfig.pushConfig = &pushConfig;
std::string message = "message";
unsigned int subType = 1;
std::string searchedContent = "searchedContent";
customMessage.message = message;
customMessage.subType = subType;
customMessage.searchedContent = searchedContent;
message = &customMessage;
zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { int i = 0; });
zim_->sendMessage(message, "toConversationID", type, config, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                              const zim::ZIMError &errorInfo) { int i = 0; });// 发送自定义信息
// 指定用户的 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = "xxxx";
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
// 发送消息的高级属性配置
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const zimCustomMessage: ZIMMessage = {
    type: 200,
    message: 'xxxx', // 自定义消息的文本内容
    subType: 100, // 具体的自定义类型
    searchedContent: 'xxxx' // 自定义消息的检索字段
};
zim.sendMessage(zimCustomMessage, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 发送自定义信息
// 指定用户的 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = "xxxx";
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
// 发送消息的高级属性配置
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const zimCustomMessage: ZIMMessage = {
    type: 200,
    message: 'xxxx', // 自定义消息的文本内容
    subType: 100, // 具体的自定义类型
    searchedContent: 'xxxx' // 自定义消息的检索字段
};
zim.sendMessage(zimCustomMessage, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 在单聊会话中向指定用户发送自定义消息
// 指定用户的 ID
String userID = "xxxx";
// 自定义消息的文本内容
String message = "";
// 具体的自定义类型
int subType = 100; 
// 自定义消息的检索字段。
String searchedContent = "";
ZIMCustomMessage zimCustomMessage = ZIMCustomMessage(message, subType);
// 发送消息的高级属性配置
ZIMMessageSendConfig config = ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.low;
ZIMConversationType type = ZIMConversationType.Peer;
ZIM.getInstance().sendMessage(zimCustomMessage, userID, type, config, ZIMMessageSendNotification(onMessageAttached: (ZIMMessage message){
    // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
  })).then((value) {
    // 发送成功回调
  }).catchError((onError){
    // 处理失败
  });// 在单聊会话中向指定用户发送自定义消息
// 指定用户的 ID
String userID = "xxxx";
// 自定义消息的文本内容
String message = "";
// 具体的自定义类型
int subType = 100; 
// 自定义消息的检索字段。
String searchedContent = "";
ZIMCustomMessage zimCustomMessage = ZIMCustomMessage(message, subType);
// 发送消息的高级属性配置
ZIMMessageSendConfig config = ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.low;
ZIMConversationType type = ZIMConversationType.Peer;
ZIM.getInstance().sendMessage(zimCustomMessage, userID, type, config, ZIMMessageSendNotification(onMessageAttached: (ZIMMessage message){
    // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
  })).then((value) {
    // 发送成功回调
  }).catchError((onError){
    // 处理失败
  });组合消息
ZIM SDK 支持开发者实现组合类型的消息收发,开发者可以通过 ZIMMultipleMessage 对象组合多种消息类型(文本、图片、音频、视频、文件和自定义消息),实现图文消息等场景。
- 仅 2.19.0 及以上版本的 ZIM SDK 支持发送组合类型消息,接收并查看组合类型消息的内容。
- 如果接收端的 SDK 版本介乎 [2.0.0, 2.19.0) 区间,可以收到组合消息时,但会显示此消息类型为未知,且无法获取信息内容。如需获取此条消息,请将 SDK 升级为 2.19.0 或以上版本。
- 如果接收端的 SDK 版本为 1.x.x 版本,则无法收到组合消息,也不会收到未知消息。

通过 multipleMediaUploadingProgress 回调,接收组合消息中富媒体文件的上传进度的相关通知。在此回调中,您可以了解到以下字段:
- currentFileSize:已上传文件总大小,单位为 Byte。
- totalFileSize:组合消息中多媒体文件的总大小,,单位为 Byte。
- messageInfoIndex:接收到此回调时,当前正在上传的文件在 ZIMMultipleMessage 数组的索引。
- currentIndexFileSize: 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
- totalIndexFileSize:接收到此回调时,当前正在上传的文件的实际大小,单位为 Byte。
上述字段可用于计算多媒体文件的总上传进度、以及当前文档的上传进度:
- 总上传进度 = currentFileSize / totalFileSize。
- 当前文件上传进度 = currentIndexFileSize / totalIndexFileSize。
:::
// 在单聊会话中向指定用户发送组合消息
String userID = "xxxx";
// 组合消息 Item 列表,最多只可以包含 20 个 Item
ArrayList<ZIMMessageLiteInfo> messageInfoList = new ArrayList();
// 文本
ZIMTextMessageLiteInfo textMsgInfo= new ZIMTextMessageLiteInfo();
textMsgInfo.message = "消息内容";
messageInfoList.add(textMsgInfo);
// 自定义消息:最多支持 1 个
ZIMCustomMessageLiteInfo customMsgInfo= new ZIMCustomMessageLiteInfo();
customMsgInfo.message = "消息内容";
customMsgInfo.searchedContent = "搜索内容";
customMsgInfo.subType = 100;
messageInfoList.add(customMsgInfo);
// 图片:最多支持 10 个
// 网络图片示例
ZIMImageMessageLiteInfo imageMsgInfo= new ZIMImageMessageLiteInfo();
imageMsgInfo.fileDownloadUrl = "https://xxxx.jpeg"; // 原图
imageMsgInfo.thumbnailDownloadUrl = "https://xxxx-thumbnail.jpeg"; // 缩略图
imageMsgInfo.largeImageDownloadUrl = "https://xxxx-large.jpeg"; // 大图
messageInfoList.add(imageMsgInfo);
// 本地图片示例
ZIMImageMessageLiteInfo localImageMsgInfo= new ZIMImageMessageLiteInfo();
localImageMsgInfo.fileLocalPath = "/storage/emulated/0/Android/data/packagename/xxx.jpg"; // 图片的绝对路径
messageInfoList.add(localImageMsgInfo);
// 文件:最多支持 1 个
ZIMFileMessageLiteInfo localFileMsgInfo= new ZIMFileMessageLiteInfo();
localFileMsgInfo.fileLocalPath = "/storage/emulated/0/Android/data/packagename/xxx.zip"; // 文件的绝对路径
messageInfoList.add(localFileMsgInfo);
// 音频:最多支持 1 个
ZIMAudioMessageLiteInfo localAudioMsgInfo= new ZIMAudioMessageLiteInfo();
localAudioMsgInfo.fileLocalPath = "/storage/emulated/0/Android/data/packagename/xxx.mp3"; // 音频的绝对路径
localAudioMsgInfo.audioDuration = 100; // 必填,音频时长,单位秒
messageInfoList.add(localAudioMsgInfo);
// 视频:最多支持 1 个
ZIMVideoMessageLiteInfo localVideoMsgInfo= new ZIMVideoMessageLiteInfo();
localVideoMsgInfo.fileLocalPath = "/storage/emulated/0/Android/data/packagename/xxx.mp4"; // 视频的绝对路径
localVideoMsgInfo.videoDuration = 100; // 必填,视频时长,单位秒
messageInfoList.add(localVideoMsgInfo);
ZIMMultipleMessage zimMultipleMessage = new ZIMMultipleMessage();
zimMultipleMessage.setMessageInfoList(messageInfoList);
// 发送消息的高级属性配置
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(zimMultipleMessage, userID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
    @Override
    public void onMultipleMediaUploadingProgress(
        ZIMMultipleMessage message,
        long currentFileSize,      // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
        long totalFileSize,        // 总文件大小,单位为 Byte。比如总文件大小 104,857,600 Byte,则此处为 104,857,600
        int messageInfoIndex,      // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
        long currentIndexFileSize, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
        long totalIndexFileSize,   // 接收到此回调时,当前正在上传的文件的实际大小,单位为 Byte。
    ) {
        // 您可以在这里展示上传进度
        // 开发者可以监听这个回调获取多媒体上传的进度
        // 总文件上传进度: currentFileSize / totalFileSize
        // 上述例子中,总文件上传进度为:20,971,520 / 104,857,600 = 20% 
        // 接收此回调时,当前正在上传的文件的上传进度:currentIndexFileSize / totalIndexFileSize
    }
});// 在单聊会话中向指定用户发送组合消息
String userID = "xxxx";
// 组合消息 Item 列表,最多只可以包含 20 个 Item
ArrayList<ZIMMessageLiteInfo> messageInfoList = new ArrayList();
// 文本
ZIMTextMessageLiteInfo textMsgInfo= new ZIMTextMessageLiteInfo();
textMsgInfo.message = "消息内容";
messageInfoList.add(textMsgInfo);
// 自定义消息:最多支持 1 个
ZIMCustomMessageLiteInfo customMsgInfo= new ZIMCustomMessageLiteInfo();
customMsgInfo.message = "消息内容";
customMsgInfo.searchedContent = "搜索内容";
customMsgInfo.subType = 100;
messageInfoList.add(customMsgInfo);
// 图片:最多支持 10 个
// 网络图片示例
ZIMImageMessageLiteInfo imageMsgInfo= new ZIMImageMessageLiteInfo();
imageMsgInfo.fileDownloadUrl = "https://xxxx.jpeg"; // 原图
imageMsgInfo.thumbnailDownloadUrl = "https://xxxx-thumbnail.jpeg"; // 缩略图
imageMsgInfo.largeImageDownloadUrl = "https://xxxx-large.jpeg"; // 大图
messageInfoList.add(imageMsgInfo);
// 本地图片示例
ZIMImageMessageLiteInfo localImageMsgInfo= new ZIMImageMessageLiteInfo();
localImageMsgInfo.fileLocalPath = "/storage/emulated/0/Android/data/packagename/xxx.jpg"; // 图片的绝对路径
messageInfoList.add(localImageMsgInfo);
// 文件:最多支持 1 个
ZIMFileMessageLiteInfo localFileMsgInfo= new ZIMFileMessageLiteInfo();
localFileMsgInfo.fileLocalPath = "/storage/emulated/0/Android/data/packagename/xxx.zip"; // 文件的绝对路径
messageInfoList.add(localFileMsgInfo);
// 音频:最多支持 1 个
ZIMAudioMessageLiteInfo localAudioMsgInfo= new ZIMAudioMessageLiteInfo();
localAudioMsgInfo.fileLocalPath = "/storage/emulated/0/Android/data/packagename/xxx.mp3"; // 音频的绝对路径
localAudioMsgInfo.audioDuration = 100; // 必填,音频时长,单位秒
messageInfoList.add(localAudioMsgInfo);
// 视频:最多支持 1 个
ZIMVideoMessageLiteInfo localVideoMsgInfo= new ZIMVideoMessageLiteInfo();
localVideoMsgInfo.fileLocalPath = "/storage/emulated/0/Android/data/packagename/xxx.mp4"; // 视频的绝对路径
localVideoMsgInfo.videoDuration = 100; // 必填,视频时长,单位秒
messageInfoList.add(localVideoMsgInfo);
ZIMMultipleMessage zimMultipleMessage = new ZIMMultipleMessage();
zimMultipleMessage.setMessageInfoList(messageInfoList);
// 发送消息的高级属性配置
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(zimMultipleMessage, userID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
    @Override
    public void onMultipleMediaUploadingProgress(
        ZIMMultipleMessage message,
        long currentFileSize,      // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
        long totalFileSize,        // 总文件大小,单位为 Byte。比如总文件大小 104,857,600 Byte,则此处为 104,857,600
        int messageInfoIndex,      // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
        long currentIndexFileSize, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
        long totalIndexFileSize,   // 接收到此回调时,当前正在上传的文件的实际大小,单位为 Byte。
    ) {
        // 您可以在这里展示上传进度
        // 开发者可以监听这个回调获取多媒体上传的进度
        // 总文件上传进度: currentFileSize / totalFileSize
        // 上述例子中,总文件上传进度为:20,971,520 / 104,857,600 = 20% 
        // 接收此回调时,当前正在上传的文件的上传进度:currentIndexFileSize / totalIndexFileSize
    }
});// 在单聊会话中向指定用户发送组合消息
NSString *toUserID = @"toUserID";
// 组合消息 Item 列表,最多只可以包含 20 个 Item
NSMutableArray<ZIMMessageLiteInfo *> *messageInfoList = [NSMutableArray array];
// 文本
ZIMTextMessageLiteInfo *textMsgInfo = [[ZIMTextMessageLiteInfo alloc] init];
textMsgInfo.message = @"消息内容";
[messageInfoList addObject:textMsgInfo];
// 自定义消息:最多支持 1 个
ZIMCustomMessageLiteInfo *customMsgInfo = [[ZIMCustomMessageLiteInfo alloc] init];
customMsgInfo.message = @"消息内容";
customMsgInfo.searchedContent = @"搜索内容";
customMsgInfo.subType = 100;
[messageInfoList addObject:customMsgInfo];
// 图片:最多支持 10 个
// 网络图片示例
ZIMImageMessageLiteInfo *imageMsgInfo = [[ZIMImageMessageLiteInfo alloc] init];
imageMsgInfo.fileDownloadUrl = @"https://xxxx.jpeg"; // 原图
imageMsgInfo.thumbnailDownloadUrl = @"https://xxxx-thumbnail.jpeg"; // 缩略图
imageMsgInfo.largeImageDownloadUrl = @"https://xxxx-large.jpeg"; // 大图
[messageInfoList addObject:imageMsgInfo];
// 本地图片示例
ZIMImageMessageLiteInfo *localImageMsgInfo = [[ZIMImageMessageLiteInfo alloc] init];
localImageMsgInfo.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/xxx.jpg"; // 图片的绝对路径
[messageInfoList addObject:localImageMsgInfo];
// 文件:最多支持 1 个
ZIMFileMessageLiteInfo *localFileMsgInfo = [[ZIMFileMessageLiteInfo alloc] init];
localFileMsgInfo.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/xxx.zip"; // 文件的绝对路径
[messageInfoList addObject:localFileMsgInfo];
// 音频:最多支持 1 个
ZIMAudioMessageLiteInfo *localAudioMsgInfo = [[ZIMAudioMessageLiteInfo alloc] init];
localAudioMsgInfo.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/xxx.mp3"; // 音频的绝对路径
localAudioMsgInfo.audioDuration = 100; // 必填,音频时长,单位秒
[messageInfoList addObject:localAudioMsgInfo];
// 视频:最多支持 1 个
ZIMVideoMessageLiteInfo *localVideoMsgInfo = [[ZIMVideoMessageLiteInfo alloc] init];
localVideoMsgInfo.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/xxx.mp4"; // 视频的绝对路径
localVideoMsgInfo.videoDuration = 100; // 必填,视频时长,单位秒
[messageInfoList addObject:localVideoMsgInfo];
ZIMMultipleMessage * multipleMessage = [[ZIMMultipleMessage alloc] init];
multipleMessage.messageInfoList = messageInfoList;
ZIMMessageSendNotification *notification = [[ZIMMessageSendNotification alloc] init];
notification.onMessageAttached = ^(ZIMMessage * _Nonnull message) {
    // 开发者可以监听这个回调执行消息发送前的业务逻辑
};
        
notification.onMultipleMediaUploadingProgress = ^(
    ZIMMultipleMessage * _Nonnull message,
    unsigned long long currentFileSize,      // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
    unsigned long long totalFileSize,        // 总文件大小,单位为 Byte。比如总文件大小 104,857,600B,则此处为 104,857,600
    unsigned int messageInfoIndex,           // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
    unsigned long long currentIndexFileSize, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
    unsigned long long totalIndexFileSize    // 接收到此回调时,当前正在上传的文件的实际大小,单位为 Byte。
) {
    // 开发者可以监听这个回调获取多媒体上传的进度
    // 总文件上传进度: currentFileSize / totalFileSize
    // 上述例子中,总文件上传进度为:20,971,520 / 104,857,600 = 20% 
    // 接收此回调时,当前正在上传的文件的上传进度:currentIndexFileSize / totalIndexFileSize
};
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc] init];
sendConfig.priority = ZIMMessagePriorityMedium;
[self.zim sendMessage:multipleMessage toUserID:toUserID conversationType: ZIMConversationTypePeer config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];// 在单聊会话中向指定用户发送组合消息
NSString *toUserID = @"toUserID";
// 组合消息 Item 列表,最多只可以包含 20 个 Item
NSMutableArray<ZIMMessageLiteInfo *> *messageInfoList = [NSMutableArray array];
// 文本
ZIMTextMessageLiteInfo *textMsgInfo = [[ZIMTextMessageLiteInfo alloc] init];
textMsgInfo.message = @"消息内容";
[messageInfoList addObject:textMsgInfo];
// 自定义消息:最多支持 1 个
ZIMCustomMessageLiteInfo *customMsgInfo = [[ZIMCustomMessageLiteInfo alloc] init];
customMsgInfo.message = @"消息内容";
customMsgInfo.searchedContent = @"搜索内容";
customMsgInfo.subType = 100;
[messageInfoList addObject:customMsgInfo];
// 图片:最多支持 10 个
// 网络图片示例
ZIMImageMessageLiteInfo *imageMsgInfo = [[ZIMImageMessageLiteInfo alloc] init];
imageMsgInfo.fileDownloadUrl = @"https://xxxx.jpeg"; // 原图
imageMsgInfo.thumbnailDownloadUrl = @"https://xxxx-thumbnail.jpeg"; // 缩略图
imageMsgInfo.largeImageDownloadUrl = @"https://xxxx-large.jpeg"; // 大图
[messageInfoList addObject:imageMsgInfo];
// 本地图片示例
ZIMImageMessageLiteInfo *localImageMsgInfo = [[ZIMImageMessageLiteInfo alloc] init];
localImageMsgInfo.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/xxx.jpg"; // 图片的绝对路径
[messageInfoList addObject:localImageMsgInfo];
// 文件:最多支持 1 个
ZIMFileMessageLiteInfo *localFileMsgInfo = [[ZIMFileMessageLiteInfo alloc] init];
localFileMsgInfo.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/xxx.zip"; // 文件的绝对路径
[messageInfoList addObject:localFileMsgInfo];
// 音频:最多支持 1 个
ZIMAudioMessageLiteInfo *localAudioMsgInfo = [[ZIMAudioMessageLiteInfo alloc] init];
localAudioMsgInfo.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/xxx.mp3"; // 音频的绝对路径
localAudioMsgInfo.audioDuration = 100; // 必填,音频时长,单位秒
[messageInfoList addObject:localAudioMsgInfo];
// 视频:最多支持 1 个
ZIMVideoMessageLiteInfo *localVideoMsgInfo = [[ZIMVideoMessageLiteInfo alloc] init];
localVideoMsgInfo.fileLocalPath = @"/private/var/mobile/Containers/Data/Application/xxx.mp4"; // 视频的绝对路径
localVideoMsgInfo.videoDuration = 100; // 必填,视频时长,单位秒
[messageInfoList addObject:localVideoMsgInfo];
ZIMMultipleMessage * multipleMessage = [[ZIMMultipleMessage alloc] init];
multipleMessage.messageInfoList = messageInfoList;
ZIMMessageSendNotification *notification = [[ZIMMessageSendNotification alloc] init];
notification.onMessageAttached = ^(ZIMMessage * _Nonnull message) {
    // 开发者可以监听这个回调执行消息发送前的业务逻辑
};
        
notification.onMultipleMediaUploadingProgress = ^(
    ZIMMultipleMessage * _Nonnull message,
    unsigned long long currentFileSize,      // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
    unsigned long long totalFileSize,        // 总文件大小,单位为 Byte。比如总文件大小 104,857,600B,则此处为 104,857,600
    unsigned int messageInfoIndex,           // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
    unsigned long long currentIndexFileSize, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
    unsigned long long totalIndexFileSize    // 接收到此回调时,当前正在上传的文件的实际大小,单位为 Byte。
) {
    // 开发者可以监听这个回调获取多媒体上传的进度
    // 总文件上传进度: currentFileSize / totalFileSize
    // 上述例子中,总文件上传进度为:20,971,520 / 104,857,600 = 20% 
    // 接收此回调时,当前正在上传的文件的上传进度:currentIndexFileSize / totalIndexFileSize
};
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc] init];
sendConfig.priority = ZIMMessagePriorityMedium;
[self.zim sendMessage:multipleMessage toUserID:toUserID conversationType: ZIMConversationTypePeer config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];// 在单聊会话中向指定用户发送组合消息
auto multiMsg = std::make_shared<ZIMMultipleMessage>();
// 文本
auto textMsgInfo = std::make_shared<ZIMTextMessageLiteInfo>();
textMsgInfo->message = "消息内容";
multiMsg->messageInfoList.push_back(textMsgInfo);
// 自定义消息:最多支持 1 个
auto customMsgInfo = std::make_shared<ZIMCustomMessageLiteInfo>();
customMsgInfo->message = "消息内容";
customMsgInfo->searchedContent = "搜索内容";
customMsgInfo->subType = 100;
multiMsg->messageInfoList.push_back(customMsgInfo);
// 图片:最多支持 10 个
// 网络图片示例
auto imageMsgInfo = std::make_shared<ZIMImageMessageLiteInfo>();
imageMsgInfo->fileDownloadUrl = "https://xxxx.jpeg";                // 原图
imageMsgInfo->thumbnailDownloadUrl = "https://xxxx-thumbnail.jpeg"; // 缩略图
imageMsgInfo->largeImageDownloadUrl = "https://xxxx-large.jpeg";    // 大图
multiMsg->messageInfoList.push_back(imageMsgInfo);
// 本地图片示例
auto localImageMsgInfo = std::make_shared<ZIMImageMessageLiteInfo>();
localImageMsgInfo->fileLocalPath = "D:\\files\\xxx.jpg"; // 图片的绝对路径
multiMsg->messageInfoList.push_back(localImageMsgInfo);
// 文件:最多支持 1 个
auto localFileMsgInfo = std::make_shared<ZIMFileMessageLiteInfo>();
localFileMsgInfo->fileLocalPath = "D:\\files\\xxx.zip"; // 文件的绝对路径
multiMsg->messageInfoList.push_back(localFileMsgInfo);
// 音频:最多支持 1 个
auto localAudioMsgInfo = std::make_shared<ZIMAudioMessageLiteInfo>();
localAudioMsgInfo->fileLocalPath = "D:\\files\\xxx.mp3"; // 音频的绝对路径
localAudioMsgInfo->audioDuration = 100; // 必填,音频时长,单位秒
multiMsg->messageInfoList.push_back(localAudioMsgInfo);
// 视频:最多支持 1 个
auto localVideoMsgInfo = std::make_shared<ZIMVideoMessageLiteInfo>();
localVideoMsgInfo->fileLocalPath = "D:\\files\\xxx.mp4"; // 文件绝对路径
localVideoMsgInfo->videoDuration = 100; // 必填,视频时长,单位秒
multiMsg->messageInfoList.push_back(localVideoMsgInfo);
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
pushConfig.content = "win_push_content";
pushConfig.payload = "win_push_payload";
pushConfig.title = "win_push_title";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
sendConfig.pushConfig = &pushConfig;
auto type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER;
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
    [=](const std::shared_ptr<zim::ZIMMessage> &message) {
        // 开发者可监听此回调,执行消息发送前的逻辑
    },
    [=](const std::shared_ptr<ZIMMediaMessage> &message,
        unsigned long long currentFileSize, unsigned long long totalFileSize) {
        // 发送组合消息时,该通知不会触发
    },
    [=](const std::shared_ptr<zim::ZIMMultipleMessage> &message,
        unsigned long long currentFileSize, // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
        unsigned long long totalFileSize, // 总文件大小,单位为 Byte。比如总文件大小 104,857,600 Byte,则此处为 104,857,600
        unsigned int messageInfoIndex, // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
        unsigned long long currentIndexFileSize, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
        unsigned long long totalIndexFileSize // 触发该回调对应的文件的大小
    ) {
        // 发送组合消息的上传回调,如果组合消息中没有媒体类型,则该回调不会触发
    });
zim_->sendMessage(multiMsg, "toConversationID", type, sendConfig, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                        const zim::ZIMError &errorInfo) {
                        // 发送结果的回调
                    });// 在单聊会话中向指定用户发送组合消息
auto multiMsg = std::make_shared<ZIMMultipleMessage>();
// 文本
auto textMsgInfo = std::make_shared<ZIMTextMessageLiteInfo>();
textMsgInfo->message = "消息内容";
multiMsg->messageInfoList.push_back(textMsgInfo);
// 自定义消息:最多支持 1 个
auto customMsgInfo = std::make_shared<ZIMCustomMessageLiteInfo>();
customMsgInfo->message = "消息内容";
customMsgInfo->searchedContent = "搜索内容";
customMsgInfo->subType = 100;
multiMsg->messageInfoList.push_back(customMsgInfo);
// 图片:最多支持 10 个
// 网络图片示例
auto imageMsgInfo = std::make_shared<ZIMImageMessageLiteInfo>();
imageMsgInfo->fileDownloadUrl = "https://xxxx.jpeg";                // 原图
imageMsgInfo->thumbnailDownloadUrl = "https://xxxx-thumbnail.jpeg"; // 缩略图
imageMsgInfo->largeImageDownloadUrl = "https://xxxx-large.jpeg";    // 大图
multiMsg->messageInfoList.push_back(imageMsgInfo);
// 本地图片示例
auto localImageMsgInfo = std::make_shared<ZIMImageMessageLiteInfo>();
localImageMsgInfo->fileLocalPath = "D:\\files\\xxx.jpg"; // 图片的绝对路径
multiMsg->messageInfoList.push_back(localImageMsgInfo);
// 文件:最多支持 1 个
auto localFileMsgInfo = std::make_shared<ZIMFileMessageLiteInfo>();
localFileMsgInfo->fileLocalPath = "D:\\files\\xxx.zip"; // 文件的绝对路径
multiMsg->messageInfoList.push_back(localFileMsgInfo);
// 音频:最多支持 1 个
auto localAudioMsgInfo = std::make_shared<ZIMAudioMessageLiteInfo>();
localAudioMsgInfo->fileLocalPath = "D:\\files\\xxx.mp3"; // 音频的绝对路径
localAudioMsgInfo->audioDuration = 100; // 必填,音频时长,单位秒
multiMsg->messageInfoList.push_back(localAudioMsgInfo);
// 视频:最多支持 1 个
auto localVideoMsgInfo = std::make_shared<ZIMVideoMessageLiteInfo>();
localVideoMsgInfo->fileLocalPath = "D:\\files\\xxx.mp4"; // 文件绝对路径
localVideoMsgInfo->videoDuration = 100; // 必填,视频时长,单位秒
multiMsg->messageInfoList.push_back(localVideoMsgInfo);
zim::ZIMMessageSendConfig sendConfig;
zim::ZIMPushConfig pushConfig;
pushConfig.content = "win_push_content";
pushConfig.payload = "win_push_payload";
pushConfig.title = "win_push_title";
sendConfig.priority = zim::ZIM_MESSAGE_PRIORITY_MEDIUM;
sendConfig.pushConfig = &pushConfig;
auto type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER;
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
    [=](const std::shared_ptr<zim::ZIMMessage> &message) {
        // 开发者可监听此回调,执行消息发送前的逻辑
    },
    [=](const std::shared_ptr<ZIMMediaMessage> &message,
        unsigned long long currentFileSize, unsigned long long totalFileSize) {
        // 发送组合消息时,该通知不会触发
    },
    [=](const std::shared_ptr<zim::ZIMMultipleMessage> &message,
        unsigned long long currentFileSize, // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
        unsigned long long totalFileSize, // 总文件大小,单位为 Byte。比如总文件大小 104,857,600 Byte,则此处为 104,857,600
        unsigned int messageInfoIndex, // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
        unsigned long long currentIndexFileSize, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
        unsigned long long totalIndexFileSize // 触发该回调对应的文件的大小
    ) {
        // 发送组合消息的上传回调,如果组合消息中没有媒体类型,则该回调不会触发
    });
zim_->sendMessage(multiMsg, "toConversationID", type, sendConfig, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                        const zim::ZIMError &errorInfo) {
                        // 发送结果的回调
                    });// 在单聊会话中向指定用户发送组合消息
// 指定用户的 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = "xxxx";
// 发送消息的高级属性配置
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {
        
    },
    onMultipleMediaUploadingProgress: (
        message: ZIMMultipleMessage,
        currentFileSize: number,      // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
        totalFileSize: number,        // 总文件大小,单位为 Byte。比如总文件大小 104,857,600 Byte,则此处为 104,857,600
        messageInfoIndex: number,     // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
        currentIndexFileSize: number, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
        totalIndexFileSize: number    // 接收到此回调时,当前正在上传的文件的实际大小,单位为 Byte。
    ) => {
        // 开发者可以监听这个回调获取多媒体上传的进度
        // 总文件上传进度: currentFileSize / totalFileSize
        // 上述例子中,总文件上传进度为:20,971,520 / 104,857,600 = 20% 
        // 接收此回调时,当前正在上传的文件的上传进度:currentIndexFileSize / totalIndexFileSize
    }
};
const zimMultipleMessage: ZIMMessage = {
    type: 10,
    // 组合消息 Item 列表,最多只可以包含 20 个 Item
    messageInfoList: [
        // 文本
        {
            type: 1,
            message: 'xxxx',
        },
        // 自定义消息:最多支持 1 个
        {
            type: 200,
            message: 'xxxx',
            subType: 100,
            searchedContent: 'xxxx'
        },
        // 图片:最多支持 10 个
        // 网络图片示例
        {
            type: 11,
            fileDownloadUrl: 'https://xxxx.jpeg', // 原图
            thumbnailDownloadUrl: 'https://xxxx-thumbnail.jpeg', // 缩略图
            largeImageDownloadUrl: 'https://xxxx-large.jpeg', // 大图
        },
        // 本地图片示例
        {
            type: 11,
            fileLocalPath: file, // 上传的文件
        },
        // 文件:最多支持 1 个
        {
            type: 12,
            fileLocalPath: file, // 上传的文件
        },
        // 音频:最多支持 1 个
        {
            type: 13,
            fileLocalPath: file, // 上传的文件
            audioDuration: 100, // 请填写音频时长,单位秒(必填)
        },
        // 视频:最多支持 1 个
        {
            type: 14,
            fileLocalPath: file, // 上传的文件
            videoDuration: 100, // 请填写视频时长,单位秒(必填)
        }
    ]
};
zim.sendMessage(zimMultipleMessage, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 在单聊会话中向指定用户发送组合消息
// 指定用户的 ID
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = "xxxx";
// 发送消息的高级属性配置
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {
        
    },
    onMultipleMediaUploadingProgress: (
        message: ZIMMultipleMessage,
        currentFileSize: number,      // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
        totalFileSize: number,        // 总文件大小,单位为 Byte。比如总文件大小 104,857,600 Byte,则此处为 104,857,600
        messageInfoIndex: number,     // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
        currentIndexFileSize: number, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
        totalIndexFileSize: number    // 接收到此回调时,当前正在上传的文件的实际大小,单位为 Byte。
    ) => {
        // 开发者可以监听这个回调获取多媒体上传的进度
        // 总文件上传进度: currentFileSize / totalFileSize
        // 上述例子中,总文件上传进度为:20,971,520 / 104,857,600 = 20% 
        // 接收此回调时,当前正在上传的文件的上传进度:currentIndexFileSize / totalIndexFileSize
    }
};
const zimMultipleMessage: ZIMMessage = {
    type: 10,
    // 组合消息 Item 列表,最多只可以包含 20 个 Item
    messageInfoList: [
        // 文本
        {
            type: 1,
            message: 'xxxx',
        },
        // 自定义消息:最多支持 1 个
        {
            type: 200,
            message: 'xxxx',
            subType: 100,
            searchedContent: 'xxxx'
        },
        // 图片:最多支持 10 个
        // 网络图片示例
        {
            type: 11,
            fileDownloadUrl: 'https://xxxx.jpeg', // 原图
            thumbnailDownloadUrl: 'https://xxxx-thumbnail.jpeg', // 缩略图
            largeImageDownloadUrl: 'https://xxxx-large.jpeg', // 大图
        },
        // 本地图片示例
        {
            type: 11,
            fileLocalPath: file, // 上传的文件
        },
        // 文件:最多支持 1 个
        {
            type: 12,
            fileLocalPath: file, // 上传的文件
        },
        // 音频:最多支持 1 个
        {
            type: 13,
            fileLocalPath: file, // 上传的文件
            audioDuration: 100, // 请填写音频时长,单位秒(必填)
        },
        // 视频:最多支持 1 个
        {
            type: 14,
            fileLocalPath: file, // 上传的文件
            videoDuration: 100, // 请填写视频时长,单位秒(必填)
        }
    ]
};
zim.sendMessage(zimMultipleMessage, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 在单聊会话中向指定用户发送组合消息
// 指定用户的 ID
String userID = "xxxx";
// 组合消息 Item 列表,最多只可以包含 20 个 Item
List<ZIMMessageLiteInfo> messageInfoList = [];
// 文本消息
ZIMTextMessageLiteInfo textMsgInfo = ZIMTextMessageLiteInfo();
textMsgInfo.message = "消息内容";
messageInfoList.add(textMsgInfo);
// 自定义消息:最多支持 1 个
ZIMCustomMessageLiteInfo customMsgInfo = ZIMCustomMessageLiteInfo();
customMsgInfo.message = "消息内容";
customMsgInfo.searchedContent = "搜索内容";
customMsgInfo.subType = 100;
messageInfoList.add(customMsgInfo);
// 图片:最多支持 10 个
// 网络图片
ZIMImageMessageLiteInfo imageMsgInfo = ZIMImageMessageLiteInfo();
imageMsgInfo.fileDownloadUrl = "https://xxxx.jpeg"; // 原图
imageMsgInfo.thumbnailDownloadUrl = "https://xxxx-thumbnail.jpeg"; // 缩略图
imageMsgInfo.largeImageDownloadUrl = "https://xxxx-large.jpeg"; // 大图
messageInfoList.add(imageMsgInfo);
// 本地图片
ZIMImageMessageLiteInfo localImageMsgInfo = ZIMImageMessageLiteInfo();
localImageMsgInfo.fileLocalPath = "/path/xxx.jpg"; // 图片绝对路径
messageInfoList.add(localImageMsgInfo);
// 文件:最多支持 1 个
ZIMImageMessageLiteInfo localFileMsgInfo = ZIMFileMessageLiteInfo();
localFileMsgInfo.fileLocalPath = "/path/xxx.zip"; // 文件绝对路径
messageInfoList.add(localFileMsgInfo);
// 音频:最多支持 1 个
ZIMAudioMessageLiteInfo localAudioMsgInfo = ZIMAudioMessageLiteInfo();
localAudioMsgInfo.fileLocalPath = "/path/xxx.mp3"; // 音频绝对路径
localAudioMsgInfo.audioDuration = 100; // 必填,播放时长,单位秒
messageInfoList.add(localAudioMsgInfo);
// 视频:最多支持 1 个
ZIMVideoMessageLiteInfo localVideoMsgInfo = ZIMVideoMessageLiteInfo();
localVideoMsgInfo.fileLocalPath = "/path/xxx.mp4"; // 视频绝对路径
localVideoMsgInfo.videoDuration = 100; // 必填,播放时长,单位秒
messageInfoList.add(localVideoMsgInfo);
ZIMMultipleMessage zimMultipleMessage = ZIMMultipleMessage(messageInfos);
zimMultipleMessage.messageInfoList = messageInfoList;
ZIMMessageSendNotification notification = ZIMMessageSendNotification(
    onMessageAttached: (message){
        // 开发者可以监听这个回调执行消息发送前的业务逻辑
    },
    onMultipleMediaUploadingProgress: (
        message,
        currentFileSize,      // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
        totalFileSize,        // 总文件大小,单位为 Byte。比如总文件大小 104,857,600 Byte,则此处为 104,857,600
        messageInfoIndex,     // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
        currentIndexFileSize, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
        totalIndexFileSize    // 接收到此回调时,当前正在上传的文件的实际大小,单位为 Byte。
    ){
        // 开发者可以监听这个回调获取多媒体上传的进度
        // 总文件上传进度: currentFileSize / totalFileSize
        // 上述例子中,总文件上传进度为:20,971,520 / 104,857,600 = 20% 
        // 接收此回调时,当前正在上传的文件的上传进度:currentIndexFileSize / totalIndexFileSize
    }
);
// 发送消息的高级属性配置
ZIMMessageSendConfig config = ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.low;
ZIMConversationType type = ZIMConversationType.Peer;
ZIM.getInstance().sendMessage(zimMultipleMessage, userID, type, config, notification).then((value) {
    // 发送成功回调
  }).catchError((onError){
    // 处理失败
  });// 在单聊会话中向指定用户发送组合消息
// 指定用户的 ID
String userID = "xxxx";
// 组合消息 Item 列表,最多只可以包含 20 个 Item
List<ZIMMessageLiteInfo> messageInfoList = [];
// 文本消息
ZIMTextMessageLiteInfo textMsgInfo = ZIMTextMessageLiteInfo();
textMsgInfo.message = "消息内容";
messageInfoList.add(textMsgInfo);
// 自定义消息:最多支持 1 个
ZIMCustomMessageLiteInfo customMsgInfo = ZIMCustomMessageLiteInfo();
customMsgInfo.message = "消息内容";
customMsgInfo.searchedContent = "搜索内容";
customMsgInfo.subType = 100;
messageInfoList.add(customMsgInfo);
// 图片:最多支持 10 个
// 网络图片
ZIMImageMessageLiteInfo imageMsgInfo = ZIMImageMessageLiteInfo();
imageMsgInfo.fileDownloadUrl = "https://xxxx.jpeg"; // 原图
imageMsgInfo.thumbnailDownloadUrl = "https://xxxx-thumbnail.jpeg"; // 缩略图
imageMsgInfo.largeImageDownloadUrl = "https://xxxx-large.jpeg"; // 大图
messageInfoList.add(imageMsgInfo);
// 本地图片
ZIMImageMessageLiteInfo localImageMsgInfo = ZIMImageMessageLiteInfo();
localImageMsgInfo.fileLocalPath = "/path/xxx.jpg"; // 图片绝对路径
messageInfoList.add(localImageMsgInfo);
// 文件:最多支持 1 个
ZIMImageMessageLiteInfo localFileMsgInfo = ZIMFileMessageLiteInfo();
localFileMsgInfo.fileLocalPath = "/path/xxx.zip"; // 文件绝对路径
messageInfoList.add(localFileMsgInfo);
// 音频:最多支持 1 个
ZIMAudioMessageLiteInfo localAudioMsgInfo = ZIMAudioMessageLiteInfo();
localAudioMsgInfo.fileLocalPath = "/path/xxx.mp3"; // 音频绝对路径
localAudioMsgInfo.audioDuration = 100; // 必填,播放时长,单位秒
messageInfoList.add(localAudioMsgInfo);
// 视频:最多支持 1 个
ZIMVideoMessageLiteInfo localVideoMsgInfo = ZIMVideoMessageLiteInfo();
localVideoMsgInfo.fileLocalPath = "/path/xxx.mp4"; // 视频绝对路径
localVideoMsgInfo.videoDuration = 100; // 必填,播放时长,单位秒
messageInfoList.add(localVideoMsgInfo);
ZIMMultipleMessage zimMultipleMessage = ZIMMultipleMessage(messageInfos);
zimMultipleMessage.messageInfoList = messageInfoList;
ZIMMessageSendNotification notification = ZIMMessageSendNotification(
    onMessageAttached: (message){
        // 开发者可以监听这个回调执行消息发送前的业务逻辑
    },
    onMultipleMediaUploadingProgress: (
        message,
        currentFileSize,      // 已上传文件总大小,单位为 Byte。比如已上传了 20,971,520 Byte,则此处为 20,971,520。
        totalFileSize,        // 总文件大小,单位为 Byte。比如总文件大小 104,857,600 Byte,则此处为 104,857,600
        messageInfoIndex,     // 接收到此回调时,当前正在上传的文件在 messageInfoList 数组的索引
        currentIndexFileSize, // 接收到此回调时,当前正在上传的文件的已上传大小,单位为 Byte。
        totalIndexFileSize    // 接收到此回调时,当前正在上传的文件的实际大小,单位为 Byte。
    ){
        // 开发者可以监听这个回调获取多媒体上传的进度
        // 总文件上传进度: currentFileSize / totalFileSize
        // 上述例子中,总文件上传进度为:20,971,520 / 104,857,600 = 20% 
        // 接收此回调时,当前正在上传的文件的上传进度:currentIndexFileSize / totalIndexFileSize
    }
);
// 发送消息的高级属性配置
ZIMMessageSendConfig config = ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.low;
ZIMConversationType type = ZIMConversationType.Peer;
ZIM.getInstance().sendMessage(zimMultipleMessage, userID, type, config, notification).then((value) {
    // 发送成功回调
  }).catchError((onError){
    // 处理失败
  });@ 消息
@ 消息,是指包含“@ + 用户”内容的消息。被 @ 的用户在收到消息时会强提醒。

仅 2.14.0 及以上版本的 ZIM SDK 支持发送消息中带 @ 信息。
@ 消息不属于消息类型,是消息对象的属性。一条消息既可以是文本消息或其他类型消息,同时也是 @ 消息。
在调用 sendMessage 发送消息时,可以通过以下属性或方法(可同时使用)将一条消息设置为 @ 信息:
- mentionedUserIDs:提醒指定用户(可以是会话外用户)查看消息。传入的 userID 列表长度最多为 50,如需上调,请联系 ZEGO 技术支持。
- isMentionAll:提醒会话内所有其他用户查看消息。
// 以下为用户在单聊会话中发送 @ 消息的示例代码:
// 创建提醒用户列表
ArrayList<String> mentionArrayList = new ArrayList<>();
// 添加提醒用户(用户可以不在当前会话)
mentionArrayList.add("userId1");
mentionArrayList.add("userId2");
// message 可以为任何类型消息
// 调用接口提醒列表中用户查看消息
message.setMentionedUserIDs(mentionArrayList);
// 提醒会话内所有其他用户查看消息
boolean isMentionAll = true;
message.setIsMentionAll(isMentionAll);
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 是否强推送给被提醒用户(不管对方是否开启了会话免打扰),默认为true;
config.isNotifyMentionedUsers = true;
// 以发送单聊信息为例子
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(message, "conv_id", type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});// 以下为用户在单聊会话中发送 @ 消息的示例代码:
// 创建提醒用户列表
ArrayList<String> mentionArrayList = new ArrayList<>();
// 添加提醒用户(用户可以不在当前会话)
mentionArrayList.add("userId1");
mentionArrayList.add("userId2");
// message 可以为任何类型消息
// 调用接口提醒列表中用户查看消息
message.setMentionedUserIDs(mentionArrayList);
// 提醒会话内所有其他用户查看消息
boolean isMentionAll = true;
message.setIsMentionAll(isMentionAll);
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 是否强推送给被提醒用户(不管对方是否开启了会话免打扰),默认为true;
config.isNotifyMentionedUsers = true;
// 以发送单聊信息为例子
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(message, "conv_id", type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});// 以下为用户在单聊会话中发送 @ 消息的示例代码:
// 创建提醒用户列表
NSMutableArray<NSString *> *mentionArrayList = [[NSMutableArray alloc] init];
// 添加提醒用户(用户可以不在当前会话)
[mentionArrayList addObject:@"userId1"];
[mentionArrayList addObject:@"userId2"];
// message 可以为任何类型消息
// 调用接口提醒列表中用户查看消息
[message mentionedUserIDs:mentionArrayList];
// 提醒会话内所有其他用户查看消息
BOOL isMentionAll = YES;
[message isMentionAll:isMentionAll];
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
// 是否强推送给被提醒用户(不管对方是否开启了会话免打扰),默认为 YES;
config.isNotifyMentionedUsers = YES;
// 以发送单聊信息为例
ZIMConversationType type = ZIMConversationTypePeer;
[zim sendMessage:message convId:@"conv_id" type:type config:config callback:^(ZIMMessage *zimMessage, ZIMError *error) {
    if (error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
}];// 以下为用户在单聊会话中发送 @ 消息的示例代码:
// 创建提醒用户列表
NSMutableArray<NSString *> *mentionArrayList = [[NSMutableArray alloc] init];
// 添加提醒用户(用户可以不在当前会话)
[mentionArrayList addObject:@"userId1"];
[mentionArrayList addObject:@"userId2"];
// message 可以为任何类型消息
// 调用接口提醒列表中用户查看消息
[message mentionedUserIDs:mentionArrayList];
// 提醒会话内所有其他用户查看消息
BOOL isMentionAll = YES;
[message isMentionAll:isMentionAll];
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
// 是否强推送给被提醒用户(不管对方是否开启了会话免打扰),默认为 YES;
config.isNotifyMentionedUsers = YES;
// 以发送单聊信息为例
ZIMConversationType type = ZIMConversationTypePeer;
[zim sendMessage:message convId:@"conv_id" type:type config:config callback:^(ZIMMessage *zimMessage, ZIMError *error) {
    if (error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
}];// 创建提醒用户列表
std::vector<std::string> mentionArrayList;
// 添加提醒用户(用户可以不在当前会话)
mentionArrayList.push_back("userId1");
mentionArrayList.push_back("userId2");
// message 可以为任何类型消息
message->mentionedUserIDs = mentionArrayList;
// 提醒会话内所有其他用户查看消息
bool isMentionAll = true;
message->isMentionAll = true;
ZIMMessageSendConfig config;
// 设置消息优先级
config.priority = ZIMMessagePriority::LOW;
// 是否强推送给被提醒用户(不管对方是否开启了会话免打扰),默认为 true;
config.isNotifyMentionedUsers = true;
// 以发送单聊信息为例子
ZIMConversationType type = ZIMConversationType::Peer;
zim_->sendMessage(
    message, "conv_id", type, config,
    std::make_shared<zim::ZIMMessageSendNotification>(
        [=](const std::shared_ptr<zim::ZIMMessage> &message) {
            if (message) {
                // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
            }
        }),
    [=](std::shared_ptr<zim::ZIMMessage> message, zim::ZIMError errorInfo) {
        // 开发者可以通过该回调监听消息是否发送成功。
        if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
            
        }
    });// 创建提醒用户列表
std::vector<std::string> mentionArrayList;
// 添加提醒用户(用户可以不在当前会话)
mentionArrayList.push_back("userId1");
mentionArrayList.push_back("userId2");
// message 可以为任何类型消息
message->mentionedUserIDs = mentionArrayList;
// 提醒会话内所有其他用户查看消息
bool isMentionAll = true;
message->isMentionAll = true;
ZIMMessageSendConfig config;
// 设置消息优先级
config.priority = ZIMMessagePriority::LOW;
// 是否强推送给被提醒用户(不管对方是否开启了会话免打扰),默认为 true;
config.isNotifyMentionedUsers = true;
// 以发送单聊信息为例子
ZIMConversationType type = ZIMConversationType::Peer;
zim_->sendMessage(
    message, "conv_id", type, config,
    std::make_shared<zim::ZIMMessageSendNotification>(
        [=](const std::shared_ptr<zim::ZIMMessage> &message) {
            if (message) {
                // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
            }
        }),
    [=](std::shared_ptr<zim::ZIMMessage> message, zim::ZIMError errorInfo) {
        // 开发者可以通过该回调监听消息是否发送成功。
        if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
            
        }
    });// 以下为用户在单聊会话中发送 @ 消息(文本消息)的示例代码:
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = '';
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageTextObj: ZIMMessage = {
    type: 1,
    message: 'xxxx',
    isMentionAll: true, // 提醒会话内所有其他用户查看消息
    mentionedUserIDs: ["userId1", "userId2"], // 提醒列表中用户查看消息
};
zim.sendMessage(messageTextObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 以下为用户在单聊会话中发送 @ 消息(文本消息)的示例代码:
// 单聊时,toConversationID 即是对方的 userID;群组时,toConversationID 即是群组的 groupID;房间时,toConversationID 即是房间的 roomID
const toConversationID = '';
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageTextObj: ZIMMessage = {
    type: 1,
    message: 'xxxx',
    isMentionAll: true, // 提醒会话内所有其他用户查看消息
    mentionedUserIDs: ["userId1", "userId2"], // 提醒列表中用户查看消息
};
zim.sendMessage(messageTextObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 以下为用户在单聊会话中发送 @ 消息的示例代码:
try {
    // 待提醒的用户列表
    List<String> memtionList = ['userID1', 'userID2'];
    // message 可以为任何类型消息
    // 调用接口提醒列表中用户查看消息
    message.mentionedUserIDs(memtionList);
    // 提醒会话内所有其他用户查看消息
    bool isMentionAll = true;
    message.isMentionAll(isMentionAll);
    ZIMMessageSendConfig config = ZIMMessageSendConfig();
    //设置消息优先级
    config.priority = ZIMMessagePriority.low;
    // 是否强推送给被提醒用户(不管对方是否开启了会话免打扰),默认为 true;
    config.isNotifyMentionedUsers = true;
    // 以发送单聊消息为例子
    ZIMConversationType type = ZIMConversationType.peer;
    ZIMMessageSentResult result = await ZIM.getInstance()!.sendMessage(message, 'conv_id', type, config);
    
} on PlatformException catch (onError){
    onError.code;//根据错误码表处理
    onError.message;//错误信息
}// 以下为用户在单聊会话中发送 @ 消息的示例代码:
try {
    // 待提醒的用户列表
    List<String> memtionList = ['userID1', 'userID2'];
    // message 可以为任何类型消息
    // 调用接口提醒列表中用户查看消息
    message.mentionedUserIDs(memtionList);
    // 提醒会话内所有其他用户查看消息
    bool isMentionAll = true;
    message.isMentionAll(isMentionAll);
    ZIMMessageSendConfig config = ZIMMessageSendConfig();
    //设置消息优先级
    config.priority = ZIMMessagePriority.low;
    // 是否强推送给被提醒用户(不管对方是否开启了会话免打扰),默认为 true;
    config.isNotifyMentionedUsers = true;
    // 以发送单聊消息为例子
    ZIMConversationType type = ZIMConversationType.peer;
    ZIMMessageSentResult result = await ZIM.getInstance()!.sendMessage(message, 'conv_id', type, config);
    
} on PlatformException catch (onError){
    onError.code;//根据错误码表处理
    onError.message;//错误信息
}接收消息
- 开发者可以通过 on 注册监听,用于接收消息相关通知。
- 开发者可以通过相关回调接收消息通知。
- 接收消息时:
- 单聊消息(Peer 类型),通过 peerMessageReceived 回调接收。
- 房间消息(Room 类型),通过 roomMessageReceived 回调接收。
- 群组消息(Group 类型),通过 groupMessageReceived 回调接收。
 
- 接收消息时,收到的消息类型是基类 ZIMMessage 。开发者需要根据其中的 type(具体请参考 ZIMMessageType )字段,判断消息类型,然后强转基类为具体的子类。
- 接收消息时,可以使用消息的 orderkey 来实现排序;即 orderkey 越大,消息的时间越新。接收到消息后,会自动更新消息未读数量。
zim.setEventHandler(new ZIMEventHandler() {
    @Override
    public void onPeerMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList, ZIMMessageReceivedInfo info, String fromUserID) {
        // 收到单聊消息的回调
        
        ZIMMediaDownloadConfig config = new ZIMMediaDownloadConfig();
        for (ZIMMessage zimMessage : messageList) {
           if (zimMessage instanceof ZIMTextMessage) {
                ZIMTextMessage zimTextMessage = (ZIMTextMessage) zimMessage;
           } else if (zimMessage instanceof ZIMBarrageMessage) {
                ZIMBarrageMessage zimBarrageMessage = (ZIMBarrageMessage) zimMessage;
           } else if (zimMessage instanceof ZIMCommandMessage) {
                ZIMCommandMessage zimCommandMessage = (ZIMCommandMessage) zimMessage;
           } else if (zimMessage instanceof ZIMCustomMessage) {
                ZIMCustomMessage zimCustomMessage = (ZIMCustomMessage) zimMessage;
           } else if (zimMessage instanceof ZIMMediaMessage) {
                // 下载富媒体文件消息
                ZIMMediaMessage zimMediaMessage = (ZIMMediaMessage) zimMessage;
                zim.downloadMediaFile(zimMediaMessage, ZIMMediaFileType.ORIGINAL_FILE, config, new ZIMMediaDownloadedCallback() {
                    @Override
                    public void onMediaDownloaded(ZIMMessage message, ZIMError errorInfo) {
                        // 下载完成回调
                    }
                    @Override
                    public void onMediaDownloadingProgress(ZIMMessage message, long currentFileSize, long totalFileSize) {
                        // 下载进度回调
                    }
                });
           } else if (zimMessage instanceof ZIMMultipleMessage) {
                // 下载组合消息中的富媒体文件
                ZIMMultipleMessage zimMultipleMessage = (ZIMMultipleMessage) zimMessage;
                ArrayList infos = zimMultipleMessage.getMessageInfoList();
                for (int i = 0; i < infos.size(); i++) {
                    if (infos.get(i) instanceof ZIMMediaMessageLiteInfo) {
                        ZIMMediaDownloadConfig messageInfoConfig = new ZIMMediaDownloadConfig();
                        // 设置为 item 的序号
                        messageInfoConfig.messageInfoIndex = i;
                        zim.downloadMediaFile(zimMultipleMessage, ZIMMediaFileType.ORIGINAL_FILE, messageInfoConfig, new ZIMMediaDownloadedCallback() {
                            @Override
                            public void onMediaDownloaded(ZIMMessage message, ZIMError errorInfo) {
                                // 下载完成回调
                            }
                            @Override
                            public void onMediaDownloadingProgress(ZIMMessage message, long currentFileSize, long totalFileSize) {
                                // 下载进度回调
                            }
                        });
                    }
                }
           } 
        }
    }
    @Override
    public void onGroupMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList, ZIMMessageReceivedInfo info, String fromGroupID) {
        // 收到群组消息的回调
    }
    @Override
    public void onRoomMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList, ZIMMessageReceivedInfo info, String fromRoomID) {
        // 收到房间消息的回调
    }
});zim.setEventHandler(new ZIMEventHandler() {
    @Override
    public void onPeerMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList, ZIMMessageReceivedInfo info, String fromUserID) {
        // 收到单聊消息的回调
        
        ZIMMediaDownloadConfig config = new ZIMMediaDownloadConfig();
        for (ZIMMessage zimMessage : messageList) {
           if (zimMessage instanceof ZIMTextMessage) {
                ZIMTextMessage zimTextMessage = (ZIMTextMessage) zimMessage;
           } else if (zimMessage instanceof ZIMBarrageMessage) {
                ZIMBarrageMessage zimBarrageMessage = (ZIMBarrageMessage) zimMessage;
           } else if (zimMessage instanceof ZIMCommandMessage) {
                ZIMCommandMessage zimCommandMessage = (ZIMCommandMessage) zimMessage;
           } else if (zimMessage instanceof ZIMCustomMessage) {
                ZIMCustomMessage zimCustomMessage = (ZIMCustomMessage) zimMessage;
           } else if (zimMessage instanceof ZIMMediaMessage) {
                // 下载富媒体文件消息
                ZIMMediaMessage zimMediaMessage = (ZIMMediaMessage) zimMessage;
                zim.downloadMediaFile(zimMediaMessage, ZIMMediaFileType.ORIGINAL_FILE, config, new ZIMMediaDownloadedCallback() {
                    @Override
                    public void onMediaDownloaded(ZIMMessage message, ZIMError errorInfo) {
                        // 下载完成回调
                    }
                    @Override
                    public void onMediaDownloadingProgress(ZIMMessage message, long currentFileSize, long totalFileSize) {
                        // 下载进度回调
                    }
                });
           } else if (zimMessage instanceof ZIMMultipleMessage) {
                // 下载组合消息中的富媒体文件
                ZIMMultipleMessage zimMultipleMessage = (ZIMMultipleMessage) zimMessage;
                ArrayList infos = zimMultipleMessage.getMessageInfoList();
                for (int i = 0; i < infos.size(); i++) {
                    if (infos.get(i) instanceof ZIMMediaMessageLiteInfo) {
                        ZIMMediaDownloadConfig messageInfoConfig = new ZIMMediaDownloadConfig();
                        // 设置为 item 的序号
                        messageInfoConfig.messageInfoIndex = i;
                        zim.downloadMediaFile(zimMultipleMessage, ZIMMediaFileType.ORIGINAL_FILE, messageInfoConfig, new ZIMMediaDownloadedCallback() {
                            @Override
                            public void onMediaDownloaded(ZIMMessage message, ZIMError errorInfo) {
                                // 下载完成回调
                            }
                            @Override
                            public void onMediaDownloadingProgress(ZIMMessage message, long currentFileSize, long totalFileSize) {
                                // 下载进度回调
                            }
                        });
                    }
                }
           } 
        }
    }
    @Override
    public void onGroupMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList, ZIMMessageReceivedInfo info, String fromGroupID) {
        // 收到群组消息的回调
    }
    @Override
    public void onRoomMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList, ZIMMessageReceivedInfo info, String fromRoomID) {
        // 收到房间消息的回调
    }
});//注册 ZIMEventHander 回调
[zim setEventHandler:self];
// 收到单聊消息的回调
- (void)zim:(ZIM *)zim
    peerMessageReceived:(NSArray<ZIMMessage *> *)messageList
            info:(ZIMMessageReceivedInfo *)info
            fromUserID:(NSString *)fromUserID {
                
    ZIMMediaDownloadConfig *config = [[ZIMMediaDownloadConfig alloc] init];
    for (ZIMMessage *msg in messageList) {
        if(msg.type == ZIMMessageTypeCommand){
            ZIMCommandMessage *cmdMsg = (ZIMCommandMessage *)msg;
            NSData *receivedData = cmdMsg.message;
        } else if(msg.type == ZIMMessageTypeCustom){
            ZIMCustomMessage *customMsg = (ZIMCustomMessage *)msg;
        } else if(msg.type == ZIMMessageTypeImage || msg.type == ZIMMessageTypeFile || msg.type == ZIMMessageTypeAudio || msg.type == ZIMMessageTypeVideo){
            // 下载富媒体文件消息
            ZIMMediaMessage *mediaMsg = (ZIMMediaMessage *)msg;
            [[ZIM getInstance] downloadMediaFileWithMessage:mediaMsg fileType:ZIMMediaFileTypeOriginalFile config:config
                progress:^(ZIMMessage * _Nonnull message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
                    // 下载进度
                } callback:^(ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo) {
                    // 下载结果 
                }];
        } else if(msg.type == ZIMMessageTypeMultiple){
            // 下载组合消息中的富媒体文件
            ZIMMultipleMessage *multipleMsg = (ZIMMultipleMessage *)msg;
            NSArray<ZIMMessageLiteInfo *> *infos = multipleMsg.messageInfoList;
            for (NSUInteger i = 0; i < [infos count]; i++) {
                ZIMMessageLiteInfo *info = infos[i];
                if (info.type == ZIMMessageTypeImage || info.type == ZIMMessageTypeFile || info.type == ZIMMessageTypeAudio || info.type == ZIMMessageTypeVideo) {
                    ZIMMediaDownloadConfig *infoConfig = [[ZIMMediaDownloadConfig alloc] init];
                    // 设置为 item 的序号
                    infoConfig.messageInfoIndex = i;
                    [[ZIM getInstance] downloadMediaFileWithMessage:multipleMsg fileType:ZIMMediaFileTypeOriginalFile config:infoConfig
                        progress:^(ZIMMessage * _Nonnull message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
                            // 下载进度
                        } callback:^(ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo) {
                            // 下载结果 
                        }];
                }
            }
        } 
    }        
}
// 收到群组消息的回调
- (void)zim:(ZIM *)zim
    groupMessageReceived:(NSArray<ZIMMessage *> *)messageList
            info:(ZIMMessageReceivedInfo *)info
            fromGroupID:(NSString *)fromGroupID{
}
// 收到房间消息的回调
- (void)zim:(ZIM *)zim
    roomMessageReceived:(NSArray<ZIMMessage *> *)messageList
            info:(ZIMMessageReceivedInfo *)info
            fromRoomID:(NSString *)fromRoomID{
}//注册 ZIMEventHander 回调
[zim setEventHandler:self];
// 收到单聊消息的回调
- (void)zim:(ZIM *)zim
    peerMessageReceived:(NSArray<ZIMMessage *> *)messageList
            info:(ZIMMessageReceivedInfo *)info
            fromUserID:(NSString *)fromUserID {
                
    ZIMMediaDownloadConfig *config = [[ZIMMediaDownloadConfig alloc] init];
    for (ZIMMessage *msg in messageList) {
        if(msg.type == ZIMMessageTypeCommand){
            ZIMCommandMessage *cmdMsg = (ZIMCommandMessage *)msg;
            NSData *receivedData = cmdMsg.message;
        } else if(msg.type == ZIMMessageTypeCustom){
            ZIMCustomMessage *customMsg = (ZIMCustomMessage *)msg;
        } else if(msg.type == ZIMMessageTypeImage || msg.type == ZIMMessageTypeFile || msg.type == ZIMMessageTypeAudio || msg.type == ZIMMessageTypeVideo){
            // 下载富媒体文件消息
            ZIMMediaMessage *mediaMsg = (ZIMMediaMessage *)msg;
            [[ZIM getInstance] downloadMediaFileWithMessage:mediaMsg fileType:ZIMMediaFileTypeOriginalFile config:config
                progress:^(ZIMMessage * _Nonnull message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
                    // 下载进度
                } callback:^(ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo) {
                    // 下载结果 
                }];
        } else if(msg.type == ZIMMessageTypeMultiple){
            // 下载组合消息中的富媒体文件
            ZIMMultipleMessage *multipleMsg = (ZIMMultipleMessage *)msg;
            NSArray<ZIMMessageLiteInfo *> *infos = multipleMsg.messageInfoList;
            for (NSUInteger i = 0; i < [infos count]; i++) {
                ZIMMessageLiteInfo *info = infos[i];
                if (info.type == ZIMMessageTypeImage || info.type == ZIMMessageTypeFile || info.type == ZIMMessageTypeAudio || info.type == ZIMMessageTypeVideo) {
                    ZIMMediaDownloadConfig *infoConfig = [[ZIMMediaDownloadConfig alloc] init];
                    // 设置为 item 的序号
                    infoConfig.messageInfoIndex = i;
                    [[ZIM getInstance] downloadMediaFileWithMessage:multipleMsg fileType:ZIMMediaFileTypeOriginalFile config:infoConfig
                        progress:^(ZIMMessage * _Nonnull message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
                            // 下载进度
                        } callback:^(ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo) {
                            // 下载结果 
                        }];
                }
            }
        } 
    }        
}
// 收到群组消息的回调
- (void)zim:(ZIM *)zim
    groupMessageReceived:(NSArray<ZIMMessage *> *)messageList
            info:(ZIMMessageReceivedInfo *)info
            fromGroupID:(NSString *)fromGroupID{
}
// 收到房间消息的回调
- (void)zim:(ZIM *)zim
    roomMessageReceived:(NSArray<ZIMMessage *> *)messageList
            info:(ZIMMessageReceivedInfo *)info
            fromRoomID:(NSString *)fromRoomID{
}// 收到单聊消息的回调
void onPeerMessagedReceived(ZIM *zim*,
                         const std::vector<std::shared_ptr<ZIMMessage>> & messageList,
                         const ZIMMessageReceivedInfo & info,
                         const std::string &fromUserID) {
    zim::ZIMMediaDownloadConfig download_config;
    for (auto &it : message_list) {
        zim::ZIMMessageType type = it->getType();
        if (type == zim::ZIM_MESSAGE_TYPE_COMMAND) {
            auto commandMessage = std::dynamic_pointer_cast<zim::ZIMCommandMessage>(it);
        } else if (type == zim::ZIM_MESSAGE_TYPE_CUSTOM) {
            auto customMessage = std::dynamic_pointer_cast<zim::ZIMCustomMessage>(it);
        } else if (type == zim::ZIMMessageType::ZIM_MESSAGE_TYPE_IMAGE
            || type == zim::ZIMMessageType::ZIM_MESSAGE_TYPE_FILE
            || type == zim::ZIMMessageType::ZIM_MESSAGE_TYPE_AUDIO
            || type == zim::ZIMMessageType::ZIM_MESSAGE_TYPE_VIDEO) {
            // 下载富媒体文件消息
            auto mediaMessage = std::dynamic_pointer_cast<zim::ZIMMediaMessage>(it);
            zim->downloadMediaFile(
                mediaMessage.get(),
                zim::ZIMMediaFileType::ZIM_MEDIA_FILE_TYPE_ORIGINAL_FILE,
                download_config,
                [=](const std::shared_ptr<zim::ZIMMessage> &message, unsigned long long currentSize,
                    unsigned long long totalSize) {
                    // 下载进度
                },
                [=](const std::shared_ptr<zim::ZIMMessage> &message,
                    const zim::ZIMError &errorInfo) {
                });
        } else if (type == zim::ZIM_MESSAGE_TYPE_MULTIPLE) {
            // 下载组合消息中的富媒体文件
            auto multipleMessage = std::dynamic_pointer_cast<zim::ZIMMultipleMessage>(it);
            const auto &infoList = multipleMessage->messageInfoList;
            for (size_t i = 0; i < infoList.size(); ++i) {
                auto &infoItem = infoList[i];
                zim::ZIMMessageType subType = infoItem->type;
                if (subType == zim::ZIM_MESSAGE_TYPE_IMAGE ||
                    subType == zim::ZIM_MESSAGE_TYPE_FILE ||
                    subType == zim::ZIM_MESSAGE_TYPE_AUDIO ||
                    subType == zim::ZIM_MESSAGE_TYPE_VIDEO) {
                    zim::ZIMMediaDownloadConfig itemConfig;
                    // 设置为 item 的序号
                    itemConfig.messageInfoIndex = static_cast<int>(i);
                    zim->downloadMediaFile(
                        multipleMessage.get(),
                        zim::ZIMMediaFileType::ZIM_MEDIA_FILE_TYPE_ORIGINAL_FILE,
                        itemConfig,
                        // 下载进度
                        [&](const std::shared_ptr<zim::ZIMMessage> &message,
                            unsigned long long currentSize,
                            unsigned long long totalSize) {
                            // TODO: 处理组合消息子项的下载进度
                        },
                        // 下载完成
                        [&](const std::shared_ptr<zim::ZIMMessage> &message,
                            const zim::ZIMError &errorInfo) {
                            // TODO: 组合消息子项下载完成
                        });
                }
            }
        } 
    }
}
// 收到群组消息的回调
void onGroupMessagedReceived(ZIM *zim*,
                         const std::vector<std::shared_ptr<ZIMMessage>> & messageList,
                         const ZIMMessageReceivedInfo & info,
                         const std::string &fromGroupID) {
}
// 收到房间消息的回调
void onRoomMessagedReceived(ZIM *zim*,
                         const std::vector<std::shared_ptr<ZIMMessage>> & messageList,
                         const ZIMMessageReceivedInfo & info,
                         const std::string &fromRoomID) {
}// 收到单聊消息的回调
void onPeerMessagedReceived(ZIM *zim*,
                         const std::vector<std::shared_ptr<ZIMMessage>> & messageList,
                         const ZIMMessageReceivedInfo & info,
                         const std::string &fromUserID) {
    zim::ZIMMediaDownloadConfig download_config;
    for (auto &it : message_list) {
        zim::ZIMMessageType type = it->getType();
        if (type == zim::ZIM_MESSAGE_TYPE_COMMAND) {
            auto commandMessage = std::dynamic_pointer_cast<zim::ZIMCommandMessage>(it);
        } else if (type == zim::ZIM_MESSAGE_TYPE_CUSTOM) {
            auto customMessage = std::dynamic_pointer_cast<zim::ZIMCustomMessage>(it);
        } else if (type == zim::ZIMMessageType::ZIM_MESSAGE_TYPE_IMAGE
            || type == zim::ZIMMessageType::ZIM_MESSAGE_TYPE_FILE
            || type == zim::ZIMMessageType::ZIM_MESSAGE_TYPE_AUDIO
            || type == zim::ZIMMessageType::ZIM_MESSAGE_TYPE_VIDEO) {
            // 下载富媒体文件消息
            auto mediaMessage = std::dynamic_pointer_cast<zim::ZIMMediaMessage>(it);
            zim->downloadMediaFile(
                mediaMessage.get(),
                zim::ZIMMediaFileType::ZIM_MEDIA_FILE_TYPE_ORIGINAL_FILE,
                download_config,
                [=](const std::shared_ptr<zim::ZIMMessage> &message, unsigned long long currentSize,
                    unsigned long long totalSize) {
                    // 下载进度
                },
                [=](const std::shared_ptr<zim::ZIMMessage> &message,
                    const zim::ZIMError &errorInfo) {
                });
        } else if (type == zim::ZIM_MESSAGE_TYPE_MULTIPLE) {
            // 下载组合消息中的富媒体文件
            auto multipleMessage = std::dynamic_pointer_cast<zim::ZIMMultipleMessage>(it);
            const auto &infoList = multipleMessage->messageInfoList;
            for (size_t i = 0; i < infoList.size(); ++i) {
                auto &infoItem = infoList[i];
                zim::ZIMMessageType subType = infoItem->type;
                if (subType == zim::ZIM_MESSAGE_TYPE_IMAGE ||
                    subType == zim::ZIM_MESSAGE_TYPE_FILE ||
                    subType == zim::ZIM_MESSAGE_TYPE_AUDIO ||
                    subType == zim::ZIM_MESSAGE_TYPE_VIDEO) {
                    zim::ZIMMediaDownloadConfig itemConfig;
                    // 设置为 item 的序号
                    itemConfig.messageInfoIndex = static_cast<int>(i);
                    zim->downloadMediaFile(
                        multipleMessage.get(),
                        zim::ZIMMediaFileType::ZIM_MEDIA_FILE_TYPE_ORIGINAL_FILE,
                        itemConfig,
                        // 下载进度
                        [&](const std::shared_ptr<zim::ZIMMessage> &message,
                            unsigned long long currentSize,
                            unsigned long long totalSize) {
                            // TODO: 处理组合消息子项的下载进度
                        },
                        // 下载完成
                        [&](const std::shared_ptr<zim::ZIMMessage> &message,
                            const zim::ZIMError &errorInfo) {
                            // TODO: 组合消息子项下载完成
                        });
                }
            }
        } 
    }
}
// 收到群组消息的回调
void onGroupMessagedReceived(ZIM *zim*,
                         const std::vector<std::shared_ptr<ZIMMessage>> & messageList,
                         const ZIMMessageReceivedInfo & info,
                         const std::string &fromGroupID) {
}
// 收到房间消息的回调
void onRoomMessagedReceived(ZIM *zim*,
                         const std::vector<std::shared_ptr<ZIMMessage>> & messageList,
                         const ZIMMessageReceivedInfo & info,
                         const std::string &fromRoomID) {
}// 收到单消息的回调
zim.on('peerMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
    data.messageList.forEach((msg) => {
        if (msg.type == 2) {
            // 信令消息,这里以 JSON 字符串 为例,将 Uint8Array 消息内容转为 JSON 字符串
            const uint8Array = msg.message;
            const jsonText = decodeURIComponent(escape(String.fromCharCode(...Array.from(uint8Array))));
            const jsonObj = JSON.parse(jsonText);
        } 
        // 富媒体文件消息的 URL
        else if (msg.type == 11) {
            console.log(msg.thumbnailDownloadUrl, msg.largeImageDownloadUrl, msg.fileDownloadUrl);
        } else if (msg.type == 12) {
            console.log(msg.fileDownloadUrl);
        } else if (msg.type == 13) {
            console.log(msg.fileDownloadUrl);
        } else if (msg.type == 14) {
            console.log(msg.videoFirstFrameDownloadUrl, msg.fileDownloadUrl);
        } else if (msg.type == 10) {
            // 组合消息中的富媒体文件的 URL
            msg.messageInfoList.forEach((info) => {
                if (info.type == 11) {
                    console.log(info.thumbnailDownloadUrl, info.largeImageDownloadUrl, info.fileDownloadUrl);
                } else if (info.type == 12) {
                    console.log(info.fileDownloadUrl);
                } else if (info.type == 13) {
                    console.log(info.fileDownloadUrl);
                } else if (info.type == 14) {
                    console.log(info.videoFirstFrameDownloadUrl, info.fileDownloadUrl);
                } 
            }
        }
    })
});
// 收到群组消息的回调
zim.on('groupMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
});
// 收到房间消息的回调
zim.on('roomMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
});// 收到单消息的回调
zim.on('peerMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
    data.messageList.forEach((msg) => {
        if (msg.type == 2) {
            // 信令消息,这里以 JSON 字符串 为例,将 Uint8Array 消息内容转为 JSON 字符串
            const uint8Array = msg.message;
            const jsonText = decodeURIComponent(escape(String.fromCharCode(...Array.from(uint8Array))));
            const jsonObj = JSON.parse(jsonText);
        } 
        // 富媒体文件消息的 URL
        else if (msg.type == 11) {
            console.log(msg.thumbnailDownloadUrl, msg.largeImageDownloadUrl, msg.fileDownloadUrl);
        } else if (msg.type == 12) {
            console.log(msg.fileDownloadUrl);
        } else if (msg.type == 13) {
            console.log(msg.fileDownloadUrl);
        } else if (msg.type == 14) {
            console.log(msg.videoFirstFrameDownloadUrl, msg.fileDownloadUrl);
        } else if (msg.type == 10) {
            // 组合消息中的富媒体文件的 URL
            msg.messageInfoList.forEach((info) => {
                if (info.type == 11) {
                    console.log(info.thumbnailDownloadUrl, info.largeImageDownloadUrl, info.fileDownloadUrl);
                } else if (info.type == 12) {
                    console.log(info.fileDownloadUrl);
                } else if (info.type == 13) {
                    console.log(info.fileDownloadUrl);
                } else if (info.type == 14) {
                    console.log(info.videoFirstFrameDownloadUrl, info.fileDownloadUrl);
                } 
            }
        }
    })
});
// 收到群组消息的回调
zim.on('groupMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
});
// 收到房间消息的回调
zim.on('roomMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
});// 收到单消息的回调
zim.on('peerMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
    
    const config: ZIMMediaDownloadConfig = {messageInfoIndex: 0};
    data.messageList.forEach((msg) => {
        if (msg.type == 2) {
            // 信令消息,这里以 JSON 字符串 为例,将 Uint8Array 消息内容转为 JSON 字符串
            const uint8Array = msg.message;
            const jsonText = decodeURIComponent(escape(String.fromCharCode(...Array.from(uint8Array))));
            const jsonObj = JSON.parse(jsonText);
        } else if (msg.type == 11 || msg.type == 12 || msg.type == 13 || msg.type == 14) {
            // 下载富媒体文件消息
            zim.downloadMediaFile(msg, 1, config, (_msg, currentFileSize, totalFileSize) => {
                // 下载进度
            })
            .then((res: ZIMMediaDownloadedResult) => {
                // 操作成功
            })
            .catch((err: ZIMError) => {
                // 操作失败
            })
        } else if (msg.type == 10) {
            // 下载组合消息中的富媒体文件
            msg.messageInfoList.forEach((info, i) => {
                if (info.type == 11 || info.type == 12 || info.type == 13 || info.type == 14) {
                    // 设置为 item 的序号
                    const infoConfig: ZIMMediaDownloadConfig = {messageInfoIndex: i};
                    zim.downloadMediaFile(msg, 1, infoConfig, (_msg, currentFileSize, totalFileSize) => {
                        // 下载进度
                    })
                    .then((res: ZIMMediaDownloadedResult) => {
                        // 操作成功
                    })
                    .catch((err: ZIMError) => {
                        // 操作失败
                    })
                } 
            }
        }
    })
});
// 收到群组消息的回调
zim.on('groupMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
});
// 收到房间消息的回调
zim.on('roomMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
});// 收到单消息的回调
zim.on('peerMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
    
    const config: ZIMMediaDownloadConfig = {messageInfoIndex: 0};
    data.messageList.forEach((msg) => {
        if (msg.type == 2) {
            // 信令消息,这里以 JSON 字符串 为例,将 Uint8Array 消息内容转为 JSON 字符串
            const uint8Array = msg.message;
            const jsonText = decodeURIComponent(escape(String.fromCharCode(...Array.from(uint8Array))));
            const jsonObj = JSON.parse(jsonText);
        } else if (msg.type == 11 || msg.type == 12 || msg.type == 13 || msg.type == 14) {
            // 下载富媒体文件消息
            zim.downloadMediaFile(msg, 1, config, (_msg, currentFileSize, totalFileSize) => {
                // 下载进度
            })
            .then((res: ZIMMediaDownloadedResult) => {
                // 操作成功
            })
            .catch((err: ZIMError) => {
                // 操作失败
            })
        } else if (msg.type == 10) {
            // 下载组合消息中的富媒体文件
            msg.messageInfoList.forEach((info, i) => {
                if (info.type == 11 || info.type == 12 || info.type == 13 || info.type == 14) {
                    // 设置为 item 的序号
                    const infoConfig: ZIMMediaDownloadConfig = {messageInfoIndex: i};
                    zim.downloadMediaFile(msg, 1, infoConfig, (_msg, currentFileSize, totalFileSize) => {
                        // 下载进度
                    })
                    .then((res: ZIMMediaDownloadedResult) => {
                        // 操作成功
                    })
                    .catch((err: ZIMError) => {
                        // 操作失败
                    })
                } 
            }
        }
    })
});
// 收到群组消息的回调
zim.on('groupMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
});
// 收到房间消息的回调
zim.on('roomMessageReceived', (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => {
});// 收到单聊消息的回调
zim.onPeerMessageReceived((data) => {
    
    const config: ZIMMediaDownloadConfig = {messageInfoIndex: 0};
    data.messageList.forEach((msg) => {
        if (msg.type == 2) {
            // 信令消息
            const byteArray = msg.message;
        } else if (msg.type == 11 || msg.type == 12 || msg.type == 13 || msg.type == 14) {
            // 下载富媒体文件消息
            zim.downloadMediaFile(msg, 1, config, (_msg, currentFileSize, totalFileSize) => {
                // 下载进度
            })
            .then((res: ZIMMediaDownloadedResult) => {
                // 操作成功
            })
            .catch((err: ZIMError) => {
                // 操作失败
            })
        } else if (msg.type == 10) {
            // 下载组合消息中的富媒体文件
            msg.messageInfoList.forEach((info, i) => {
                if (info.type == 11 || info.type == 12 || info.type == 13 || info.type == 14) {
                    // 设置为 item 的序号
                    const infoConfig: ZIMMediaDownloadConfig = {messageInfoIndex: i};
                    zim.downloadMediaFile(msg, 1, infoConfig, (_msg, currentFileSize, totalFileSize) => {
                        // 下载进度
                    })
                    .then((res: ZIMMediaDownloadedResult) => {
                        // 操作成功
                    })
                    .catch((err: ZIMError) => {
                        // 操作失败
                    })
                } 
            }
        }
    })
});
// 收到群组消息的回调
zim.onGroupMessageReceived((data) => {
});
// 收到房间消息的回调
zim.onRoomMessageReceived((data) => {
});// 收到单聊消息的回调
zim.onPeerMessageReceived((data) => {
    
    const config: ZIMMediaDownloadConfig = {messageInfoIndex: 0};
    data.messageList.forEach((msg) => {
        if (msg.type == 2) {
            // 信令消息
            const byteArray = msg.message;
        } else if (msg.type == 11 || msg.type == 12 || msg.type == 13 || msg.type == 14) {
            // 下载富媒体文件消息
            zim.downloadMediaFile(msg, 1, config, (_msg, currentFileSize, totalFileSize) => {
                // 下载进度
            })
            .then((res: ZIMMediaDownloadedResult) => {
                // 操作成功
            })
            .catch((err: ZIMError) => {
                // 操作失败
            })
        } else if (msg.type == 10) {
            // 下载组合消息中的富媒体文件
            msg.messageInfoList.forEach((info, i) => {
                if (info.type == 11 || info.type == 12 || info.type == 13 || info.type == 14) {
                    // 设置为 item 的序号
                    const infoConfig: ZIMMediaDownloadConfig = {messageInfoIndex: i};
                    zim.downloadMediaFile(msg, 1, infoConfig, (_msg, currentFileSize, totalFileSize) => {
                        // 下载进度
                    })
                    .then((res: ZIMMediaDownloadedResult) => {
                        // 操作成功
                    })
                    .catch((err: ZIMError) => {
                        // 操作失败
                    })
                } 
            }
        }
    })
});
// 收到群组消息的回调
zim.onGroupMessageReceived((data) => {
});
// 收到房间消息的回调
zim.onRoomMessageReceived((data) => {
});ZIMEventHandler.onPeerMessageReceived = (zim, messageList, info, fromUserID) {
    
    ZIMMediaDownloadConfig config = ZIMMediaDownloadConfig();
    for (ZIMMessage message in messageList) {
        switch (message.type) {
            case ZIMMessageType.command:
                message as ZIMCommandMessage;
                break;
            case ZIMMessageType.custom:
                message as ZIMCustomMessage;
                break;
            // 下载富媒体文件消息    
            case ZIMMessageType.image:
            case ZIMMessageType.video:
            case ZIMMessageType.audio:
            case ZIMMessageType.file:
                message as ZIMMediaMessage;
                zim.downloadMediaFile(message, ZIMMediaFileType.originalFile, config, (ZIMMessage message, int currentFileSize, int totalFileSize) {
                    // 下载进度
                }).then((ZIMMessage message) {
                    // 下载完成
                }).catch((ZIMError errorInfo) {
                    // 下载失败
                });
                break;        
            // 下载组合消息中的富媒体文件
            case ZIMMessageType.multiple:
                message as ZIMMultipleMessage;
                List<ZIMMessageLiteInfo> infos = message.messageInfoList;
                for (int i = 0; i < infos.length; i++) {
                    if (infos[i] is ZIMMediaMessageLiteInfo) {
                        ZIMMediaDownloadConfig messageInfoConfig = ZIMMediaDownloadConfig();
                        // 设置为 item 的序号
                        messageInfoConfig.messageInfoIndex = i;
                        zim.downloadMediaFile(message, ZIMMediaFileType.originalFile, messageInfoConfig, (ZIMMessage message, int currentFileSize, int totalFileSize) {
                            // 下载进度
                        }).then((ZIMMessage message) {
                            // 下载完成
                        }).catch((ZIMError errorInfo) {
                            // 下载失败
                        });
                    }
                }
                break;
            default:
                break;
        }
    }
};
ZIMEventHandler.onGroupMessageReceived = (zim, messageList, info, fromGroupID) {
    //收到群聊消息触发此处
};
ZIMEventHandler.onRoomMessageReceived = (zim, messageList, info, fromGroupID) {
  //收到房间消息触发此处
};ZIMEventHandler.onPeerMessageReceived = (zim, messageList, info, fromUserID) {
    
    ZIMMediaDownloadConfig config = ZIMMediaDownloadConfig();
    for (ZIMMessage message in messageList) {
        switch (message.type) {
            case ZIMMessageType.command:
                message as ZIMCommandMessage;
                break;
            case ZIMMessageType.custom:
                message as ZIMCustomMessage;
                break;
            // 下载富媒体文件消息    
            case ZIMMessageType.image:
            case ZIMMessageType.video:
            case ZIMMessageType.audio:
            case ZIMMessageType.file:
                message as ZIMMediaMessage;
                zim.downloadMediaFile(message, ZIMMediaFileType.originalFile, config, (ZIMMessage message, int currentFileSize, int totalFileSize) {
                    // 下载进度
                }).then((ZIMMessage message) {
                    // 下载完成
                }).catch((ZIMError errorInfo) {
                    // 下载失败
                });
                break;        
            // 下载组合消息中的富媒体文件
            case ZIMMessageType.multiple:
                message as ZIMMultipleMessage;
                List<ZIMMessageLiteInfo> infos = message.messageInfoList;
                for (int i = 0; i < infos.length; i++) {
                    if (infos[i] is ZIMMediaMessageLiteInfo) {
                        ZIMMediaDownloadConfig messageInfoConfig = ZIMMediaDownloadConfig();
                        // 设置为 item 的序号
                        messageInfoConfig.messageInfoIndex = i;
                        zim.downloadMediaFile(message, ZIMMediaFileType.originalFile, messageInfoConfig, (ZIMMessage message, int currentFileSize, int totalFileSize) {
                            // 下载进度
                        }).then((ZIMMessage message) {
                            // 下载完成
                        }).catch((ZIMError errorInfo) {
                            // 下载失败
                        });
                    }
                }
                break;
            default:
                break;
        }
    }
};
ZIMEventHandler.onGroupMessageReceived = (zim, messageList, info, fromGroupID) {
    //收到群聊消息触发此处
};
ZIMEventHandler.onRoomMessageReceived = (zim, messageList, info, fromGroupID) {
  //收到房间消息触发此处
};富媒体消息
接收富媒体消息时,可以直接获取富媒体消息的相关 URL 属性。
如需下载富媒体消息到本地,可调用 downloadMediaFile 接口。
下载富媒体消息时,需要指定对应的媒体消息的文件类型。
- 图片消息:可以选择下载原始文件、大图、缩略图。
- 文件/音频消息:仅能选择下载文件/音频的原始文件。
- 视频消息:可以选择下载视频原始文件、视频首帧的缩略图。
下载文件进度回调
- 
通过 ZIMMediaDownloadingProgress 回调,接收富媒体消息的下载文件进度的相关通知。 - message:正在下载的消息对象。
- currentFileSize:当前已下载文件的大小。
- totalFileSize:下载文件的总体大小。
 
void onMediaDownloadingProgress(ZIMMessage message, long currentFileSize, long totalFileSize);void onMediaDownloadingProgress(ZIMMessage message, long currentFileSize, long totalFileSize);typedef void (^ZIMMediaDownloadingProgress)(ZIMMessage *message, unsigned long long currentFileSize, unsigned long long totalFileSize);typedef void (^ZIMMediaDownloadingProgress)(ZIMMessage *message, unsigned long long currentFileSize, unsigned long long totalFileSize);using ZIMMediaDownloadingProgress = std::function<void(const std::shared_ptr<ZIMMessage> &message, unsigned int currentSize, unsigned int totalSize)>;using ZIMMediaDownloadingProgress = std::function<void(const std::shared_ptr<ZIMMessage> &message, unsigned int currentSize, unsigned int totalSize)>;type ZIMMediaDownloadingProgress = (message: ZIMMessage, currentFileSize: number, totalFileSize: number) => void;type ZIMMediaDownloadingProgress = (message: ZIMMessage, currentFileSize: number, totalFileSize: number) => void;type ZIMMediaDownloadingProgress = (message: ZIMMessage, currentFileSize: number, totalFileSize: number) => void;type ZIMMediaDownloadingProgress = (message: ZIMMessage, currentFileSize: number, totalFileSize: number) => void;typedef ZIMMediaDownloadingProgress = void Function(ZIMMessage message, int currentFileSize, int totalFileSize);typedef ZIMMediaDownloadingProgress = void Function(ZIMMessage message, int currentFileSize, int totalFileSize);组合消息
如果需要下载组合消息的 Item 中的富媒体文件,可遍历 messageInfoList 列表并判断为富媒体文件类型时,调用 downloadMediaFile 接口下载。开发者可参考 接收消息 - 富媒体消息 了解此接口参数详情。
Tips 消息
ZIM SDK 支持用户在会话内的操作转换为 Tips 消息。当相关操作出现后,ZIM SDK 会向会话发送一条 Tips 消息进行通知,详情请参考 接收 Tips 消息。
@ 消息
- 仅 2.14.0 及以上版本的 ZIM SDK 支持接收并查看 @ 信息中的内容。
- 如果接收端的 SDK 版本介乎 [2.0.0, 2.14.0) 区间,则收到的消息和会话中不会带 @ 信息。
- 如果接收端的 SDK 版本为 1.x.x 版本,则无法收到 @ 信息。
获取 mentionedInfoList
当会话内用户被提醒后,可以被动或主动获取 mentionedInfoList 。
mentionedInfoList,包含 @ 消息的对应消息 ID,发送者 userID,以及 @ 消息的类型 ZIMMessageMentionedType ,开发者可用于实现标记会话等多样业务逻辑。
被动获取
在用户被提醒时,会收到 conversationChanged 回调,即可获取当前 ZIMConversation 的最新 mentionedInfoList 。
@Override
    public void onConversationChanged(
        ZIM zim, ArrayList<ZIMConversationChangeInfo> conversationChangeInfoList) {
        // conversationChangeInfoList 可拿到收到提醒的会话里面的 mentionInfoList 
    }@Override
    public void onConversationChanged(
        ZIM zim, ArrayList<ZIMConversationChangeInfo> conversationChangeInfoList) {
        // conversationChangeInfoList 可拿到收到提醒的会话里面的 mentionInfoList 
    }- (void)zim:(ZIM *)zim
    conversationChanged:(NSArray<ZIMConversationChangeInfo *> *)conversationChangeInfoList {
        // conversationChangeInfoList 可拿到收到提醒的会话里面的 mentionInfoList 
    }- (void)zim:(ZIM *)zim
    conversationChanged:(NSArray<ZIMConversationChangeInfo *> *)conversationChangeInfoList {
        // conversationChangeInfoList 可拿到收到提醒的会话里面的 mentionInfoList 
    }void onConversationChanged(
        ZIM * /*zim*/,
        const std::vector<ZIMConversationChangeInfo> & /*conversationChangeInfoList*/) {
    // conversationChangeInfoList 可拿到收到提醒的会话里面的 mentionInfoList 
}void onConversationChanged(
        ZIM * /*zim*/,
        const std::vector<ZIMConversationChangeInfo> & /*conversationChangeInfoList*/) {
    // conversationChangeInfoList 可拿到收到提醒的会话里面的 mentionInfoList 
}zim.on('conversationChanged', (zim: ZIM, data: ZIMEventOfConversationChangedResult) => {
    console.log(data.info.mentionInfoList);
});zim.on('conversationChanged', (zim: ZIM, data: ZIMEventOfConversationChangedResult) => {
    console.log(data.info.mentionInfoList);
});zim.onConversationChanged((data) => {
    console.log(data.info.mentionInfoList);
});zim.onConversationChanged((data) => {
    console.log(data.info.mentionInfoList);
});ZIMEventHandler.onConversationChanged = (ZIM zim, List<ZIMConversationChangeInfo> conversationChangeInfoList){
    // conversationChangeInfoList 可拿到收到提醒的会话里面的 mentionInfoList 
};ZIMEventHandler.onConversationChanged = (ZIM zim, List<ZIMConversationChangeInfo> conversationChangeInfoList){
    // conversationChangeInfoList 可拿到收到提醒的会话里面的 mentionInfoList 
};主动获取
如用 queryConversationList 或者 queryConversation 主动拉取会话,也可获取会话里面的 mentionedInfoList ,可参考以下示例代码:
ArrayList<ZIMMessageMentionedInfo> mentionedInfoList = conversation.mentionedInfoList;ArrayList<ZIMMessageMentionedInfo> mentionedInfoList = conversation.mentionedInfoList;NSArray<ZIMMessageMentionedInfo *> * mentionedInfoList = conversation.mentionedInfoList;NSArray<ZIMMessageMentionedInfo *> * mentionedInfoList = conversation.mentionedInfoList;std::vector<ZIMMessageMentionedInfo> mentionedInfoList = conversation.mentionedInfoList;std::vector<ZIMMessageMentionedInfo> mentionedInfoList = conversation.mentionedInfoList;const mentionedInfoList = conversaion.mentionedInfoList;const mentionedInfoList = conversaion.mentionedInfoList;List<ZIMMessageMentionedInfo> mentionedInfoList = conversation.mentionedInfoList;List<ZIMMessageMentionedInfo> mentionedInfoList = conversation.mentionedInfoList;清除会话的 mentionedInfoList
接收 @ 消息后,用户需要清除会话的 mentionedInfoList ,才能不再被提醒。
清除会话的 mentionedInfoList 接口与清除会话消息未读数接口相同:
- clearConversationUnreadMessageCount :清除单个会话消息未读数,调用示例请参考 会话管理 - 清除单个会话消息未读数。
- clearConversationTotalUnreadMessageCount :清除全部会话消息未读数,调用示例请参考 会话管理 - 清除全部会话消息未读数。
获取被提醒用户列表
会话内所有用户都可以调用 mentionedUserIDs 参数获取具体的被提醒用户列表。
ArrayList<String> userIds = message.getMentionedUserIDs();ArrayList<String> userIds = message.getMentionedUserIDs();NSArray<NSString *> *userIds = message.mentionedUserIDs;NSArray<NSString *> *userIds = message.mentionedUserIDs;std::vector<std::string> userIds = message.mentionedUserIDs;std::vector<std::string> userIds = message.mentionedUserIDs;const userIds = message.mentionedUserIDs;const userIds = message.mentionedUserIDs;List<String> userIds = message.mentionedUserIDs;List<String> userIds = message.mentionedUserIDs;确认是否为全员提醒
会话内所有用户都可以调用 isMentionAll 参数,确认消息是否为全员提醒消息。
boolean isMentionAll = message.isMentionAll();boolean isMentionAll = message.isMentionAll();BOOL isMentionAll = message.isMentionAll;BOOL isMentionAll = message.isMentionAll;boolean isMentionAll = message.isMentionAll;boolean isMentionAll = message.isMentionAll;const isMentionAll = message.isMentionAll;const isMentionAll = message.isMentionAll;bool isMentionAll = message.isMentionAll;bool isMentionAll = message.isMentionAll;收发全员推送消息
ZIM 支持您通过服务端向 App 所有在线用户发送消息,目标用户通过客户端接收相关消息。
从服务端向所有用户发送消息
请查看服务端 API 文档 全员推送 文档,实现从服务端向所有用户发送消息。
接收服务端发送的全员推送消息
- 仅 2.10.0 及以上版本的 ZIM SDK 支持接收并查看全员推送消息的内容。
- 如果接收端的 SDK 版本介乎 [2.0.0, 2.10.0) 区间,不可以收到服务端发送的全员推送消息,如需获取此条消息,请将 SDK 升级为 2.10.0 或以上版本。
通过 broadcastMessageReceived 回调,即可接收全员推送消息。
示例代码:
// 用户接收全员推送消息
public void onBroadcastMessageReceived(ZIM zim, ZIMMessage message) {
    super.onBroadcastMessageReceived(zim, message);
    // 接收到全员推送消息
}// 用户接收全员推送消息
public void onBroadcastMessageReceived(ZIM zim, ZIMMessage message) {
    super.onBroadcastMessageReceived(zim, message);
    // 接收到全员推送消息
}// 用户接收全员推送消息
- (void)zim:(ZIM *)zim broadcastMessageReceived:(ZIMMessage *)message {
    // 接收到全员推送消息
}// 用户接收全员推送消息
- (void)zim:(ZIM *)zim broadcastMessageReceived:(ZIMMessage *)message {
    // 接收到全员推送消息
}// 用户接收全员推送消息
virtual void onBroadcastMessageReceived(ZIM * /*zim*/, const std::shared_ptr<ZIMMessage> & /*message*/) {}// 用户接收全员推送消息
virtual void onBroadcastMessageReceived(ZIM * /*zim*/, const std::shared_ptr<ZIMMessage> & /*message*/) {}// 用户接收全员推送消息
zim.on('broadcastMessageReceived', (zim: ZIM, data: ZIMEventOfBroadcastMessageReceivedResult) => {
    console.log(data.message);
});// 用户接收全员推送消息
zim.on('broadcastMessageReceived', (zim: ZIM, data: ZIMEventOfBroadcastMessageReceivedResult) => {
    console.log(data.message);
});// 用户接收全员推送消息
zim.onBroadcastMessageReceived((data) => {
    console.log(data.message);
});// 用户接收全员推送消息
zim.onBroadcastMessageReceived((data) => {
    console.log(data.message);
});// 用户接收全员推送消息
ZIMEventHandler.onBroadcastMessageReceived(zim, message){}// 用户接收全员推送消息
ZIMEventHandler.onBroadcastMessageReceived(zim, message){}发送消息进阶功能
转发消息
ZIM SDK 支持实现以下两种形式的消息转发:
- 合并消息后转发。
- 逐条消息转发。
具体实现流程,请参考 转发消息。
重发消息
当用户发送单聊和群聊消息时,网络断开:
- 若在 30 秒内网络恢复,则 ZIM SDK 会自动重发该消息。
- 若在 30 秒内网络未恢复,则消息发送失败。
- 如需配置网络恢复等待时间,请联系 ZEGO 技术支持。
当自动重发失败时,用户可以在网络恢复后,手动重发该消息。此时,再次调用 sendMessage 接口,将发送失败的消息对象重新填入,并且参数 config.isRetrySend 设置为 true。
手动重发成功后,该消息会排序到当前最后位置。例如:当前消息排序为:A(成功)、B(失败)、C(成功),当重发消息 B 成功后,排序为 A、C、B。
示例代码
// 重发单聊 `Text` 信息
String toConversationID = "xxxx1";
ZIMTextMessage zimMessage; // 从 queryHistoryMessage 接口获取发送失败的消息
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 需要设置为 true,表示重发此消息
// !mark
config.isRetrySend = true;
ZIMConversationType type = ZIMConversationType.Peer;
// !mark
zim.sendMessage(zimMessage, toConversationID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});// 重发单聊 `Text` 信息
String toConversationID = "xxxx1";
ZIMTextMessage zimMessage; // 从 queryHistoryMessage 接口获取发送失败的消息
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// 需要设置为 true,表示重发此消息
// !mark
config.isRetrySend = true;
ZIMConversationType type = ZIMConversationType.Peer;
// !mark
zim.sendMessage(zimMessage, toConversationID, type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});示例代码
// 重发单聊 `Text` 信息
NSString *toConversationID = @"xxxx1";
ZIMTextMessage *textMessage; // 从 queryHistoryMessage 接口获取发送失败的消息
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
// 设置消息优先级
config.priority = ZIMMessagePriorityLow;
// 需要设置为 true,表示重发此消息
// !mark
config.isRetrySend = true;
ZIMMessageSendNotification *notification = [[ZIMMessageSendNotification alloc] init];
notification.onMessageAttached = ^(ZIMMessage * _Nonnull message) {
    // 发送前的回调,客户可以在这里获取一个临时对象,该对象与开发者创建的 zimMessage 对象属于同一对象,开发者可利用此特性做一些业务逻辑,如提前展示 UI 等
};
ZIMConversationType type = ZIMConversationTypePeer;
// !mark
[self.zim sendMessage:textMessage toConversationID:toConversationID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];// 重发单聊 `Text` 信息
NSString *toConversationID = @"xxxx1";
ZIMTextMessage *textMessage; // 从 queryHistoryMessage 接口获取发送失败的消息
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
// 设置消息优先级
config.priority = ZIMMessagePriorityLow;
// 需要设置为 true,表示重发此消息
// !mark
config.isRetrySend = true;
ZIMMessageSendNotification *notification = [[ZIMMessageSendNotification alloc] init];
notification.onMessageAttached = ^(ZIMMessage * _Nonnull message) {
    // 发送前的回调,客户可以在这里获取一个临时对象,该对象与开发者创建的 zimMessage 对象属于同一对象,开发者可利用此特性做一些业务逻辑,如提前展示 UI 等
};
ZIMConversationType type = ZIMConversationTypePeer;
// !mark
[self.zim sendMessage:textMessage toConversationID:toConversationID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
}];示例代码
// 重发单聊 `Text` 信息
std::shared_ptr<zim::ZIMTextMessage> message; // 从 queryHistoryMessage 接口获取发送失败的消息
// 设置消息优先级
zim::ZIMMessageSendConfig config;
config.priority = zim::ZIM_MESSAGE_PRIORITY_LOW;
// 需要设置为 true,表示重发此消息
// !mark
config.isRetrySend = true;
zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { int i = 0; });
// !mark
zim_->sendMessage(message, "toConversationID", type, config, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                              const zim::ZIMError &errorInfo) { int i = 0; });// 重发单聊 `Text` 信息
std::shared_ptr<zim::ZIMTextMessage> message; // 从 queryHistoryMessage 接口获取发送失败的消息
// 设置消息优先级
zim::ZIMMessageSendConfig config;
config.priority = zim::ZIM_MESSAGE_PRIORITY_LOW;
// 需要设置为 true,表示重发此消息
// !mark
config.isRetrySend = true;
zim::ZIMConversationType type = zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER
auto notification = std::make_shared<zim::ZIMMessageSendNotification>(
            [=](const std::shared_ptr<zim::ZIMMessage> &message) { int i = 0; });
// !mark
zim_->sendMessage(message, "toConversationID", type, config, notification,
                    [=](const std::shared_ptr<zim::ZIMMessage> &message,
                              const zim::ZIMError &errorInfo) { int i = 0; });示例代码
// 重发单聊 `Text` 信息
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
// !mark
    isRetrySend: true, // 需要设置为 true,表示重发此消息
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageTextObj: ZIMMessage = {}; // 从 queryHistoryMessage 接口获取发送失败的消息
zim.sendMessage(messageTextObj, toConversationID, conversationType, config, notification)
// !mark
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 重发单聊 `Text` 信息
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
// !mark
    isRetrySend: true, // 需要设置为 true,表示重发此消息
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageTextObj: ZIMMessage = {}; // 从 queryHistoryMessage 接口获取发送失败的消息
zim.sendMessage(messageTextObj, toConversationID, conversationType, config, notification)
// !mark
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });示例代码
// 重发单聊 `Text` 信息
ZIMTextMessage textMessage; // 从 queryHistoryMessage 接口获取发送失败的消息
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
// 设置消息优先级
sendConfig.priority = ZIMMessagePriority.low;
// 需要设置为 true,表示重发此消息
// !mark
sendConfig.isRetrySend = true;
ZIMMessageSendNotification notification = ZIMMessageSendNotification(onMessageAttached: (message){
    // 发送前的回调,开发者可以在这里获取一个临时对象,该对象与开发者创建的 zimMessage 对象属于同一对象,开发者可利用此特性做一些业务逻辑,如提前展示 UI 等
});
ZIMConversationType type = ZIMConversationType.peer;
// !mark
ZIM.getInstance()!.sendMessage(textMessage, toConversationID, type, sendConfig).then((value) => {
    // 开发者可以通过该回调监听消息是否发送成功。
}).catchError((onError){
    // 开发者可以捕获发送失败的异常。
});// 重发单聊 `Text` 信息
ZIMTextMessage textMessage; // 从 queryHistoryMessage 接口获取发送失败的消息
ZIMMessageSendConfig sendConfig = ZIMMessageSendConfig();
// 设置消息优先级
sendConfig.priority = ZIMMessagePriority.low;
// 需要设置为 true,表示重发此消息
// !mark
sendConfig.isRetrySend = true;
ZIMMessageSendNotification notification = ZIMMessageSendNotification(onMessageAttached: (message){
    // 发送前的回调,开发者可以在这里获取一个临时对象,该对象与开发者创建的 zimMessage 对象属于同一对象,开发者可利用此特性做一些业务逻辑,如提前展示 UI 等
});
ZIMConversationType type = ZIMConversationType.peer;
// !mark
ZIM.getInstance()!.sendMessage(textMessage, toConversationID, type, sendConfig).then((value) => {
    // 开发者可以通过该回调监听消息是否发送成功。
}).catchError((onError){
    // 开发者可以捕获发送失败的异常。
});发送不计入未读消息数的消息
在调用 sendMessage 发送消息时,可以通过以下参数设置发送的消息不会被计入到未读消息数中:
- 
- true: 不计入未读消息数
- false: 计入未读消息数
 
仅 2.23.0 及以上版本的 ZIM SDK 支持发送不计入未读消息数的消息。
// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// !mark(1:2)
// 设置消息为不计入未读消息数消息
config.disableUnreadMessageCount = true;
// 以发送单聊信息为例子
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(message, "conv_id", type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 设置消息优先级
config.priority = ZIMMessagePriority.LOW;
// !mark(1:2)
// 设置消息为不计入未读消息数消息
config.disableUnreadMessageCount = true;
// 以发送单聊信息为例子
ZIMConversationType type = ZIMConversationType.Peer;
zim.sendMessage(message, "conv_id", type, config, new ZIMMessageSentFullCallback() {
    @Override
    public void onMessageAttached(ZIMMessage zimMessage) {
        // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。               
    }
    @Override
    public void onMessageSent(ZIMMessage zimMessage, ZIMError error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
});// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
// 设置消息为不计入未读消息数消息
// !mark
config.disableUnreadMessageCount = YES;
// !mark
// 以发送单聊信息为例
ZIMConversationType type = ZIMConversationTypePeer;
[zim sendMessage:message convId:@"conv_id" type:type config:config callback:^(ZIMMessage *zimMessage, ZIMError *error) {
    if (error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
}];// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
// 设置消息为不计入未读消息数消息
// !mark
config.disableUnreadMessageCount = YES;
// !mark
// 以发送单聊信息为例
ZIMConversationType type = ZIMConversationTypePeer;
[zim sendMessage:message convId:@"conv_id" type:type config:config callback:^(ZIMMessage *zimMessage, ZIMError *error) {
    if (error) {
        // 开发者可以通过该回调监听消息是否发送成功。
    }
}];// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
ZIMMessageSendConfig config;
// 设置消息优先级
config.priority = ZIMMessagePriority::LOW;
// !mark(1:2)
// 设置消息为不计入未读消息数消息
config.disableUnreadMessageCount = true;
// 以发送单聊信息为例子
ZIMConversationType type = ZIMConversationType::Peer;
zim_->sendMessage(
    message, "conv_id", type, config,
    std::make_shared<zim::ZIMMessageSendNotification>(
        [=](const std::shared_ptr<zim::ZIMMessage> &message) {
            if (message) {
                // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
            }
        }),
    [=](std::shared_ptr<zim::ZIMMessage> message, zim::ZIMError errorInfo) {
        // 开发者可以通过该回调监听消息是否发送成功。
        if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
            
        }
    });// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
ZIMMessageSendConfig config;
// 设置消息优先级
config.priority = ZIMMessagePriority::LOW;
// !mark(1:2)
// 设置消息为不计入未读消息数消息
config.disableUnreadMessageCount = true;
// 以发送单聊信息为例子
ZIMConversationType type = ZIMConversationType::Peer;
zim_->sendMessage(
    message, "conv_id", type, config,
    std::make_shared<zim::ZIMMessageSendNotification>(
        [=](const std::shared_ptr<zim::ZIMMessage> &message) {
            if (message) {
                // 开发者可以通过该回调,监听消息是否开始准备发送。只有当通过本地基础参数检验的消息才会抛出该回调,否则通过 onMessageSent 回调抛出错误。
            }
        }),
    [=](std::shared_ptr<zim::ZIMMessage> message, zim::ZIMError errorInfo) {
        // 开发者可以通过该回调监听消息是否发送成功。
        if (errorInfo.code == zim::ZIMErrorCode::ZIM_ERROR_CODE_SUCCESS) {
            
        }
    });// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
// !mark
    disableUnreadMessageCount: true, // 设置消息为不计入未读消息数消息
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageTextObj: ZIMMessage = {
    type: 1,
    message: 'xxxx',
};
zim.sendMessage(messageTextObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
const toConversationID = ''; // 对方 userID
const conversationType = 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
const config: ZIMMessageSendConfig = { 
    priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
// !mark
    disableUnreadMessageCount: true, // 设置消息为不计入未读消息数消息
};
const notification: ZIMMessageSendNotification = {
    onMessageAttached: (message: ZIMMessage) => {}
}
const messageTextObj: ZIMMessage = {
    type: 1,
    message: 'xxxx',
};
zim.sendMessage(messageTextObj, toConversationID, conversationType, config, notification)
    .then((res: ZIMMessageSentResult) => {
        // 发送成功
    })
    .catch((err: ZIMError) => {
        // 发送失败
    });// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
try {
    ZIMMessageSendConfig config = ZIMMessageSendConfig();
    //设置消息优先级
    config.priority = ZIMMessagePriority.low;
// !mark(1:2)
    // 设置消息为不计入未读消息数消息
    config.disableUnreadMessageCount = true;
    // 以发送单聊消息为例子
    ZIMConversationType type = ZIMConversationType.peer;
    ZIMMessageSentResult result = await ZIM.getInstance()!.sendMessage(message, 'conv_id', type, config);
    
} on PlatformException catch (onError){
    onError.code;//根据错误码表处理
    onError.message;//错误信息
}// 以下为用户在单聊会话中发送不计入未读消息数的示例代码:
try {
    ZIMMessageSendConfig config = ZIMMessageSendConfig();
    //设置消息优先级
    config.priority = ZIMMessagePriority.low;
// !mark(1:2)
    // 设置消息为不计入未读消息数消息
    config.disableUnreadMessageCount = true;
    // 以发送单聊消息为例子
    ZIMConversationType type = ZIMConversationType.peer;
    ZIMMessageSentResult result = await ZIM.getInstance()!.sendMessage(message, 'conv_id', type, config);
    
} on PlatformException catch (onError){
    onError.code;//根据错误码表处理
    onError.message;//错误信息
}监听消息发送状态
在一些弱网场景中,可能存在以下场景,即消息发送成功,但由于某些因素(如网络丢包),导致 ZIM SDK 未收到服务端应答。此时,ZIM SDK 会因应答超时而认为消息发送失败,但实际上消息发送成功,导致消息状态混乱。为解决该问题,明确消息最终状态, 2.6.0 或以上版本 SDK 支持开发者监听 messageSentStatusChanged 回调,接收消息的状态变化。消息的状态有三种,即 Sending、Success 和 Failed。根据消息状态的变化,开发者可判断消息发送是否成功,并在业务上做相应处理。
// 监听消息状态
zim.setEventHandler(new ZIMEventHandler() {
    @Override
    public void onMessageSentStatusChanged(
        ZIM zim, ArrayList<ZIMMessageSentStatusChangeInfo> messageSentStatusChangeInfoList) {
    // 开发者可在这里监听消息状态改变时的回调。
}
});// 监听消息状态
zim.setEventHandler(new ZIMEventHandler() {
    @Override
    public void onMessageSentStatusChanged(
        ZIM zim, ArrayList<ZIMMessageSentStatusChangeInfo> messageSentStatusChangeInfoList) {
    // 开发者可在这里监听消息状态改变时的回调。
}
});// 监听消息状态
- (void)zim:(ZIM *)zim messageSentStatusChanged:
        (NSArray<ZIMMessageSentStatusChangeInfo *> *)messageSentStatusChangeInfoList {
            // 开发者可在这里监听消息状态的改变
}// 监听消息状态
- (void)zim:(ZIM *)zim messageSentStatusChanged:
        (NSArray<ZIMMessageSentStatusChangeInfo *> *)messageSentStatusChangeInfoList {
            // 开发者可在这里监听消息状态的改变
}// 监听消息状态
void onMessageSentStatusChanged(zim::ZIM *zim, const std::vector<ZIMMessageSentStatusChangeInfo> &messageSentStatusChangeInfoList{
    // 开发者可以在这里监听消息状态变更的回调。
}// 监听消息状态
void onMessageSentStatusChanged(zim::ZIM *zim, const std::vector<ZIMMessageSentStatusChangeInfo> &messageSentStatusChangeInfoList{
    // 开发者可以在这里监听消息状态变更的回调。
}// 监听消息状态
zim.on('messageSentStatusChanged', (zim: ZIM, data: ZIMEventOfMessageSentStatusChangedResult) => {
    data.infos.forEach((info) => {
        console.warn(info.message, info.status);
    });  
});// 监听消息状态
zim.on('messageSentStatusChanged', (zim: ZIM, data: ZIMEventOfMessageSentStatusChangedResult) => {
    data.infos.forEach((info) => {
        console.warn(info.message, info.status);
    });  
});// 监听消息状态
zim.onMessageSentStatusChanged((data) => {
    data.infos.forEach((info) => {
        console.warn(info.message, info.status);
    });  
});// 监听消息状态
zim.onMessageSentStatusChanged((data) => {
    data.infos.forEach((info) => {
        console.warn(info.message, info.status);
    });  
});//监听消息状态
ZIMEventHandler.onMessageSentStatusChanged = (
    ZIM zim, List<ZIMMessageSentStatusChangeInfo> messageSentStatusChangedInfoList){
        for(ZIMMessageSentStatusChangeInfo info in messageSentStatusChangedInfoList){
            log(info.status.toString());
            log(info.message!.messageID.toString());
        }
    };//监听消息状态
ZIMEventHandler.onMessageSentStatusChanged = (
    ZIM zim, List<ZIMMessageSentStatusChangeInfo> messageSentStatusChangedInfoList){
        for(ZIMMessageSentStatusChangeInfo info in messageSentStatusChangedInfoList){
            log(info.status.toString());
            log(info.message!.messageID.toString());
        }
    };


