消息收发
更新时间: 2024/08/15 14:20:27
网易云信即时通讯(NetEase IM)iOS SDK(以下简称 NIM SDK)支持收发多种消息类型,助您快速实现多样化的消息业务场景。
本文介绍通过网易云信 NIM SDK 实现消息收发的技术原理、前提条件以及具体的实现流程。
技术原理
应用集成 NIM SDK 并完成 SDK 初始化后,消息收发流程如下图所示(本地提示消息 和 通知消息 除外)。
上图中的流程可归纳为如下三步:
-
账号集成与登录。
- 开发者将应用的用户账号(
accid
)传入网易云信 IM 服务器。 - 网易云信 IM 服务器返回 Token 给应用服务器。
- 应用客户端登录应用服务器。
- 应用服务器将 Token 返回给应用客户端。
- 用户带 Token 登录网易云信 IM 服务器。
- 开发者将应用的用户账号(
-
用户 A 发送一条消息到网易云信 IM 服务器。
-
网易云信 IM 服务器投递消息至其他用户,分为如下两种情况:
- 如为单聊消息,IM 服务器将其投递至用户 B。
- 如为群聊消息,IM 服务器将其投递至群内其他每一位用户。
上图仅以静态 Token 登录为例展示消息收发流程。网易云信 IM 还支持动态 Token 登录鉴权和第三方回调登录鉴权,相关详情请参考 登录鉴权。
前提条件
在实现消息收发之前,请确保您已经完成了以下设置:
API 使用限制
发送消息(sendMessage
)的方法调用存在频控,一分钟内默认最多可调用 300 次。
实现消息收发
NIM SDK 提供 NIMChatManagerDelegate
协议和 NIMChatManager
协议,支持构建、监听和收发多种类型的消息。SDK 中定义消息的结构为 NIMMessage
(不支持继承扩展),不同消息类型以 messageType
作区分。
公共参数说明
发送不同类型消息的方法均为 sendMessage:toSession:error:
方法或 sendMessage:toSession:completion:
异步方法。
这两个方法的参数说明如下:
参数 |
类型 |
说明 |
---|---|---|
message |
NIMMessage |
需要发送的消息,开发者构造出 message 后,需要选择构造对应的 messageObject 注入 (文本消息直接填入 text 即可,无须消息附件注入),即可传入此接口进行发送 |
session |
NIMSession |
需要发送到的会话。通过 sessionType 参数,可设置发送的文本消息为 单聊 消息或 群聊 消息。如设置为群聊消息,请确保已创建相应的群组。 |
error |
NSError * | 您需要自己构造出一个 NSError 对象,并将对象引用传入。如果在准备发送消息阶段发生错误,这个对象会被填充相应的信息。通常为参数检查错误或者登录状态错误,可参考错误码说明定位具体的出错类型 |
completion |
void(^)(NSError *error) | 发送完成后的回调,这里的回调完成只表示当前这个函数调用完成,需要后续的回调才能判断消息是否已经发送至服务器 |
可通过消息配置选项 NIMMessageSetting
设置该消息是否存入云端、写入漫游、计入未读数等。具体配置示例请参考 消息配置选项。
收发文本消息
以下信息仅对上图中标为橙色的流程进行详细说明,其他流程请参考相关文档。
-
发送方在登录前,调用
addDelegate:
方法添加委托(具体回调函数如下),完成对消息发送相关事件的监听。-
注册
willSendMessage
回调函数,监听 消息即将发送 事件。 -
注册
sendMessage:progress:
回调函数,监听消息发送进度。 -
注册
sendMessage:didCompleteWithError:
回调函数,监听 消息发送完成 事件。
示例代码如下:
Objective-C
// 在某处添加代理对象 [NIMSDK sharedSDK].chatManager addDelegate:self]; //... //回调方法监听,此处为消息即将发送事件 -(void)willSendMessage:(NIMMessage *)message { //your code } //发送进度回调 -(void)sendMessage:(NIMMessage *)message progress:(float)progress { //your code } //消息发送完成回调 //发送结果 - (void)sendMessage:(NIMMessage *)message didCompleteWithError:(NSError *)error { //your code }
-
-
接收方在登录前,调用
addDelegate:
方法添加委托,注册onRecvMessages:
回调函数,监听消息接收。示例代码如下:
Objective-C
//收到消息 - (void)onRecvMessages:(NSArray *)messages { //your code }
-
发送方构建一条文本消息,并调用
sendMessage:toSession:error:
或针对大文件的sendMessage:toSession:completion:
异步方法发送该消息。以发送一条文本消息 hello 至好友 ID 为
user
的业务场景为例,示例代码如下:Objective-C
// 构造出具体会话:P2P 单聊,对方账号为 user NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 构造出具体消息 NIMMessage *message = [[NIMMessage alloc] init]; message.text = @"hello"; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
-
onRecvMessage:
回调函数触发,投递文本消息至接收方。
收发多媒体消息
多媒体消息包括图片消息、语音消息、视频消息和文件消息。
以下信息仅对上图中标为橙色的流程进行详细说明,其他流程请参考相关文档。
-
发送方在登录前,调用
addDelegate:
方法添加委托,完成对消息发送相关事件的监听。-
注册
willSendMessage
回调函数,监听 消息即将发送 事件。示例代码见上文的 文本消息收发。 -
注册
sendMessage:progress:
回调函数,监听消息发送进度。示例代码见上文的 文本消息收发。 -
注册
sendMessage:didCompleteWithError:
回调函数,监听 消息发送完成 事件。示例代码见上文的 文本消息收发。 -
注册
uploadAttachmentSuccess:forMessage:
回调函数,监听多媒体资源上传完成事件。示例代码如下:
Objective-C
//附件上传完成 - (void)uploadAttachmentSuccess:(NSString *)urlString forMessage:(NIMQChatMessage *)message { //your code }
-
-
接收方在登录前,调用
addDelegate:
方法添加委托,注册如下回调函数。onRecvMessages:
回调函数,用于监听消息接收。fetchMessageAttachment:progress:
回调函数,用于监听附件下载进度。fetchMessageAttachment:didCompleteWithError:
回调函数,用于监听 消息附件下载完成 事件。
-
发送方通过初始化附件实例获取多媒体附件,并构建消息对象,注入附件,最后调用
sendMessage:toSession:error:
或针对大文件的sendMessage:toSession:completion:
异步方法发送该消息。可在初始化附件实例时预设其 NOS 资源存储场景,指定其在网易对象存储(Netease Object Storage, NOS)服务上的存活时长。
多媒体附件 说明 NIMImageObject
图片实例对象,左侧链接内包含图片实例的参数说明与图片实例初始化说明 NIMAudioObject
语音实例对象,左侧链接内包含语音实例的参数说明与语音实例初始化说明 NIM SDK 提供了高清语音的录制与播放的功能,用于处理语音消息的语音附件。相关详情请参考 语音消息处理。 NIMVideoObject
视频实例对象,左侧链接内包含视频实例的参数说明与视频实例初始化说明 NIMFileObject
文件实例对象,左侧链接内包含文件实例的参数说明与文件实例初始化说明 - 发送图片消息的示例代码
图片(以 UIImage 初始化)Objective-C
// 构造出具体会话 NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 获得图片附件对象 NIMImageObject *object = [[NIMImageObject alloc] initWithImage:image]; // 构造出具体消息并注入附件 NIMMessage *message = [[NIMMessage alloc] init]; message.messageObject = object; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
图片(以图片路径初始化)Objective-C
// 构造出具体会话 NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 获得图片附件对象 NIMImageObject *object = [[NIMImageObject alloc] initWithFilepath:path]; // 构造出具体消息并注入附件 NIMMessage *message = [[NIMMessage alloc] init]; message.messageObject = object; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
图片(以图片数据初始化)Objective-C
// 构造出具体会话 NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 获得图片附件对象 NIMImageObject *object = [[NIMImageObject alloc] initWithData:data extension:@"png"]; // 构造出具体消息并注入附件 NIMMessage *message = [[NIMMessage alloc] init]; message.messageObject = object; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
- 发送语音消息示例代码
语音(以语音路径初始化)Objective-C
// 构造出具体会话 NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 获得语音附件对象 NIMAudioObject *object = [[NIMAudioObject alloc] initWithSourcePath:path]; // 构造出具体消息并注入附件 NIMMessage *message = [[NIMMessage alloc] init]; message.messageObject = object; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
语音(语音数据初始化)Objective-C
// 构造出具体会话 NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 获得语音附件对象 NIMAudioObject *audioObject = [[NIMAudioObject alloc] initWithData:data extension:@"aac"]; // 构造出具体消息并注入附件 NIMMessage *message = [[NIMMessage alloc] init]; message.messageObject = object; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
- 发送视频消息示例代码
视频(以视频路径初始化)Objective-C
// 构造出具体会话 NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 获得视频附件对象 NIMVideoObject *object = [[NIMVideoObject alloc] initWithSourcePath:path]; // 构造出具体消息并注入附件 NIMMessage *message = [[NIMMessage alloc] init]; message.messageObject = object; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
视频(以视频数据初始化)Objective-C
// 构造出具体会话 NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 获得视频附件对象 NIMVideoObject *object = [[NIMVideoObject alloc] initWithData:data extension:@"mp4"]; // 构造出具体消息并注入附件 NIMMessage *message = [[NIMMessage alloc] init]; message.messageObject = object; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
- 发送文件消息示例代码
文件(以文件路径初始化)Objective-C
// 构造出具体会话 NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 获得文件附件对象 NIMFileObject *object = [[NIMFileObject alloc] initWithSourcePath:path]; // 构造出具体消息并注入附件 NIMMessage *message = [[NIMMessage alloc] init]; message.messageObject = object; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
文件(以文件数据初始化)Objective-C
// 构造出具体会话 NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P]; // 获得视频附件对象 NIMFileObject *audioObject = [[NIMFileObject alloc] initWithData:data extension:@"data"]; // 构造出具体消息并注入附件 NIMMessage *message = [[NIMMessage alloc] init]; message.messageObject = object; // 错误反馈对象 NSError *error = nil; // 发送消息 [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
-
(可选)发送方在发送消息后,可进行如下操作。
- 调用
messageInTransport:
方法,判断附件是否正在传输。 - 调用
messageTransportProgress:
方法,获取附件传输进度。
示例代码如下:
Objective-C
//判断是否在传输 BOOL isInTransport = [[NIMSDK sharedSDK].chatManager messageInTransport: msg]; ... //获取进度 float progress = [[NIMSDK sharedSDK].chatManager messageTransportProgress:msg];
- 调用
-
onRecvMessage:
函数触发,接收方收到文本消息。 -
(可选)接收方接收消息后,可进行如下操作。
- 调用
messageInTransport:
方法,判断附件是否正在传输。 - 调用
messageTransportProgress:
方法,获取附件传输进度。
- 调用
-
(可选)图片消息的缩略图、语音消息的语音文件和视频消息的视频封面,默认由 SDK 自动下载。如果自动下载失败(本地没有这些文件),那么接收方可调用
fetchMessageAttachment:error:
方法获取。示例代码如下:
Objective-C
//下载附件 NSError *error; [[NIMSDK sharedSDK].chatManager fetchMessageAttachment:msg error:&error];
收发位置消息
地理位置消息收发流程与文本消息收发流程基本一致,区别在于需要构建的消息对象不同(位置消息对象为 NIMLocationObject
)。提供了初始化位置实例的 initWithLatitude:longitude:title:
方法。本节仅简要展示调用示例,具体实现流程请参考上文的 收发文本消息。
以下示例代码的业务场景为:发送一条位置消息至 IM 账号为 user
的好友, 位置的经纬度为(30.27415,120.15515),地点名为 address
。
Objective-C// 构造出具体会话
NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P];
// 获得位置附件对象
NIMLocationObject *object = [[NIMLocationObject alloc] initWithLatitude:120.15515 longitude:30.27415 title:@"address"];
// 构造出具体消息并注入附件
NIMMessage *message = [[NIMMessage alloc] init];
message.messageObject = object;
// 错误反馈对象
NSError *error = nil;
// 发送消息
[[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
收发提示消息
提示消息主要用于会话内的通知提醒,消息使用场景例如:进入会话时出现的欢迎消息,或是会话过程中命中敏感词后的提示消息等场景。也可以用自定义消息实现,但相对复杂。
提示消息附件内部没有额外的信息字段,提示内容建议放入 NIMMessage
中的 text
字段,额外信息可以存储在 NIMMessage
的 remoteExt
和 localExt
字段中。
附件原型:
Objective-C@interface NIMTipObject : NSObject<NIMMessageObject>
@end
以下示例代码的业务场景为:发送一条提示消息至网易云信 IM 账号为 user
的好友 , 文案内容为 welcome
。
Objective-C// 构造出具体会话
NIMSession *session = [NIMSession session:@"user" type:NIMSessionTypeP2P];
// 获得文件附件对象
NIMTipObject *object = [[NIMTipObject alloc] init];
// 构造出具体消息并注入附件
NIMMessage *message = [[NIMMessage alloc] init];
message.messageObject = object;
message.text = @"welcome";
// 错误反馈对象
NSError *error = nil;
// 发送消息
[[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
接收通知消息
针对一些特定场景的事件,网易云信服务器预置了一些通知消息,在事件发生时下发到 SDK。通知消息也是一种特定消息,开发者需解析消息中附带的信息,来获取通知内容。如最常见的通知消息——群通知事件,如有新成员进群,则群内已有成员将收到此通知消息。
-
通知消息属于会话内的一种消息,其对应的数据结构为
NIMMessage
,消息类型为NIMMessageTypeNotification
。通知消息目前用于在群和聊天室的事件通知。 -
通知消息需要进行解析,具体请参考 验证入群邀请。
-
可对通知消息进行过滤,具体请参考 通知消息过滤。
收发自定义消息
除了上述内置消息类型以外,NIM SDK 还支持收发自定义消息类型。具体实现流程介绍,请参考 自定义消息收发。
常见问题
发送消息后怎么获取消息内容
实现 NIMChatManagerDelegate
的 sendMessage:didCompleteWithError:
方法来接收发送消息完成回调,其中回调 NIMMessage
对象。可以通过 isOutgoingMsg
属性判断是否是发送出去的消息,通过 session
属性获取聊天对象的 accid/群组 ID/聊天室 ID,通过 text
属性获取消息文本(仅适用于文本消息和提示消息),通过 messageObject
属性获取消息附件内容,通过 deliveryState
属性获取发送消息的投递状态,通过 timestamp
属性获取消息发送时间。
deliveryState
默认是发送失败的状态,但仅作参考。准确实时的消息状态,建议客户根据消息发送完成的回调来重新从本地数据库取消息记录用来展示。或者根据消息发送的生命周期(将要发送,发送完成等回调),在消息的扩展字段定义消息的发送状态,用来 UI 展示。
如何判断消息已发送成功
调用消息发送接口 sendMessage:toSession:error:
时,判断 error == nil
表示方法调用成功。实现 NIMChatManagerDelegate
的 –sendMessage:didCompleteWithError:
方法,判断 error == nil
表示消息已经发送至服务器。
如何设置消息的扩展字段
单聊或群聊消息具有服务端扩展字段和客户端扩展字段。服务端扩展字段只能在消息发送前设置,会同步到其他端。客户端扩展字段在消息发送前后设置均可,不会同步到其他端。
扩展字段,请使用 JSON 格式封装,并传入非格式化的 JSON 字符串,最大长度 1024 字节。
具体方法如下:
-
对于单聊或群聊消息,构造
NIMMessage
对象时,通过localExt
方法设置客户端扩展字段。 -
调用
updateMessage:forSession:completion
方法更新消息的本地扩展字段。设置消息的客户端扩展字段后,必须调用
updateMessage:forSession:completion
方法,否则无法生效。
对于单聊或群聊消息,构造 IMMessage
对象时,通过 setRemoteExtension
方法设置消息的服务端扩展字段,
API 参考
API |
说明 |
---|---|
addDelegate: |
添加委托,可通过参数 delegate 配置需要委托的回调函数 |
removeDelegate: |
移除委托,可通过参数 delegate 配置需要移除委托的回调函数 |
willSendMessage |
即将发送消息回调 |
uploadAttachmentSuccess:forMessage: |
上传资源文件成功回调 |
sendMessage:progress: |
发送消息进度回调 |
sendMessage:didCompleteWithError: |
发送消息完成回调 |
onRecvMessages: |
收到消息回调 |
fetchMessageAttachment:progress: |
收到消息附件进度回调 |
fetchMessageAttachment:didCompleteWithError: |
收到消息附件完成回调 |
sendMessage:toSession:error: |
发送消息 |
sendMessage:toSession:completion: |
异步发送消息 |
cancelSendingMessage: |
取消发送消息 |
更多相关 SDK API,请参考 NIMChatManagerDelegate
协议和 NIMChatManager
协议。