收发消息
更新时间: 2025/01/15 15:20:22
网易云信即时通讯 SDK(NetEase IM SDK,简称 NIM SDK)支持收发多种消息类型,助您快速实现多样化的消息业务场景。
本文介绍通过 NIM SDK 实现消息收发的具体流程。
本文介绍的消息收发仅包含单聊、高级群、超大群消息,不包含聊天室、圈组的消息,具体实现流程请分别参考 聊天室消息收发 和 圈组消息收发。
支持平台
本文内容适用的开发平台或框架如下表所示:
Android | iOS | macOS/Windows | Web/uni-app/小程序 | Node.js/Electron | HarmonyOS | Flutter |
---|---|---|---|---|---|---|
✔️️️️ | ✔️️️️ | ✔️️️️ | ✔️️️️ | ✔️️️️ | ✔️️️️ | ✔️️️️ |
技术原理
应用集成 NIM SDK 并完成 SDK 初始化后,消息收发流程如下图所示(本地提示消息 和 通知消息 除外):
sequenceDiagram
autoNumber
participant ne as 网易云信 IM 服务端
participant clienta as 客户端 A
participant app as 应用服务端
participant clientb as 客户端 B
app->>ne:传入应用账号
ne->>app:返回 Token
clienta->>app:登录
clientb->>app:登录
app->>clienta:返回 Token
app->>clientb:返回 Token
clienta->>ne:带 Token 登录 IM
clientb->>ne:带 Token 登录 IM
par 收发消息
clienta->>ne: 收发消息
clientb->>ne:
ne->>clienta: 收发消息
ne->>clientb:
end
消息收发基本流程如下:
- 账号集成与登录。
- 开发者将用户账号
accountId
传入网易云信 IM 服务器。 - 网易云信 IM 服务器返回 Token 给应用服务器。
- 应用客户端登录应用服务器。
- 应用服务器将 Token 返回给应用客户端。
- 用户携带用户账号和 Token 登录网易云信 IM 服务器,网易云信 IM 服务器进行校验。
- 开发者将用户账号
- 用户 A 发送一条消息到网易云信 IM 服务器。
- 网易云信 IM 服务器投递消息至其他用户,分为如下两种情况:
- 如果为单聊消息,IM 服务器将其投递至用户 B。
- 如果为群聊消息,IM 服务器将其投递至群内其他每一位用户。
上图仅以静态 Token 登录为例展示消息收发流程。网易云信 IM 还支持动态 Token 登录鉴权和第三方回调登录鉴权,相关详情请参考 登录鉴权。
前提条件
在实现消息收发之前,请确保:
频控限制
发送消息(sendMessage
)方法一分钟内默认最多可调用 300 次。
收发文本消息
API 调用时序
sequenceDiagram
par 步骤 1:初始化 SDK
发送方 ->> NIM: 初始化 SDK
接收方 ->> NIM: 初始化 SDK
end
par 步骤 2:发送方登录
发送方 ->> NIM: 登录
end
par 步骤 3:接收方注册消息监听并登录
接收方 ->> NIM: 监听消息接收<br>(addMessageListener)
接收方 ->> NIM: 登录
end
par 步骤 4:消息收发
发送方 ->> NIM: 构造文本消息<br>(createTextMessage)
发送方 ->> NIM: 发送消息<br>(sendMessage)
NIM ->> 接收方: 投递消息体
end
实现步骤
-
接收方 注册消息监听器,监听消息接收回调事件。
Android/iOS/macOS/Windows
接收方调用
addMessageListener
方法注册消息监听器,监听消息接收回调事件onReceiveMessages
。AndroidJava
V2NIMMessageService v2MessageService = NIMClient.getService(V2NIMMessageService.class); V2NIMMessageListener messageListener = new V2NIMMessageListener() { @Override public void onReceiveMessages(List<V2NIMMessage> messages) { } }; v2MessageService.addMessageListener(messageListener);
iOSObjective-C
[[[NIMSDK sharedSDK] v2MessageService] addMessageListener:listener];
macOS/WindowsC++
V2NIMMessageListener listener; listener.onReceiveMessages = [](nstd::vector<V2NIMMessage> messages) { // receive messages }; messageService.addMessageListener(listener);
如需移除消息监听器,可调用
removeMessageListener
。AndroidJava
V2NIMMessageService v2MessageService = NIMClient.getService(V2NIMMessageService.class); v2MessageService.removeMessageListener(messageListener);
iOSObjective-C
[[[NIMSDK sharedSDK] v2MessageService] removeMessageListener:listener];
macOS/WindowsC++
messageService.removeMessageListener(listener);
Web/uni-app/小程序/NOde.js/Electron/HarmonyOS
调用
on("EventName")
方法注册消息监听器,监听消息接收回调事件onReceiveMessages
。Web/uni-app/小程序TypeScript
nim.V2NIMMessageService.on("onReceiveMessages", function (messages: V2NIMMessage[]) {})
如需移除登录相关监听器,可调用
off("EventName")
。TypeScript
nim.V2NIMMessageService.off("onReceiveMessages", function (messages: V2NIMMessage[]) {})
Node.js/ElectronTypeScript
v2.messageService.on("receiveMessages", function (messages: V2NIMMessage[]) {})
如需移除登录相关监听器,可调用
off("EventName")
。TypeScript
v2.messageService.off("receiveMessages", function (messages: V2NIMMessage[]) {})
HarmonyOSTypeScript
nim.messageService.on("onReceiveMessages", function (messages: V2NIMMessage[]) {})
如需移除登录相关监听器,可调用
off("EventName")
。TypeScript
nim.messageService.off("onReceiveMessages", function (messages: V2NIMMessage[]) {})
Flutter
调用
add
方法注册消息监听器,监听消息接收回调事件onReceiveMessages
。Dart
subsriptions.add( NimCore.instance.messageService.onReceiveMessages.listen((event) { //do something }));
如需移除登录相关监听器,可调用
cancel
。Dart
subsriptions.forEach((subsription) { subsription.cancel(); });
-
发送方 调用
createTextMessage
方法,构建一条文本消息。AndroidJava
V2NIMMessage v2TextMessage = V2NIMMessageCreator.createTextMessage("text content");
iOSObjective-C
V2NIMMessage *v2Message = [V2NIMMessageCreator createTextMessage:@"hello world"];
macOS/WindowsC++
auto textMessage = V2NIMMessageCreator::createTextMessage("hello world"); if(!textMessage) { // create text message failed }
Web/uni-app/小程序TypeScript
try { const message = nim.V2NIMMessageCreator.createTextMessage('hello world') } catch(err) { // todo error }
Node.js/ElectronTypeScript
try { const message = v2.messageCreator.createTextMessage('Hello, world!') } catch(err) { // todo error }
HarmonyOSTypeScript
try { const message = nim.messageCreator.createTextMessage('hello world') } catch(err) { // todo error }
FlutterDart
await MessageCreator.createTextMessage(text);
-
发送方 调用
sendMessage
方法,发送已构建的文本消息。发送消息时,设置消息发送成功回调参数
success
和消息发送失败回调参数failure
,监听消息发送是否成功。若消息发送成功,则通过成功回调返回发送消息结果(接收消息对象)。若消息发送失败,则通过失败回调获取相关错误码。消息发送配置属性说明如下:
名称 说明 messageConfig
消息相关配置 routeConfig
消息路由(抄送)相关配置 pushConfig
消息第三方推送相关配置 antispamConfig
消息反垃圾相关配置,包括本地反垃圾或安全通配置 robotConfig
消息机器人相关配置 示例代码如下:
AndroidJava
V2NIMMessageService v2MessageService = NIMClient.getService(V2NIMMessageService.class); // 创建一条文本消息 V2NIMMessage v2Message = V2NIMMessageCreator.createTextMessage("xxx"); // 以单聊类型为例 String conversationId = V2NIMConversationIdUtil.conversationId("xxx", V2NIMConversationType.V2NIM_CONVERSATION_TYPE_P2P); // 根据实际情况配置 V2NIMMessageAntispamConfig antispamConfig = V2NIMMessageAntispamConfig.V2NIMMessageAntispamConfigBuilder.builder() .withAntispamBusinessId() .withAntispamCheating() .withAntispamCustomMessage() .withAntispamEnabled() .withAntispamExtension() .build(); // 根据实际情况配置 V2NIMMessageConfig messageConfig = V2NIMMessageConfig.V2NIMMessageConfigBuilder.builder() .withLastMessageUpdateEnabled() .withHistoryEnabled() .withOfflineEnabled() .withOnlineSyncEnabled() .withReadReceiptEnabled() .withRoamingEnabled() .withUnreadEnabled() .build(); // 根据实际情况配置 V2NIMMessagePushConfig pushConfig = V2NIMMessagePushConfig.V2NIMMessagePushConfigBuilder.builder() .withContent() .withForcePush() .withForcePushAccountIds() .withForcePushContent() .withPayload() .withPushEnabled() .withPushNickEnabled() .build(); // 根据实际情况配置 V2NIMMessageRobotConfig robotConfig = V2NIMMessageRobotConfig.V2NIMMessageRobotConfigBuilder.builder() .withAccountId() .withCustomContent() .withFunction() .withTopic() .build(); // 根据实际情况配置 V2NIMMessageRouteConfig routeConfig = V2NIMMessageRouteConfig.V2NIMMessageRouteConfigBuilder.builder() .withRouteEnabled() .withRouteEnvironment() .build(); // 根据实际情况配置 V2NIMSendMessageParams sendMessageParams = V2NIMSendMessageParams.V2NIMSendMessageParamsBuilder.builder() .withAntispamConfig(antispamConfig) .withClientAntispamEnabled() .withClientAntispamReplace() .withMessageConfig(messageConfig) .withPushConfig(pushConfig) .withRobotConfig(robotConfig) .withRouteConfig(routeConfig) .build(); // 发送消息 v2MessageService.sendMessage(v2Message, conversationId, sendMessageParams, new V2NIMSuccessCallback<V2NIMSendMessageResult>() { @Override public void onSuccess(V2NIMSendMessageResult v2NIMSendMessageResult) { // TODO: 发送成功 } }, new V2NIMFailureCallback() { @Override public void onFailure(V2NIMError error) { // TODO: 发送失败 } }); }
iOSObjective-C
// 创建一条文本消息 V2NIMMessage *message = [V2NIMMessageCreator createTextMessage:@"v2 message"]; V2NIMSendMessageParams *params = [[V2NIMSendMessageParams alloc] init]; // 发送消息 [[[NIMSDK sharedSDK] v2MessageService] sendMessage:message conversationId:@"conversationId" params:params success:^(V2NIMSendMessageResult * _Nonull result) { // 发送成功回调 } failure:^(V2NIMError * _Nonnull error) { // 发送失败回调,error 包含错误原因 } }];
macOS/WindowsC++
// 以单聊类型为例 auto conversationId = V2NIMConversationIdUtil::p2pConversationId("target_account_id"); // 创建一条文本消息 auto message = V2NIMMessageCreator::createTextMessage("hello world"); auto params = V2NIMSendMessageParams(); // 发送消息 messageService.sendMessage( message, conversationId, params, [](V2NIMSendMessageResult result) { // send message succeeded }, [](V2NIMError error) { // send message failed, handle error });
Web/uni-app/小程序TypeScript
try { // 创建一条文本消息 const message: V2NIMMessage = nim.V2NIMMessageCreator.createTextMessage("hello") // 发送消息 const res: V2NIMSendMessageResult = await nim.V2NIMMessageService.sendMessage(message, 'test1|1|test2') // Update UI with success message. } catch (err) { // todo error }
Node.js/ElectronTypeScript
// 创建一条文本消息 const message = v2.messageCreator.createTextMessage('Hello NTES IM') // 发送消息 const result = await v2.messageService.sendMessage(message, conversationId, params, progressCallback)
HarmonyOSTypeScript
try { // 创建一条文本消息 const message: V2NIMMessage = nim.messageCreator.createTextMessage("hello") // 发送消息 const res: V2NIMSendMessageResult = await nim.messageService.sendMessage(message, 'test1|1|test2') // todo Success } catch (err) { // todo error }
FlutterDart
await NimCore.instance.messageService.sendMessage(message, conversationId, params);
-
接收方 通过
onReceiveMessages
回调收到文本消息。
收发富媒体消息
富媒体消息包括图片消息、语音消息、视频消息和文件消息。
API 调用时序
sequenceDiagram
par 步骤 1:初始化 SDK
发送方 ->> NIM: 初始化 SDK
接收方 ->> NIM: 初始化 SDK
end
par 步骤 2:发送方登录
发送方 ->> NIM: 登录
end
par 步骤 3:接收方注册消息监听并登录
接收方 ->> NIM: 监听消息接收<br>(addMessageListener)
接收方 ->> NIM: 登录
end
par 步骤 4:消息收发
发送方 ->> NIM: 构建富媒体消息
发送方 ->> NIM: 发送消息(可通过回调监听消息附件上传进度)
发送方 ->> NIM: (可选)取消上传附件<br>(cancelMessageAttachmentUpload)
NIM ->> 接收方: 投递消息体
end
实现步骤
-
接收方 注册消息监听器,监听消息接收回调事件。
示例代码请参考 实现文本消息收发 的实现步骤 1。
-
发送方 构建富媒体消息,指定 NOS 存储场景。
NIM SDK 支持设置 IM 数据在网易对象存储(Netease Object Storage,简称 NOS)服务上的存储场景。这里的存储场景指需要存储到 NOS 的 IM 数据类型,默认包括多媒体消息的附件资源和用户、群组的资料,且这两类 IM 数据在 NOS 的存储默认不过期。NIM SDK 也支持指定 IM 数据在 NOS 上的过期时间,过期后,数据将被 NOS 删除。
-
不同消息类型创建方法
消息类型创建方法 图片消息 createImageMessage
语音消息 createAudioMessage
视频消息 createVideoMessage
文件消息 createFileMessage
-
NOS 场景参数说明
NOS 场景 说明 默认场景 用于用户、群组资料的上传场景。 IM 场景 用于文件的上传场景。 系统场景 用于 SDK 内部文件的上传场景。 安全链接场景 查看该场景的上传文件需要密钥。 自定义场景 用户调用 addCustomStorageScene
添加的自定义场景。 -
示例代码
图片消息:
AndroidJava
V2NIMMessage v2ImageMessage = V2NIMMessageCreator.createImageMessage(imagePath, name, sceneName, width, height);
iOSObjective-C
NSString *imagePath = @"文件沙盒路径"; V2NIMMessage *message = [V2NIMMessageCreator createImageMessage:imagePath name:@"imageName" sceneName:@"nim_default_im" width:200 height:200];
macOS/WindowsC++
auto imageMessage = V2NIMMessageCreator::createImageMessage("imagePath", "imageName", V2NIM_STORAGE_SCENE_NAME_DEFAULT_IM, 100, 100); if(!imageMessage) { // create image message failed }
Web/uni-app/小程序TypeScript
try { const message = nim.V2NIMMessageCreator.createImageMessage(document.getElementById('fileInputId').files[0]) } catch(err) { // todo error }
Node.js/ElectronTypeScript
try { const message = v2.messageCreator.createImageMessage(imagePath, name, sceneName, width, height) } catch(err) { // todo error }
HarmonyOSTypeScript
try { const imagePath = "沙盒路径" const message = nim.messageCreator.createImageMessage(imagePath) } catch(err) { // todo error }
FlutterDart
await MessageCreator.createImageMessage(imagePath, name, sceneName, width, height);
语音消息:
AndroidJava
V2NIMMessage v2AudioMessage = V2NIMMessageCreator.createAudioMessage(audioPath, name, sceneName, duration);
iOSObjective-C
NSString *audioPath = @"文件沙盒路径"; V2NIMMessage *message = [V2NIMMessageCreator createAudioMessage:audioPath name:@"audioName" sceneName:@"nim_default_im" duration:2];
macOS/WindowsC++
auto audioMessage = V2NIMMessageCreator::createAudioMessage("audioPath", "audioName", V2NIM_STORAGE_SCENE_NAME_DEFAULT_IM, 100); if(!audioMessage) { // create audio message failed }
Web/uni-app/小程序TypeScript
try { const message = nim.V2NIMMessageCreator.createAudioMessage(document.getElementById('fileInputId').files[0]) } catch(err) { // todo error }
Node.js/ElectronTypeScript
try { const message = v2.messageCreator.createAudioMessage(audioPath, name, sceneName, duration) } catch(err) { // todo error }
HarmonyOSTypeScript
try { const audioPath = "文件沙盒路径" ; const message = nim.messageCreator.createAudioMessage(audioPath) } catch(err) { // todo error }
FlutterDart
await MessageCreator.createAudioMessage(audioPath, name, sceneName, duration);
视频消息:
AndroidJava
V2NIMMessage v2VideoMessage = V2NIMMessageCreator.createVideoMessage(videoPath, name, sceneName, duration, width, height);
iOSObjective-C
NSString *videoPath = @"文件沙盒路径"; V2NIMMessage *message = [V2NIMMessageCreator createVideoMessage:videoPath name:@"name" sceneName:@"nim_default_im" duration:15 width:200 height:200];
macOS/WindowsC++
auto videoMessage = V2NIMMessageCreator::createVideoMessage("videoPath", "videoName", V2NIM_STORAGE_SCENE_NAME_DEFAULT_IM, 100, 100, 100); if (!videoMessage) { // create video message failed }
Web/uni-app/小程序TypeScript
try { const message = nim.V2NIMMessageCreator.createVideoMessage(document.getElementById('fileInputId').files[0]) } catch(err) { // todo error }
Node.js/ElectronTypeScript
try { const message = v2.messageCreator.createVideoMessage(videoPath, name, sceneName, duration, width, height) } catch(err) { // todo error }
HarmonyOSTypeScript
try { const videoPath = '沙盒路径' const message = nim.messageCreator.createVideoMessage(videoPath) } catch(err) { // todo error }
FlutterDart
await MessageCreator.createVideoMessage(videoPath, name, sceneName, duration, width, height);
文件消息:
AndroidJava
V2NIMMessage v2FileMessage = V2NIMMessageCreator.createFileMessage(filePath, name, sceneName);
iOSObjective-C
NSString *filePath = @"文件沙盒路径"; V2NIMMessage *message = [V2NIMMessageCreator createFileMessage:filePath name:@"name" sceneName:@"nim_default_im"];
macOS/WindowsC++
auto fileMessage = V2NIMMessageCreator::createFileMessage("filePath", "fileName", V2NIM_STORAGE_SCENE_NAME_DEFAULT_IM); if(!fileMessage) { // create file message failed }
Web/uni-app/小程序TypeScript
try { const message = nim.V2NIMMessageCreator.createFileMessage(document.getElementById('fileInputId').files[0]) } catch(err) { // todo error }
Node.js/ElectronTypeScript
try { const message = v2.messageCreator.createFileMessage(filePath, name, sceneName) } catch(err) { // todo error }
HarmonyOSTypeScript
try { const filePath = '沙盒路径' const message = nim.messageCreator.createFileMessage(filePath) } catch(err) { // todo error } }
FlutterDart
await MessageCreator.createFileMessage(filePath, name, sceneName);
-
发送方 调用
sendMessage
方法,发送已构建的富媒体消息。发送消息时,设置消息发送成功回调参数
success
、消息发送失败参数failure
及附件上传进度回调参数progress
,监听消息发送是否成功及附件上传进度。若消息发送成功,则通过发送成功回调返回发送消息的结果(接收消息对象)。若消息发送失败,则通过失败回调获取相关错误码。如果同一个图片/文件消息需要多次发送时,建议控制时序依次发送,避免出现发送失败的问题。
- 示例代码
以单聊消息为例,发送富媒体消息的示例代码如下:
AndroidJava
V2NIMMessageService v2MessageService = NIMClient.getService(V2NIMMessageService.class); // 以单聊类型为例 String conversationId = V2NIMConversationIdUtil.conversationId("xxx", V2NIMConversationType.V2NIM_CONVERSATION_TYPE_P2P); // 根据实际情况配置 V2NIMMessageAntispamConfig antispamConfig = V2NIMMessageAntispamConfig.V2NIMMessageAntispamConfigBuilder.builder() .withAntispamBusinessId() .withAntispamCheating() .withAntispamCustomMessage() .withAntispamEnabled() .withAntispamExtension() .build(); // 根据实际情况配置 V2NIMMessageConfig messageConfig = V2NIMMessageConfig.V2NIMMessageConfigBuilder.builder() .withLastMessageUpdateEnabled() .withHistoryEnabled() .withOfflineEnabled() .withOnlineSyncEnabled() .withReadReceiptEnabled() .withRoamingEnabled() .withUnreadEnabled() .build(); // 根据实际情况配置 V2NIMMessagePushConfig pushConfig = V2NIMMessagePushConfig.V2NIMMessagePushConfigBuilder.builder() .withContent() .withForcePush() .withForcePushAccountIds() .withForcePushContent() .withPayload() .withPushEnabled() .withPushNickEnabled() .build(); // 根据实际情况配置 V2NIMMessageRobotConfig robotConfig = V2NIMMessageRobotConfig.V2NIMMessageRobotConfigBuilder.builder() .withAccountId() .withCustomContent() .withFunction() .withTopic() .build(); // 根据实际情况配置 V2NIMMessageRouteConfig routeConfig = V2NIMMessageRouteConfig.V2NIMMessageRouteConfigBuilder.builder() .withRouteEnabled() .withRouteEnvironment() .build(); // 根据实际情况配置 V2NIMSendMessageParams sendMessageParams = V2NIMSendMessageParams.V2NIMSendMessageParamsBuilder.builder() .withAntispamConfig(antispamConfig) .withClientAntispamEnabled() .withClientAntispamReplace() .withMessageConfig(messageConfig) .withPushConfig(pushConfig) .withRobotConfig(robotConfig) .withRouteConfig(routeConfig) .build(); // 发送消息 v2MessageService.sendMessage(v2Message, conversationId, sendMessageParams, new V2NIMSuccessCallback<V2NIMSendMessageResult>() { @Override public void onSuccess(V2NIMSendMessageResult v2NIMSendMessageResult) { // TODO: 发送成功 } }, new V2NIMFailureCallback() { @Override public void onFailure(V2NIMError error) { // TODO: 发送失败 } }, new V2NIMProgressCallback() { @Override public void onProgress(int progress) { // TODO: 发送进度 } }); }
iOSObjective-C
V2NIMSendMessageParams *params = [[V2NIMSendMessageParams alloc] init]; // 发送消息 [[[NIMSDK sharedSDK] v2MessageService] sendMessage:message conversationId:@"conversationId" params:params success:^(V2NIMSendMessageResult * _Nonull result) { // 发送成功回调 } failure:^(V2NIMError * _Nonnull error) { // 发送失败回调,error 包含错误原因 } progress:^(NSUInteger) { // 发送进度 }];
macOS/WindowsC++
// 以单聊类型为例 auto conversationId = V2NIMConversationIdUtil::p2pConversationId("target_account_id"); auto params = V2NIMSendMessageParams(); // 发送消息 messageService.sendMessage( message, conversationId, params, [](V2NIMSendMessageResult result) { // send message succeeded }, [](V2NIMError error) { // send message failed, handle error }, [](uint32_t progress) { // upload progress });
Web/uni-app/小程序TypeScript
try { // 发送消息 const res: V2NIMSendMessageResult = await nim.V2NIMMessageService.sendMessage(message, 'test1|1|test2') // todo Success } catch (err) { // todo error }
Node.js/ElectronTypeScript
const result = await v2.messageService.sendMessage(message, conversationId, params, progressCallback)
HarmonyOSTypeScript
try { const res: V2NIMSendMessageResult = await nim.messageService.sendMessage(message, 'test1|1|test2') // todo Success } catch (err) { // todo error }
FlutterDart
await NimCore.instance.messageService.sendMessage(message, conversationId, params);
-
接收方 通过
onReceiveMessages
回调收到富媒体消息。富媒体资源一般默认自动下载,具体的默认下载策略请参考下表:
消息类型 默认资源下载策略 图片/视频消息 SDK 在收到消息时,自动下载缩略图和封面图片 语音消息 SDK 在收到消息时,自动下载原音频 文件消息 SDK 默认不下载原文件 - 如果需要下载文件消息的文件资源,可调用
downloadFile
方法手动下载(仅支持移动端)。其他类型富媒体消息的资源如自动下载失败,也可调用该方法手动重新下载。 - 如需自主选择下载时机,需将初始化配置参数
preloadAttach
设置为false
,关闭默认资源下载策略,再在合适的时机调用downloadFile
方法。 - 下载完成后,通过富媒体消息对应的附件基类获取具体的附件内容,该类继承自消息附件类。
手动下载富媒体资源示例如下:
AndroidJava
String url = "https://www.abc.com/ttt.txt"; // 设置文件存储位置 String filePath = "xxx/ttt.txt"; NIMClient.getService(V2NIMStorageService.class).downloadFile(url, filePath, new V2NIMSuccessCallback<String>() { @Override public void onSuccess(String filePath) { // 下载成功 } }, new V2NIMFailureCallback() { @Override public void onFailure(V2NIMError error) { // 下载失败 } }, new V2NIMProgressCallback() { @Override public void onProgress(int progress) { // 下载进度 } });
iOSObjective-C
// 按需配置远程目录 NSString *url = @"https://www.abc.com/ttt.txt"; // 按需配置存储目录 NSString *filePath = @"Document/ttt.txt"; [[NIMSDK sharedSDK].v2StorageService downloadFile:url filePath:filePath success:^() { // 成功回调 } failure:^(V2NIMError *error) { // 失败回调 } progress:^(NSUInteger progress) { // 进度回调 }];
macOS/WindowsC++
storageService.downloadFile( "https://example.com/test.txt", "~/test.txt", [](const nstd::string& url) { // download file succeeded }, [](V2NIMError error) { // download file failed, handle error }, [](uint32_t progress) { // download progress });
HarmonyOSTypescript
const url = 'https://www.abc.com/ttt.txt' const filePath = 'sandbox path' const path = await nim.storageService.downloadFile(url, filePath, (percent) => { console.log(`downloadFile percent: ${percent}`) })
FlutterDart
await NimCore.instance.storageService.downloadFile(url, filePath);
- 如果需要下载文件消息的文件资源,可调用
-
(可选)如发送图片消息、视频消息或文件消息,发送后可调用
cancelMessageAttachmentUpload
方法取消附件的上传。如果附件已经上传成功,操作将会失败。如果成功取消了附件的上传,对应的消息会发送失败,附件上传状态也为失败。
AndroidJava
V2NIMMessageService v2MessageService = NIMClient.getService(V2NIMMessageService.class); v2MessageService.cancelMessageAttachmentUpload(message, new V2NIMSuccessCallback<Void>() { @Override public void onSuccess(Void unused) { // cancel succeeded } }, new V2NIMFailureCallback() { @Override public void onFailure(V2NIMError error) { // cancel failed, handle error } });
iOSObjective-C
[[[NIMSDK sharedSDK] v2MessageService] cancelMessageAttachmentUpload:message success:^{ // cancel succeeded } failure:^(V2NIMError * _Nonnull error) { // cancel failed, handle error }];
macOS/WindowsC++
V2NIMMessage message; // more code messageService.cancelMessageAttachmentUpload( message, []() { // cancel message attachment upload succeeded }, [](V2NIMError error) { // cancel message attachment upload failed, handle error });
Web/uni-app/小程序TypeScript
try { await nim.V2NIMMessageService.cancelMessageAttachmentUpload(message) // todo Success } catch (err) { // todo error }
Node.js/ElectronTypeScript
try { await v2.messageService.cancelMessageAttachmentUpload(message) // todo Success } catch (err) { // todo error }
HarmonyOSTypeScript
try { await nim.messageService.cancelMessageAttachmentUpload(message) // todo Success } catch (err) { // todo error }
FlutterDart
await NimCore.instance.messageService.cancelMessageAttachmentUpload(message);
收发地理位置消息
地理位置消息收发流程与文本消息收发流程基本一致,区别在于构建消息的调用方法不同(需调用 createLocationMessage
)。本节仅简要展示相关调用示例,具体实现流程请参考 实现文本消息收发。
API 调用时序
sequenceDiagram
par 步骤 1:初始化 SDK
发送方 ->> NIM: 初始化 SDK
接收方 ->> NIM: 初始化 SDK
end
par 步骤 2:发送方登录
发送方 ->> NIM: 登录
end
par 步骤 3:接收方注册消息监听并登录
接收方 ->> NIM: 监听消息接收<br>(addMessageListener)
接收方 ->> NIM: 登录
end
par 步骤 4:消息收发
发送方 ->> NIM: 构造地理位置消息<br>(createLocationMessage)
发送方 ->> NIM: 发送消息<br>(sendMessage)
NIM ->> 接收方: 投递消息体
end
实现步骤
-
接收方 注册消息监听器,监听消息接收回调事件。
示例代码请参考 实现文本消息收发 的实现步骤 1。
-
发送方 调用
createLocationMessage
方法,构建一条地理位置消息。AndroidJava
V2NIMMessage v2LocationMessage = V2NIMMessageCreator.createLocationMessage(latitude,longitude, address);
iOSObjective-C
V2NIMMessage *message = [V2NIMMessageCreator createLocationMessage:37.787359 longitude:-122.408227 address:@"杭州滨江区网商路 399 号"];
macOS/WindowsC++
auto locationMessage = V2NIMMessageCreator::createLocationMessage(100, 100, "address"); if(!locationMessage) { // create location message failed }
Web/uni-app/小程序TypeScript
try { const message = nim.V2NIMMessageCreator.createLocationMessage(30.25, 120.166664, "HangZhou") } catch(err) { // todo error }
Node.js/ElectronTypeScript
try { const message = v2.messageCreator.createLocationMessage(latitude, longitude, address) } catch(err) { // todo error }
HarmonyOSTypeScript
try { const message = nim.messageCreator.createLocationMessage(30.25, 120.166664, "HangZhou") } catch(err) { // todo error }
FlutterDart
await MessageCreator.createLocationMessage(latitude, longitude, address);
-
发送方 调用
sendMessage
方法,发送已构建的地理位置消息。示例代码请参考 实现文本消息收发。
-
接收方 通过
onReceiveMessages
回调收到地理位置消息。
收发提示消息
提示消息(又称 Tip 消息)主要用于会话内的通知提醒。与自定义消息的区别在于,提示消息不支持设置附件。
提示消息的典型使用场景包括进入会话时出现的欢迎消息、会话过程中命中敏感词后的提示等。
API 调用时序
sequenceDiagram
par 步骤 1:初始化 SDK
发送方 ->> NIM: 初始化 SDK
接收方 ->> NIM: 初始化 SDK
end
par 步骤 2:发送方登录
发送方 ->> NIM: 登录
end
par 步骤 3:接收方注册消息监听并登录
接收方 ->> NIM: 监听消息接收<br>(addMessageListener)
接收方 ->> NIM: 登录
end
par 步骤 4:消息收发
发送方 ->> NIM: 构造提示消息<br>(createTipsMessage)
发送方 ->> NIM: 发送消息<br>(sendMessage)
NIM ->> 接收方: 投递消息体
end
实现步骤
-
接收方 注册消息监听器,监听消息接收回调事件。
示例代码请参考 实现文本消息收发 的实现步骤 1。
-
发送方 调用
createTipsMessage
方法,构建一条提示消息。AndroidJava
V2NIMMessage v2TipMessage = V2NIMMessageCreator.createTipsMessage("tip content");
iOSObjective-C
V2NIMMessage *message = [V2NIMMessageCreator createTipsMessage:"tip text"];
macOS/WindowsC++
auto tipMessage = V2NIMMessageCreator::createTipsMessage("text"); if(!tipMessage) { // create tip message failed }
Web/uni-app/小程序TypeScript
try { const newMessage = nim.V2NIMMessageCreator.createTipsMessage("hint") } catch(err) { // todo error }
Node.js/ElectronTypeScript
try { const newMessage = v2.messageCreator.createTipsMessage("hint") } catch(err) { // todo error }
HarmonyOSTypeScript
try { const newMessage = nim.messageCreator.createTipsMessage("hint") } catch(err) { // todo error }
FlutterDart
await MessageCreator.createTipsMessage(text);
-
发送方 调用
sendMessage
方法,发送已构建的提示消息。示例代码请参考 实现文本消息收发。
-
接收方 通过
onReceiveMessages
回调收到提示消息。
收发自定义消息
除了上述内置消息类型外,NIM SDK 还支持自定义消息类型。
SDK 不负责定义和解析自定义消息,您需要自行完成。自定义消息存入消息数据库,会和内置消息一并展现在消息记录中。
实现步骤
-
调用
createCustomMessage
构建自定义消息。AndroidJava
V2NIMMessage v2CustomMessage = V2NIMMessageCreator.createCustomMessage(text, rawAttachment);
iOSObjective-C
V2NIMMessage *message = [V2NIMMessageCreator createCustomMessage:@"text" rawAttachment:@"custoom JSON String"];
macOS/WindowsC++
auto customMessage = V2NIMMessageCreator::createCustomMessage("text", R"({"key": "value"})"); if(!customMessage) { // create custom message failed }
Web/uni-app/小程序TypeScript
try { const message = nim.V2NIMMessageCreator.createCustomMessage("text", JSON.stringify({ strategy: 1 })) } catch(err) { // todo error }
Node.js/ElectronTypeScript
try { const message = v2.messageCreator.createCustomMessage(text, rawAttachment) } catch(err) { // todo error }
HarmonyOSTypeScript
try { const message = nim.messageCreator.createCustomMessage("text", JSON.stringify({ strategy: 1 })) } catch(err) { // todo error }
FlutterDart
await MessageCreator.createCustomMessage(text, rawAttachment);
-
发送方 调用
sendMessage
方法,发送已构建的自定义消息。示例代码请参考 实现文本消息收发。
-
接收方 通过
onReceiveMessages
回调收到自定义消息。
接收通知消息
通知消息区别于系统通知,属于 会话内消息,是网易云信服务器针对一些特定场景事件预置的消息,目前主要用于群和聊天室的事件通知。当事件发生时服务器下发通知消息到 SDK,您需要解析消息中附带的信息来获取通知内容。例如群通知消息,当有新成员进群时,群内成员将收到 新成员进群 的通知消息。
场景功能
发送消息后获取消息内容
调用 sendMessage
发送消息时,设置消息发送成功回调参数 success
。如果消息发送成功,通过成功回调返回的结果接收消息对象。
发送消息后确认消息是否发送成功
发送消息时,设置消息发送成功回调参数 success
和消息发送失败参数 failure
,监听消息发送是否成功。如果收到成功回调,则消息发送成功。
设置消息的扩展字段
会话内消息具有服务端扩展字段和客户端扩展字段。服务端扩展字段仅能在消息发送前设置,会多端同步。客户端扩展字段在消息发送前后均可设置,不会多端同步。
- 扩展字段必须使用 JSON 格式封装,并传入非格式化的 JSON 字符串。
- 最大长度为 1024 字节,可通过 网易云信控制台 IM 即时通讯下 基础功能 > 消息扩展字段上限调整 修改长度上限。
- 发送消息前设置:构造消息对象时,通过
localExtension
设置客户端扩展字段。 - 发送消息后设置:调用
updateMessageLocalExtension
方法更新消息的本地扩展字段。
构造消息对象时,通过 serverExtension
设置服务端端扩展字段。
插入本地消息
当有业务场景需要插入一条消息至本地数据库内而不发出时,可以通过 insertMessageToLocal
方法实现。例如本地提示类消息的 UI 展示,向群里插入一条 群创建成功 的提示消息。
该功能不支持 Web 端。
-
接收方 注册消息监听器,监听消息接收回调事件。
示例代码请参考 实现文本消息收发 的实现步骤 1。
-
调用
createXXXMessage
方法,构建一条消息。 -
调用
insertMessageToLocal
方法,向本地数据库插入一条已构建的消息。插入消息成功后,本端会收到消息接收回调onReceiveMessages
并通知 UI 界面更新。- 如果为单聊场景,可以插入一条发送或接收的消息。
- 如果为群聊场景,可以插入一条任意群成员的消息。
以文本消息为例:
AndroidJava
V2NIMMessageService v2MessageService = NIMClient.getService(V2NIMMessageService.class); // 构建被插入的消息 V2NIMMessage v2NIMMessage = V2NIMMessageCreator.createTextMessage("xxx"); V2NIMConversationType conversationType = V2NIMConversationType.V2NIM_CONVERSATION_TYPE_P2P; String conversationId = V2NIMConversationIdUtil.conversationId("xxx", conversationType); v2MessageService.insertMessageToLocal(v2NIMMessage, conversationId, "xxx", 0, new V2NIMSuccessCallback<NIMMessage>() { @Override public void onSuccess(NIMMessage nimMessage) { } }, new V2NIMFailureCallback() { @Override public void onFailure(V2NIMError error) { } });
iOSObjective-C
[[[NIMSDK sharedSDK] v2MessageService] insertMessageToLocal:message conversationId:@"conversaionId" senderId:@"senderId" createTime:1698809881 success:^(V2NIMMessage * _Nonnull result) { // result 插入消息成功 } failure:^(V2NIMError * _Nonnull error) { // error 包含错误原因 }];
macOS/WindowsC++
auto conversationId = V2NIMConversationIdUtil::p2pConversationId("target_account_id"); auto message = V2NIMMessageCreator::createTextMessage("hello world"); messageService.insertMessageToLocal( message, conversationId, "target_account_id", 0, [](V2NIMMessage message) { // Insert local message succeeded }, [](V2NIMError error) { // Insert local message failed, handle error });
Node.js/ElectronTypeScript
const message = await v2.messageService.insertMessageToLocal(message, conversationId, senderId, createTime)
HarmonyOSTypeScript
const messageResult:V2NIMMessage = await nim.messageService.insertMessageToLocal(message, conversationId)
FlutterDart
await NimCore.instance.messageService.insertMessageToLocal(message, conversationId, senderId, createTime);
重发消息
如因网络等原因消息发送失败,您可以再次调用 sendMessage
方法重发消息。SDK 会判断本地或缓存中是否有该消息,如有则视为消息重发。
涉及接口
API | 说明 |
---|---|
addMessageListener |
注册消息相关监听器 |
removeMessageListener |
取消注册消息相关监听器 |
createXXXMessage |
消息构建,包括创建一条文本/图片/语音/视频/文件/地理/提示/自定义消息 |
sendMessage |
发送消息 |
addCustomStorageScene |
添加自定义存储场景 |
downloadFile |
下载文件 |
cancelMessageAttachmentUpload |
取消上传消息附件 |
updateMessageLocalExtension |
更新消息的本地扩展字段 |
insertMessageToLocal |
插入一条消息到本地数据库 |
V2NIMStorageSceneConfig |
网易对象存储 NOS 文件存储场景配置 |
V2NIMMessageAttachment |
消息附件对象 |
API | 说明 |
---|---|
on("EventName") |
注册消息相关监听器 |
off("EventName") |
取消注册消息相关监听器 |
createXXXMessage |
消息构建,包括创建一条文本/图片/语音/视频/文件/地理/提示/自定义消息 |
sendMessage |
发送消息 |
addCustomStorageScene |
添加自定义存储场景 |
downloadFile |
下载文件 |
cancelMessageAttachmentUpload |
取消上传消息附件 |
updateMessageLocalExtension |
更新消息的本地扩展字段 |
insertMessageToLocal |
插入一条消息到本地数据库 |
V2NIMStorageSceneConfig |
网易对象存储 NOS 文件存储场景配置 |
V2NIMMessageAttachment |
消息附件对象 |
API | 说明 |
---|---|
add |
注册消息相关监听器 |
cancel |
取消注册消息相关监听器 |
createXXXMessage |
消息构建,包括创建一条文本/图片/语音/视频/文件/地理/提示/自定义消息 |
sendMessage |
发送消息 |
addCustomStorageScene |
添加自定义存储场景 |
downloadFile |
下载文件 |
cancelMessageAttachmentUpload |
取消上传消息附件 |
updateMessageLocalExtension |
更新消息的本地扩展字段 |
insertMessageToLocal |
插入一条消息到本地数据库 |
NIMStorageSceneConfig |
网易对象存储 NOS 文件存储场景配置 |
NIMMessageAttachment |
消息附件对象 |