圈组消息收发
更新时间: 2024/11/21 15:44:08
NIM SDK 的NIMQChatMessageManager
协议提供圈组消息收发的方法,支持支持文本、图片、语音、视频、文件、地理位置和自定义等消息类型。定义圈组消息的结构体为NIMQchatMessage
。
功能介绍
消息类型 |
API关键字 |
说明 |
---|---|---|
文本消息 | text |
消息内容为普通文本 |
图片消息 | image |
消息内容为图片 URL 地址、尺寸、图片大小等信息 |
语音消息 | audio |
消息内容为语音文件的 URL 地址、时长、大小、格式等信息 |
视频消息 | video |
消息内容为视频文件的 URL 地址、时长、大小、格式等信息 |
文件消息 | file |
消息内容为文件的 URL 地址、大小、格式等信息 |
位置消息 | location |
消息内容为地理位置标题、经度、纬度信息 |
提示消息 | tip |
又叫做 Tip 消息,没有推送和通知栏提醒,主要用于会话内的通知提醒,例如进入会话时出现的欢迎消息,或是会话过程中命中敏感词后的提示消息等场景 |
通知消息 | notification |
主要用于圈组的事件通知 |
自定义消息 | custom |
开发者自定义的消息类型,例如红包消息、石头剪子布等形式的消息 |
技术原理
下图展示了集成并初始化 NIM SDK 后,实现圈组消息收发的基本工作流。图中的 QChat 即为 NIM SDK 的圈组组件,云信服务端包含 IM 服务端和圈组服务端。
- 上图仅以静态 Token 登录为例展示消息收发流程。网易云信 IM 还支持动态 Token 登录鉴权和第三方回调登录鉴权,相关详情请参见登录鉴权。
- 圈组服务端与圈组服务器是两个不同概念,前者指云信服务器内提供圈组功能的服务端,后者为圈组的特殊概念,对应 Discord 的 Server, 为社群本身。
上图中的流程可归纳为如下 5 步:
- 账号集成与登录。
- 开发者将应用的用户账号传入云信 IM 服务端,注册云信 IM 账号。
- 云信 IM 服务端返回 Token 给应用服务端。
- 应用客户端登录应用服务端。
- 应用服务端将 Token 返回给应用客户端。
- 用户A 和用户B 带 Token 登录云信 IM 服务端。
- 用户A 和用户B 登录云信圈组服务端,此时无需再传入 Token 等参数。
- 用户A 创建圈组服务器,并在服务器内创建频道。
- 用户B 加入圈组服务器。
- 用户A 在频道发送一条消息到云信圈组服务端。
- 云信圈组服务端投递消息至频道,用户B 接收消息。
前提条件
- 已开通圈组功能。
- 已完成圈组初始化。
如果频道所属的服务器的成员人数超过 2000 人阈值,接收方还必须先订阅该频道,才能收到该频道的消息。如果未超过 2000 人阈值,无需订阅也能收到消息。订阅相关说明,请参见圈组订阅机制。
实现流程
实现消息收发
API 调用时序
sequenceDiagram
note over NIM SDK: 初始化 SDK 并登录 IM
note over NIM SDK: 注册回调函数并登录圈组
发送方 ->> NIM SDK: 监听"即将发送消息"事件
发送方 ->> NIM SDK: 监听消息发送进度
发送方 ->> NIM SDK: 监听"消息发送完成"事件
发送方 ->> NIM SDK: 监听"上传附件成功"事件<br>(仅发送多媒体消息需要)
发送方 ->> NIM SDK: 登录圈组
接收方 ->> NIM SDK: 监听消息接收
接收方 ->> NIM SDK: 监听"附件下载进度"<br>(仅接收多媒体消息需要)
接收方 ->> NIM SDK: 监听"附件下载成功"事件<br>(仅接收多媒体消息需要)
接收方 ->> NIM SDK: 登录圈组
note over NIM SDK: 双方都成为同一服务器的成员
note over NIM SDK: 双方都能访问同一频道
note over NIM SDK: 发送方拥有发送消息的权限
note over NIM SDK: 消息收发
发送方 ->> NIM SDK: 在频道发送消息
NIM SDK ->> 接收方: 投递消息(NIMQChatMessage)
接收方 ->> NIM SDK: 将消息标记为已读
接收方 ->> NIM SDK: 下载附件<br>(可选,仅多媒体消息收发需要)
NIM SDK ->> 接收方: 下载进度
NIM SDK ->> 接收方: 下载状态
流程说明
本节仅对上图中标为部分的流程进行说明,其他流程请参考相关文档。例如:
-
发送方在登录圈组前,调用
addDelegate:
方法添加委托(具体回调函数如下)。-
注册
willSendMessage
消息即将发送回调函数。 -
注册
sendMessage:progress:
消息发送进度回调函数。 -
注册
sendMessage:didCompleteWithError:
消息发送完成回调函数。 -
如果发送的是多媒体消息(包括图片、语音、视频和文件消息),还需注册
uploadAttachmentSuccess:forMessage:
附件上传完成回调函数。
示例代码如下:
消息即将发送回调- (void)willSendMessage:(NIMQChatMessage *)message { //your code }
消息发送进度回调objc
//消息发送进度 - (void)sendMessage:(NIMQChatMessage *)message progress:(float)progress { //your code }
消息发送完成回调objc
- (void)sendMessage:(NIMQChatMessage *)message didCompleteWithError:(nullable NSError *)error { //your code }
附件上传完成回调objc
- (void)uploadAttachmentSuccess:(NSString *)urlString forMessage:(NIMQChatMessage *)message { //your code }
-
-
接收方在登录前,调用
addDelegate:
方法添加委托(具体回调函数如下)。- 注册
onRecvMessages:
消息接收回调函数。 - 如果接收多媒体消息,还需注册
fetchMessageAttachment:progress:
消息下载进度回调函数。 - 如果接收多媒体消息,还需注册
fetchMessageAttachment:didCompleteWithError:
消息下载完成回调函数。
示例代码如下:
消息接收回调函数- (void)onRecvMessages:(NSArray<NIMQChatMessage *> *)messages { //your code, deal messages }
附件下载进度进度回调objc
/** * 收取消息附件回调 * @param message 当前收取的消息 * @param progress 进度 * @discussion 附件包括:图片,视频的缩略图,语音文件 */ - (void)fetchMessageAttachment:(NIMQChatMessage *)message progress:(float)progress { //your code }
附件下载完成回调objc
/** * 收取消息附件完成回调 * * @param message 当前收取的消息 * @param error 错误返回,如果收取成功,error为nil */ - (void)fetchMessageAttachment:(NIMQChatMessage *)message didCompleteWithError:(nullable NSError *)error { //your code }
- 注册
-
发送方构建一条消息,并调用
sendMessage:toSession:error:
或针对大文件的sendMessage:toSession:completion:
异步方法发送该消息。调用时通过messageType
参数设置消息类型。调用时,可通过
NIMMessageSetting
配置消息是否保存历史消息、计入未读数、需要推送和开启抄送等。消息发送方需要拥有发送消息的权限(
NIMQChatPermissionTypeSendMsg
)。
部分重要方法说明如下:
参数 类型 说明 yidunAntiSpamSetting
NIMQChatMessageAntispamSetting
配置安全通(易盾反垃圾)相关的各项参数。如果您配置了这些参数,在发送消息时,会对发送的文本和附件进行内容审核(反垃圾检测)。根据您在云信控制台预设的拦截/过滤规则,如果检测到违规内容,消息可能发送失败或者敏感信息被过滤。 圈组的安全通功能属于增值功能,需要在开通圈组功能后再额外开通,具体请参考开通 IM 安全通。 mentionAll
BOOL 是否@所有人,false:否,true:是 用户需要拥有@所有人权限才能@所有人。 mentionedAccids
NSArray<NSString *>
@部分人,如果将该消息设置为@所有人或者@身份组,则本参数无效) 用户需要拥有@他人权限( remindOther
)才能@部分人。mentionRoleIds
NSArray<NSString *>
@的身份组列表,最多@ 10 个身份组。如果将该消息设置为@所有人,则本参数无效 用户需要拥有@身份组权限才能@身份组。 发送不同类型消息的示例代码如下:
文本id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NIMQChatMessage *message = [[NIMQChatMessage alloc] init]; NIMSession * session = [NIMSession sessionForQChat:121212 qchatServerId:123456]; message.text = @"文本消息的内容"; //反垃圾 NIMQChatMessageAntispamSetting *antispamSetting = [NIMQChatMessageAntispamSetting new]; antispamSetting.antiSpamBusinessId = @"{\"txtbid\":\"5624564236342d543\"}"; antispamSetting.antiSpamUsingYidun = YES; message.yidunAntiSpamSetting = antispamSetting; //抄送 message.env = @"***" NSError *error = nil; BOOL result = [qchatMessageManager sendMessage:message toSession:session error:&error];
图片id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NIMQChatMessage *message = [[NIMQChatMessage alloc] init]; NIMSession * session = [NIMSession sessionForQChat:121212 qchatServerId:123456]; message.text = @"图片"; NIMImageObject * imageObject = [[NIMImageObject alloc] initWithImage:[UIImage imageNamed:@"**"]]; message.messageObject = imageObject; //反垃圾 NIMQChatMessageAntispamSetting *antispamSetting = [NIMQChatMessageAntispamSetting new]; antispamSetting.antiSpamBusinessId = @"{\"txtbid\":\"5624564236342d543\"}"; antispamSetting.antiSpamUsingYidun = YES; message.yidunAntiSpamSetting = antispamSetting; //抄送 message.env = @"***" NSError *error = nil; BOOL result = [qchatMessageManager sendMessage:message toSession:session error:&error];
语音id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NIMQChatMessage *message = [[NIMQChatMessage alloc] init]; NIMSession * session = [NIMSession sessionForQChat:121212 qchatServerId:123456]; message.text = @"语音"; //filePath 为音频路径 NIMAudioObject *audioObject = [[NIMAudioObject alloc] initWithSourcePath:filePath]; message.messageObject = audioObject; //反垃圾 NIMQChatMessageAntispamSetting *antispamSetting = [NIMQChatMessageAntispamSetting new]; antispamSetting.antiSpamBusinessId = @"{\"txtbid\":\"5624564236342d543\"}"; antispamSetting.antiSpamUsingYidun = YES; message.yidunAntiSpamSetting = antispamSetting; //抄送 message.env = @"***" NSError *error = nil; BOOL result = [qchatMessageManager sendMessage:message toSession:session error:&error];
视频id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NIMQChatMessage *message = [[NIMQChatMessage alloc] init]; NIMSession * session = [NIMSession sessionForQChat:121212 qchatServerId:123456]; message.text = @"文本消息的内容"; //filePath 为视频路径 NIMVideoObject *videoObject = [[NIMVideoObject alloc] initWithSourcePath:filePath]; message.messageObject = videoObject; //反垃圾 NIMQChatMessageAntispamSetting *antispamSetting = [NIMQChatMessageAntispamSetting new]; antispamSetting.antiSpamBusinessId = @"{\"txtbid\":\"5624564236342d543\"}"; antispamSetting.antiSpamUsingYidun = YES; message.yidunAntiSpamSetting = antispamSetting; //抄送 message.env = @"***" NSError *error = nil; BOOL result = [qchatMessageManager sendMessage:message toSession:session error:&error];
文件id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NIMQChatMessage *message = [[NIMQChatMessage alloc] init]; NIMSession * session = [NIMSession sessionForQChat:121212 qchatServerId:123456]; message.text = @"文件"; //filePath 为文件路径 NIMFileObject *object = [[NIMFileObject alloc] initWithSourcePath:filepath]; message.messageObject = object; //反垃圾 NIMQChatMessageAntispamSetting *antispamSetting = [NIMQChatMessageAntispamSetting new]; antispamSetting.antiSpamBusinessId = @"{\"txtbid\":\"5624564236342d543\"}"; antispamSetting.antiSpamUsingYidun = YES; message.yidunAntiSpamSetting = antispamSetting; //抄送 message.env = @"***" NSError *error = nil; BOOL result = [qchatMessageManager sendMessage:message toSession:session error:&error];
提示id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NIMQChatMessage *message = [[NIMQChatMessage alloc] init]; NIMSession * session = [NIMSession sessionForQChat:121212 qchatServerId:123456]; message.text = @"提示"; NIMTipObject *object = [[NIMTipObject alloc] init]; object.attach = @"*****"; message.messageObject = object; //反垃圾 NIMQChatMessageAntispamSetting *antispamSetting = [NIMQChatMessageAntispamSetting new]; antispamSetting.antiSpamBusinessId = @"{\"txtbid\":\"5624564236342d543\"}"; antispamSetting.antiSpamUsingYidun = YES; message.yidunAntiSpamSetting = antispamSetting; //抄送 message.env = @"***" NSError *error = nil; BOOL result = [qchatMessageManager sendMessage:message toSession:session error:&error];
通知id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NIMQChatMessage *message = [[NIMQChatMessage alloc] init]; NIMSession * session = [NIMSession sessionForQChat:121212 qchatServerId:123456]; message.text = @"通知"; NIMNotificationObject *object = [[NIMNotificationObject alloc] init]; object.content = @"**向你打了个招呼"; message.messageObject = object; //反垃圾 NIMQChatMessageAntispamSetting *antispamSetting = [NIMQChatMessageAntispamSetting new]; antispamSetting.antiSpamBusinessId = @"{\"txtbid\":\"5624564236342d543\"}"; antispamSetting.antiSpamUsingYidun = YES; message.yidunAntiSpamSetting = antispamSetting; //抄送 message.env = @"***" NSError *error = nil; BOOL result = [qchatMessageManager sendMessage:message toSession:session error:&error];
自定义id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NIMQChatMessage *message = [[NIMQChatMessage alloc] init]; NIMSession * session = [NIMSession sessionForQChat:121212 qchatServerId:123456]; NIMCustomObject *object = [[NIMCustomObject alloc] init]; //自定义对象的附件需要实现<> object.attachment = id<NIMCustomAttachment>**; message.messageObject = object; //反垃圾 NIMQChatMessageAntispamSetting *antispamSetting = [NIMQChatMessageAntispamSetting new]; antispamSetting.antiSpamBusinessId = @"{\"txtbid\":\"5624564236342d543\"}"; antispamSetting.antiSpamUsingYidun = YES; message.yidunAntiSpamSetting = antispamSetting; //抄送 message.env = @"***" NSError *error = nil; BOOL result = [qchatMessageManager sendMessage:message toSession:session error:&error];
-
消息接收回调函数触发,消息投递至接收方。
-
接收方调用
markMessageRead:completion:
方法将接收到的消息标记为已读。- 将消息标记为已读后,该消息之前接收到的消息全部变为已读状态。
- 如果传入的时间戳参数为 0,则频道内所有消息将被标记为未读。
- 该方法调用存在频控,300ms 内最多可调用一次。
示例代码如下:
id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NIMQChatMarkMessageReadParam *param = [[NIMQChatMarkMessageReadParam alloc] init]; param.serverId = 123456; param.channelId = 121212; param.ackTimestamp = 1641006661.111; [qchatMessageManager markMessageRead:param completion:^(NSError *__nullable error) { // your code }];
-
如果接收方接收到的是多媒体消息,可调用
fetchMessageAttachment:error:
方法下载附件。下载附件会触发附件下载进度和附件下载完成回调函数。
示例代码如下:
id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager]; NSError *error = nil; BOOL result = [qchatMessageManager fetchMessageAttachment:(NIMQChatMessage *)message error:&error];
圈组自定义消息的解析流程,请参考 自定义消息收发 的示例。
实现消息重发
如果因为网络等原因消息发送失败,可以调用resendMessage:error:
方法重发消息。该方法的入参message
需传入待重发的消息体(NIMQChatMessage
)。
示例代码如下:
id<NIMQChatMessageManager> qchatMessageManager = [[NIMSDK sharedSDK] qchatMessageManager];
NSError *error = nil;
BOOL result = [qchatMessageManager resendMessage:(NIMQChatMessage *)message
error:&error];
相关参考
消息未读数限制
- 所有未读消息(包括@消息)的消息阈值默认为 99 条。
- @消息的未读数的有效期,默认为 7 天,即默认存储 7 天。
若需要扩展上限,可在控制台配置圈组子功能项(未读的@消息数-周期 和 所有未读消息(包括@)的消息计数-阈值),具体请参考开通和配置圈组功能。