
IOS
【社区精华|持续更新】收录本社区精华内容,手把手教学IM/RTC开发!
IM即时通讯 • admin 发表了文章 • 8 个评论 • 492 次浏览 • 2020-12-07 14:41

本文收录了GeekOnline社区精华内容,希望帮助社区开发者学习IM+RTC知识,解答疑惑。赠人玫瑰,手有余香,如您有不错的内容需要收录,欢迎在在评论区投稿回复。
Android篇
解决融云 SDK 4.0 版本配置 https 导航报 SSLHandshakeException
融云即时通讯SDK集成 — 定制UI(一) ——会话界面小改动
融云即时通讯SDK集成 — 定制UI(二) ——添加自定义表情库
融云即时通讯SDK集成 — 定制UI(三) ——兼容Android Q
融云即时通讯SDK集成 — 国内厂商推送集成踩坑篇(Android平台)
融云 ConversationListFragment 会话列表添加头部布局
融云即时通讯SDK集成 — FCM推送集成指南(Android平台)
iOS篇
集成融云 IMLib 时,如何实现一套类似于 IMKit 的用户信息管理机制
干货分享——使用融云通讯能力库 IMLib 实现单群聊的阅读回执
Web篇
作为小白接融云 IM SDK 新路体验~
微信小程序集成融云 SDK (即时通讯) 集成必备条件
Web 端使用融云 SDK 集成实现滑动加载历史消息
融云IM SDK web 端集成 — 表情采坑篇
融云 Web SDK 如何实现表情的收发 ?
集成融云小程序 SDK 遇到的问题
使用融云 Web SDK 撤回消息
Web 端集成融云 SDK 如何发送正确图片消息给移动端展示?
融云 Web 播放声音 — Flash 篇 (播放 AMR、WAV)
融云 AMR(Aduio) 播放 AMR 格式 Base64 码音频
社区福利
【领取见面礼】限量 100份 GeekOnline加油包!等你来拿
【有奖调研】Geek Online 2020 编程挑战赛参赛调研
【征稿活动】Geek Online 社区第一期投稿激励计划已启动!
GeekOnline编程挑战赛
Geek Online 2020 编程挑战赛 GitHub 仓库
2 个月激烈角逐,15 支队伍突围决赛路演!Geek Online 2020 编程挑战赛完美收官!
一张图回顾 Geek Online 2020 编程挑战赛精彩瞬间!
“这些项目不是什么赚大钱的项目,但是它们足够有趣。”丨关于 Geek Online 2020 编程挑战赛,选手们如是说
融云 CTO 杨攀: Geek Online 2020 编程挑战赛 让开发者站上 C 位
【参赛攻略】你想了解的Geek Online 2020 编程挑战赛常见问题这里都有!
【融云集成常见问题整理】Geek Online 2020 编程挑战赛选手提问整理
求职招聘
持续更新....
融云 IMKit 音频录制参数
IM即时通讯 • 王叫兽 发表了文章 • 0 个评论 • 215 次浏览 • 2021-01-11 15:14
场景:
使用融云自带的界面进行语音消息的播放。
自己进行音频录制。
使用的融云的
RCHQMessage
问题:
语音消息 iOS 和 Android 不互通,接收到消息之后无法播放。
解决方案:
经过与融云开发者的确认,使用时必须保证如下录制参数:
iOS AVAudioRecorder 录制参数如下设置:
AVFormatIDKey : @(kAudioFormatMPEG4AAC_HE),
AVSampleRateKey : @(44100.0),
AVNumberOfChannelsKey : @1,
AVEncoderBitRateKey : @(16000)
Android MediaRecorder 录制参数如下:
setAudioSamplingRate(44100);
setAudioEncodingBitRate(16000);
setAudioChannels(1);
setAudioSource(MediaRecorder.AudioSource.MIC);
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
其他一些内容的使用可以自己去官网文档搜索:
融云文档:https://docs.rongcloud.cn/v4/
融云会话页面刷新不及时问题
IM即时通讯 • 徐凤年 发表了文章 • 0 个评论 • 227 次浏览 • 2021-01-11 15:14
项目用的融云 IMKit SDK,调试中发现收到消息的时候,不刷新,上拉一下才会显示。排查方法是直接使用 SDK 的会话页面,排除是子类代码的问题,替换后发现还是有此问题。后来和技术人员沟通发现是使用了 RCIMClient 中的初始化接口,这样会影响 UI 刷新的。替换为 RCIM 的初始化方法,问题解决!希望此文字可以帮助到后续开发者!
/*!
初始化融云SDK
@param appKey 从融云开发者平台创建应用后获取到的App Key
@discussion 您在使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化SDK。
在App整个生命周期中,您只需要执行一次初始化。
@warning 如果您使用IMKit,请使用此方法初始化SDK;
如果您使用IMLib,请使用RCIMClient中的同名方法初始化,而不要使用此方法。
*/
- (void)initWithAppKey:(NSString *)appKey;
友情提示融云官网:(www.rongcloud.cn)
融云自定义消息不显示
IM即时通讯 • 徐凤年 发表了文章 • 0 个评论 • 118 次浏览 • 2021-01-11 15:14
项目用的融云,IMKit SDK(自带 UI),但是出现一个问题,就是自定义消息在会话页面刚收到的时候能显示,但是退出会话页面再进入就不显示了。非常的纳闷啊。查询了存储策略,编解码方法,都没有问题。后来提交工单,技术人员给了反馈才发现自己把消息的注册放到了初始化 appkey 前边,然后人家融云写的很明确:使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化 SDK。可见认真查看文档接口注释的重要性!!
/*!
初始化融云SDK
@param appKey 从融云开发者平台创建应用后获取到的App Key
@discussion 您在使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化SDK。
在App整个生命周期中,您只需要执行一次初始化。
@warning 如果您使用IMKit,请使用此方法初始化SDK;
如果您使用IMLib,请使用RCIMClient中的同名方法初始化,而不要使用此方法。
*/
- (void)initWithAppKey:(NSString *)appKey;
融云(www.rongcloud.cn)
如何利用融云 IMLib 来实现一个阅后即焚功能
IM即时通讯 • 柠檬^ 发表了文章 • 0 个评论 • 212 次浏览 • 2021-01-11 15:14
场景
项目需要在私聊中来实现一个阅后即焚的功能,即 A 用户给 B 用户发送消息,B 用户在进入聊天页面查看之后 A 用户删除此消息,B 用户开始进入倒计时,倒计时结束后,删除此消息。
思考
大体的梳理一下具体的逻辑
A -> B
B 进入会话页面
B 将此消息开始倒计时
通知 A 我已进行阅读
A 删除消息
从上面内容我们来大体的设计一下我们需要用户的技术
单例类
自定义消息,用来告诉 A 我已经开始阅读了,你删除吧
一个用于维护阅后即焚消息的管理类
一个存储 A 给 B 发送的所有的阅后即焚的消息的容器 A k 为 targetid ,v 为 messageIDs
一个存储每条阅后即焚消息的容器 B k 为 messageId, v 为当前消息还剩的倒计时时间。
一个用来存储所有阅后即焚消息的容器 C K:ID V:msg
两个处理队列 一个处理时间 一个处理消息
对外暴露接口
代理 接收方焚烧消息的每秒倒计时
通知 接收方收到对方已阅读某条消息的通知
详解
初始化我们的所有容器
收到消息,在合适的业务时机将此消息加入到焚烧队列
查询消息是否已经在焚烧队列
如果不在,添加到 A B C容器
执行倒计时
倒计时操作
遍历 C 是否有消息
给发送方发送消息,通知我已经开始焚烧 A 里的消息了 并在 A 容器删除此会话
发送方收到消息发送通知
接收方遍历 B 容器,判断每条消息是否到时
如果消息焚烧时间到 在 A、B 容器删除,并触发代理
如果没到时间,就触发代理并修改 此消息在 B 容器的时长。
融云 SDK 如何实现群组操作
IM即时通讯 • 柠檬^ 发表了文章 • 0 个评论 • 203 次浏览 • 2021-01-11 15:14
融云 SDK 如何实现群组操作
背景
在集成融云 SDK 后,需要实现群组操作的消息通知。包括:
群创建、销毁通知
群公告通知
群人员加入、退出通知
群昵称修改通知
...
融云现有的 SDK 仅提供了 RCGroupNotificationMessage
,内部封装了几种简单的类型操作,且扩展性不强,无法完成现有的操作。
解决方案:
使用自定义消息重新来构建群组通知消息。
参考 sealtlak 中的 RCDGroupNotificationMessage
,也是单独对群组操作内容,重新进行了封装处理
/*!
群组通知消息
*/
@interface RCDGroupNotificationMessage : RCMessageContent
//操作名
@property (nonatomic, copy) NSString *operation;
//操作人
@property (nonatomic, copy) NSString *operatorUserId;
//操作对象
@property (nonatomic, strong) NSArray<NSString *> *targetUserIds;
//内容
@property (nonatomic, copy) NSString *message;
//获取摘要
- (NSString *)getDigest:(NSString *)groupId;
@end
这个类预定义了下面几种操作类型消息,具体内容可参考名字定义
extern NSString *const RCDGroupCreate;
extern NSString *const RCDGroupMemberAdd;
extern NSString *const RCDGroupMemberQuit;
extern NSString *const RCDGroupMemberKicked;
extern NSString *const RCDGroupRename;
extern NSString *const RCDGroupBulletin;
extern NSString *const RCDGroupOwnerTransfer;
extern NSString *const RCDGroupDismiss;
extern NSString *const RCDGroupMemberJoin;
extern NSString *const RCDGroupMemberManagerSet;
extern NSString *const RCDGroupMemberManagerRemove;
extern NSString *const RCDGroupMemberProtectionOpen;
extern NSString *const RCDGroupMemberProtectionClose;
.m 的实现还是按照自定义消息的实现进行处理。唯一有区别的是在获取摘要的方法,在这个方法中对消息内容进行了处理,根据操作名的不同,来对显示的内容进行各种适配。此处根据根据自己的业务进行修改。
- (NSString *)getDigest:(NSString *)groupId {
NSString *content;
//获取用户信息
NSString *operationName = [self getDisplayNames:@[ self.operatorUserId?self.operatorUserId:@""] groupId:groupId];
NSString *targetNames = [self getDisplayNames:self.targetUserIds groupId:groupId];
//是否当前用户操作
BOOL isMeOperate = NO;
if ([self.operatorUserId isEqualToString:[RCIMClient sharedRCIMClient].currentUserInfo.userId]) {
isMeOperate = YES;
}
//判断操作类型
if ([self.operation isEqualToString:RCDGroupCreate]) {
content =
[NSString stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveCreated" : @"GroupCreated",
@"RongCloudKit", nil),
operationName];
} else if ([self.operation isEqualToString:RCDGroupMemberAdd]) {
if (self.targetUserIds.count == 1 && [self.targetUserIds containsObject:self.operatorUserId]) {
content = [NSString
stringWithFormat:NSLocalizedStringFromTable(@"GroupJoin", @"RongCloudKit", nil), operationName];
} else {
content = [NSString
stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveInvited" : @"GroupInvited",
@"RongCloudKit", nil),
operationName, targetNames];
}
} else if ([self.operation isEqualToString:RCDGroupMemberJoin]) {
content =
[NSString stringWithFormat:NSLocalizedStringFromTable(@"GroupJoin", @"RongCloudKit", nil), operationName];
} else if ([self.operation isEqualToString:RCDGroupMemberQuit]) {
content = [NSString stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveQuit" : @"GroupQuit",
@"RongCloudKit", nil),
operationName];
} else if ([self.operation isEqualToString:RCDGroupMemberKicked]) {
content =
[NSString stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveRemoved" : @"GroupRemoved",
@"RongCloudKit", nil),
operationName, targetNames];
} else if ([self.operation isEqualToString:RCDGroupRename]) {
content = [NSString stringWithFormat:NSLocalizedStringFromTable(@"GroupChanged", @"RongCloudKit", nil),
operationName, self.targetGroupName];
} else if ([self.operation isEqualToString:RCDGroupDismiss]) {
content =
[NSString stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveDismiss" : @"GroupDismiss",
@"RongCloudKit", nil),
operationName];
} else if ([self.operation isEqualToString:RCDGroupOwnerTransfer]) {
content = [NSString stringWithFormat:RCDLocalizedString(@"GroupHasNewOwner"), targetNames];
} else if ([self.operation isEqualToString:RCDGroupMemberManagerSet]) {
content = [NSString stringWithFormat:RCDLocalizedString(@"GroupSetManagerMessage"), targetNames];
} else if ([self.operation isEqualToString:RCDGroupMemberProtectionOpen]) {
content = RCDLocalizedString(@"openMemberProtection");
} else if ([self.operation isEqualToString:RCDGroupMemberProtectionClose]) {
content = [NSString stringWithFormat:RCDLocalizedString(@"closeMemberProtection"), operationName];
} else {
content = NSLocalizedStringFromTable(@"unknown_message_cell_tip", @"RongCloudKit", nil);
}
return content;
}
此外,还有一个获取名称的方法,用来维护用户信息。
- (NSString *)getDisplayNames:(NSArray<NSString *> *)userIds groupId:(NSString *)groupId
关于融云 SDK 在使用 p8 证书的坎坷~
IM即时通讯 • 木土走召 发表了文章 • 0 个评论 • 208 次浏览 • 2021-01-11 15:14
新上的项目使用了融云的 IM SDK,但在项目集成 APNs 推送的时候,尝鲜使用了一下开发者后台的 p8 证书,此文记录使用 p8 的辛酸史~
P8 简介
官网给出了这种更 "快" 的推送通道: Establishing a Token-Based Connection to APNs,并且这个生成的这个 key 可以适用于当前账户的所有 APP,为开发人员省了不少力气。福音啊~
想想那一堆证书...... 脑阔痛!
辛酸史
起因是这样的,在融云开发者后台上传了 p8 之后,发现 debug 环境,一直无法收到推送,在经过和融云提供的推送文档进行严格的比对之后,发现没毛病啊~
最后终于在融云开发人员的帮助下找到了问题~,融云后台目前阶段只支持生产环境~ OMG,我打你信不~
区别
p8 是可以同时支持生产和测试环境的,那么为什么融云收不到呢~
让我们大胆猜测一下:
之前基于证书进行校验的时候,一套证书是基于开发者后台一个 AppKey 绑定的,那么我用了哪个 AppKey,后端就基于 AppKey 解析对应的证书,这样就可以发送到对应的 push 环境去了,那么问题来了?使用了 p8 之后,他怎么区分呢?
我也不知道~ 哈哈哈,但我猜测应该是没有解析都去走了生产环境,因为提示我环境不匹配~
苹果 APNs 服务
Development server: api.sandbox.push.apple.com:443
Production server: api.push.apple.com:443
融云 Flutter IM SDK 解析
IM即时通讯 • 木土走召 发表了文章 • 0 个评论 • 226 次浏览 • 2021-01-11 15:14
最近准备使用融云的 Flutter SDK,所以顺便记录一下。
融云 Flutter IM SDK 地址:传送门
融云的 Flutter SDK 是基于 融云 IMLib 层做的封装,封装了 IMLib 的部分接口提供给 Flutter 开发者使用。此文章只介绍了 Flutter 层做的一些操作。
目录结构
整体 SDK 的结构规规矩矩,核心内容参考红色箭头即可。
SDK 层包含 三个目录:android:此目录包含了和原生 SDK 交互的所有 Java 文件
ios:此目录包含了和原生 SDK 交互的所有 oc 文件
lib: 此目录为使用 dart 编写的 Flutter SDK 文件
其他目录:doc:主要是融云开发者提供的一些文档相关
example:是融云开发者基于此 SDK 提供的一个简单示例,整体较为简陋,且有细微 bug,仅供参考
FunctionList.md
是融云开发者提供的一个功能清单,
大体如下:
# RongCloud IM Flutter SDK 功能清单
## 连接
初始化
连接
断开连接
连接状态兼容
## 配置
设置服务器地址( im 服务;文件服务)
## 会话
获取会话列表,支持全量获取,分页获取
获取单个会话
删除指定会话
## 消息
当前仅支持 文本消息,语音消息,图片消息,小视频消息
收发消息(可以携带 pushContent)
自定义消息
获取批量本地历史消息
获取单条本地历史消息
获取批量远端历史消息
插入消息
删除批量本地消息
获取未读数
清除指定会话未读数
## 免打扰
设置会话免打扰
获取会话免打扰
## 会话置顶
设置会话置顶
备注:获取会话是可以获取到会话置顶状态
## 黑名单
加入黑名单
移除黑名单
获取黑名单列表
检查特定用户的黑名单状态
## 聊天室
加入聊天室
退出聊天室
获取聊天室信息
都是一些接口层的操作。
剩下的文件基本可以忽略。
解析
我们开始从 lib
目录开始分析
这两个文件是核心文件,我们所有的调用接口都在这里。
rong_im_client.dart
是最新版本的接口类,我们只关心这个即可。
rong_im_plugin.dart
是旧版本的接口类,已经废弃。
common_define.dart
是定义了 SDK 内使用的所有枚举和状态码。
method_key.dart
是定义了 Flutter SDK 和原生层进行交互时标识的唯一的常量字符串。
然后就是剩下的三个文件目录:
info
: 其实就是对象 model 类
message:
这个是 Flutter SDK提供的所有内置的消息类型,包括聊天室KV消息、合并消息、文件消息、GIF消息、图片消息、位置消息、撤回消息、引用消息、图文消息、视频消息、文本消息、语音消息。
其中有一个比较特殊的 dart 类就是 message_content.dart
, 这个类是所有消息的基类。
每个消息都需要继承此类,并复写里面的方法进行编解码。
util
: 这个目录就是一个工具目录。
message_factory.dart
主要是进行消息封装,字典转模型,模型转字典,根本原因我猜就是 Flutter 和 原生仅有的交互类型限制。
type_util.dart
:略
以上就是 SDK 在 Flutter 层做的所有的操作,内容整体不多,而且所有代码都是开源的,看看基本上都了解。
与原生层的交互
整体都是通过 invokeMethod
与原生进行通信的,后面的key 就是之前说的常量字符串,用来保证唯一性。
而在 iOS
和 Android
都提供了对应的定义。
并通过触发 iOS 和 Android 层对应的方法来进行处理。
原生层
Android:
整体核心的处理都在 RCIMFlutterWrapper.java
这个类处理了 dart 代码传递过来的数据,并与融云 IMLib 的 SDK 进行了处理。
iOS:
同样,iOS 的核心代码也都在 RCIMFlutterWrapper.m
这个类处理。具体内容大家可以自己看一下。
到此整个内容我们也就大体明白了。
整体看来其实就是 flutter 中 rong_im_client.dart
和 原生的两个 Wrapper
类做交互,其他的都是助攻。
整体看来不难,搞起~
融云文档:传送门
干货分享——使用融云通讯能力库 IMLib 实现单群聊的阅读回执
IM即时通讯 • 王叫兽 发表了文章 • 0 个评论 • 219 次浏览 • 2021-01-11 15:14
今天的干货分享是关于“阅读回执”功能,这是一个很普遍的功能,但是针对使用融云的 SDK 去实现,还是有些坑在等着我们的,下面就开始分(bì)享(kēng)喽~
分享之前先做一些准备工作,先找到我们需要调用的接口文档
根据不同的会话类型以及消息的发送方和接收方,要分别处理
单聊
接收方 :在阅读消息后,调用 RCIMClient 类的发送阅读回执接口,参数如下:
conversationType 单聊会话类型
targetId 消息的会话 ID
time 会话最后一条消息的发送时间(sentTime)
/*!
发送某个会话中消息阅读的回执
@param conversationType 会话类型
@param targetId 会话 ID
@param timestamp 该会话中已阅读的最后一条消息的发送时间戳
@param successBlock 发送成功的回调
@param errorBlock 发送失败的回调[nErrorCode: 失败的错误码]
@discussion 此接口只支持单聊, 如果使用 IMLib 可以注册监听
RCLibDispatchReadReceiptNotification 通知,使用 IMKit 直接设置RCIM.h
中的 enabledReadReceiptConversationTypeList。
@warning 目前仅支持单聊。
@remarks 高级功能
*/
- (void)sendReadReceiptMessage:(RCConversationType)conversationType
targetId:(NSString *)targetId
time:(long long)timestamp
success:(void (^)(void))successBlock
error:(void (^)(RCErrorCode nErrorCode))errorBlock;
发送方:监听下面这个通知,在接收后修改消息的展示
/*!
@const 收到已读回执的 Notification
@discussion 收到消息已读回执之后,IMLib 会分发此通知。
Notification 的 object 为 nil,userInfo 为 NSDictionary 对象,
其中 key 值分别为 @"cType"、@"tId"、@"messageTime",
对应的 value 为会话类型的 NSNumber 对象 、会话的 targetId 、已阅读的最后一条消息的 sendTime。
如:
NSNumber *ctype = [notification.userInfo objectForKey:@"cType"];
NSNumber *time = [notification.userInfo objectForKey:@"messageTime"];
NSString *targetId = [notification.userInfo objectForKey:@"tId"];
NSString *fromUserId = [notification.userInfo objectForKey:@"fId"];
收到这个消息之后可以更新这个会话中 messageTime 以前的消息 UI 为已读(底层数据库消息状态已经改为已读)。
@remarks 事件监听
*/
FOUNDATION_EXPORT NSString *const RCLibDispatchReadReceiptNotification;
群聊
发送方:
在发送消息 A 后,需要针对该消息发送回执请求,message 传之前发的消息 A
/*!
请求消息阅读回执
@param message 要求阅读回执的消息
@param successBlock 请求成功的回调
@param errorBlock 请求失败的回调[nErrorCode: 失败的错误码]
@discussion 通过此接口,可以要求阅读了这条消息的用户发送阅读回执。
@remarks 高级功能
*/
- (void)sendReadReceiptRequest:(RCMessage *)message
success:(void (^)(void))successBlock
error:(void (^)(RCErrorCode nErrorCode))errorBlock;
设置下面代理函数,在接收到发送方发来的阅读回执响应后,修改消息的展示
/*!
IMlib消息接收的监听器
@discussion
设置IMLib的消息接收监听器请参考RCIMClient的setReceiveMessageDelegate:object:方法。
@warning 如果您使用IMlib,可以设置并实现此Delegate监听消息接收;
如果您使用IMKit,请使用RCIM中的RCIMReceiveMessageDelegate监听消息接收,而不要使用此监听器,否则会导致IMKit中无法自动更新UI!
*/
@protocol RCIMClientReceiveMessageDelegate <NSObject>
/*!
消息已读回执响应(收到阅读回执响应,可以按照 messageUId 更新消息的阅读数)
@param messageUId 请求已读回执的消息ID
@param conversationType conversationType
@param targetId targetId
@param userIdList 已读userId列表
*/
- (void)onMessageReceiptResponse:(RCConversationType)conversationType
targetId:(NSString *)targetId
messageUId:(NSString *)messageUId
readerList:(NSMutableDictionary *)userIdList;
接收方:
设置下面代理函数,在接收到消息 A 后,还会接收到针对消息 A 的阅读回执请求
/*!
IMlib消息接收的监听器
@discussion
设置IMLib的消息接收监听器请参考RCIMClient的setReceiveMessageDelegate:object:方法。
@warning 如果您使用IMlib,可以设置并实现此Delegate监听消息接收;
如果您使用IMKit,请使用RCIM中的RCIMReceiveMessageDelegate监听消息接收,而不要使用此监听器,否则会导致IMKit中无法自动更新UI!
*/
@protocol RCIMClientReceiveMessageDelegate <NSObject>
/*!
请求消息已读回执(收到需要阅读时发送回执的请求,收到此请求后在会话页面已经展示该 messageUId 对应的消息或者调用
getHistoryMessages 获取消息的时候,包含此 messageUId 的消息,需要调用 sendMessageReadReceiptResponse
接口发送消息阅读回执)
@param messageUId 请求已读回执的消息ID
@param conversationType conversationType
@param targetId targetId
*/
- (void)onMessageReceiptRequest:(RCConversationType)conversationType
targetId:(NSString *)targetId
messageUId:(NSString *)messageUId;
在代理方法中,调用下面接口发送阅读回执响应给发送方
/*!
发送阅读回执
@param conversationType 会话类型
@param targetId 会话 ID
@param messageList 已经阅读了的消息列表
@param successBlock 发送成功的回调
@param errorBlock 发送失败的回调[nErrorCode: 失败的错误码]
@discussion 当用户阅读了需要阅读回执的消息,可以通过此接口发送阅读回执,消息的发送方即可直接知道那些人已经阅读。
@remarks 高级功能
*/
- (void)sendReadReceiptResponse:(RCConversationType)conversationType
targetId:(NSString *)targetId
messageList:(NSArray<RCMessage *> *)messageList
success:(void (^)(void))successBlock
error:(void (^)(RCErrorCode nErrorCode))errorBlock;
总结
阅读回执需要区分会话类型处理,且单聊的阅读回执是针对会话的,群聊的阅读回执是针对某一条消息的:
单聊:接收方阅读某个会话的消息后,发送阅读回执 ——发送方接到阅读回执,更新 UI
群聊:发送方发送消息 A, 针对该消息,发送阅读回执请求 —— 接收方实现监听代理,接收到消息 A 的阅读回执请求 —— 接收方发送阅读回执响应 —— 发送方收到阅读回执响应,更新 UI
如何设置融云用户信息
IM即时通讯 • dht1212 发表了文章 • 0 个评论 • 222 次浏览 • 2021-01-08 11:35
最近在使用融云,由于第一次使用,遇到了一个小坑,在这里记录一下,希望能帮助到后续开发者
问题是使用了融云的 IMKit 组件,也就是自带 UI 的,对于快速试错的产品来说,工期必须短,所以使用 IMKit 是非常方便的,省去了很大部分时间去搞界面。但是使用过程中发现,没有用户的头像和昵称。后来经过阅读文档发现,需要设置“用户信息提供者”代理方法。SDK 在需要显示头像和昵称的时候,会通过这个代理找开发者索取用户信息,开发者只要遵循代理,且实现代理方法,返回用户信息即可。
上代码:
1.遵循代理
@interface AppDelegate () <RCIMUserInfoDataSource>
@end
2.设置代理
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//必须先初始化
[[RCIM sharedRCIM] initWithAppKey:"开发者自己的 appkey"];
[[RCIM sharedRCIM] connectWithToken:"当前用户的 token" dbOpened:^(RCDBErrorCode code) {
} success:^(NSString *userId) {
} error:^(RCConnectErrorCode errorCode) {
}];
//设置当前用户信息
RCUserInfo *currentUser = [[RCUserInfo alloc] initWithUserId:@"tiezhu" name:@"铁柱" portrait:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1573646812313&di=116350f184eda99d91393304fa83a6ea&imgtype=0&src=http%3A%2F%2Fimg.jinse.com%2F712431_image3.png"];
[RCIM sharedRCIM].currentUserInfo = currentUser;
//设置代理
[RCIM sharedRCIM].userInfoDataSource = self;
}
3.实现代理方法
- (void)getUserInfoWithUserId:(NSString *)userId completion:(void (^)(RCUserInfo *userInfo))completion {
//这里最好是从开发者自己服务器获取用户信息,然后返回。此处仅为示例
RCUserInfo *user = nil;
if ([userId isEqualToString:@"tiezhu"]) {
user = [[RCUserInfo alloc] initWithUserId:@"tiezhu" name:@"铁柱" portrait:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1570172426&di=01d14daa81f320235376d9c4dede0493&imgtype=jpg&er=1&src=http%3A%2F%2Fgss0.baidu.com%2F-vo3dSag_xI4khGko9WTAnF6hhy%2Fzhidao%2Fpic%2Fitem%2Fd788d43f8794a4c240e9466f0ef41bd5ac6e39af.jpg"];
}
if (completion) {
completion(user);
}
}
到此就搞定了兄嘚,值一杯秋天的奶茶
【社区精华|持续更新】收录本社区精华内容,手把手教学IM/RTC开发!
IM即时通讯 • admin 发表了文章 • 8 个评论 • 492 次浏览 • 2020-12-07 14:41

本文收录了GeekOnline社区精华内容,希望帮助社区开发者学习IM+RTC知识,解答疑惑。赠人玫瑰,手有余香,如您有不错的内容需要收录,欢迎在在评论区投稿回复。
Android篇
解决融云 SDK 4.0 版本配置 https 导航报 SSLHandshakeException
融云即时通讯SDK集成 — 定制UI(一) ——会话界面小改动
融云即时通讯SDK集成 — 定制UI(二) ——添加自定义表情库
融云即时通讯SDK集成 — 定制UI(三) ——兼容Android Q
融云即时通讯SDK集成 — 国内厂商推送集成踩坑篇(Android平台)
融云 ConversationListFragment 会话列表添加头部布局
融云即时通讯SDK集成 — FCM推送集成指南(Android平台)
iOS篇
集成融云 IMLib 时,如何实现一套类似于 IMKit 的用户信息管理机制
干货分享——使用融云通讯能力库 IMLib 实现单群聊的阅读回执
Web篇
作为小白接融云 IM SDK 新路体验~
微信小程序集成融云 SDK (即时通讯) 集成必备条件
Web 端使用融云 SDK 集成实现滑动加载历史消息
融云IM SDK web 端集成 — 表情采坑篇
融云 Web SDK 如何实现表情的收发 ?
集成融云小程序 SDK 遇到的问题
使用融云 Web SDK 撤回消息
Web 端集成融云 SDK 如何发送正确图片消息给移动端展示?
融云 Web 播放声音 — Flash 篇 (播放 AMR、WAV)
融云 AMR(Aduio) 播放 AMR 格式 Base64 码音频
社区福利
【领取见面礼】限量 100份 GeekOnline加油包!等你来拿
【有奖调研】Geek Online 2020 编程挑战赛参赛调研
【征稿活动】Geek Online 社区第一期投稿激励计划已启动!
GeekOnline编程挑战赛
Geek Online 2020 编程挑战赛 GitHub 仓库
2 个月激烈角逐,15 支队伍突围决赛路演!Geek Online 2020 编程挑战赛完美收官!
一张图回顾 Geek Online 2020 编程挑战赛精彩瞬间!
“这些项目不是什么赚大钱的项目,但是它们足够有趣。”丨关于 Geek Online 2020 编程挑战赛,选手们如是说
融云 CTO 杨攀: Geek Online 2020 编程挑战赛 让开发者站上 C 位
【参赛攻略】你想了解的Geek Online 2020 编程挑战赛常见问题这里都有!
【融云集成常见问题整理】Geek Online 2020 编程挑战赛选手提问整理
求职招聘
持续更新....
【社区精华|持续更新】收录本社区精华内容,手把手教学IM/RTC开发!
IM即时通讯 • admin 发表了文章 • 8 个评论 • 492 次浏览 • 2020-12-07 14:41

本文收录了GeekOnline社区精华内容,希望帮助社区开发者学习IM+RTC知识,解答疑惑。赠人玫瑰,手有余香,如您有不错的内容需要收录,欢迎在在评论区投稿回复。
Android篇
解决融云 SDK 4.0 版本配置 https 导航报 SSLHandshakeException
融云即时通讯SDK集成 — 定制UI(一) ——会话界面小改动
融云即时通讯SDK集成 — 定制UI(二) ——添加自定义表情库
融云即时通讯SDK集成 — 定制UI(三) ——兼容Android Q
融云即时通讯SDK集成 — 国内厂商推送集成踩坑篇(Android平台)
融云 ConversationListFragment 会话列表添加头部布局
融云即时通讯SDK集成 — FCM推送集成指南(Android平台)
iOS篇
集成融云 IMLib 时,如何实现一套类似于 IMKit 的用户信息管理机制
干货分享——使用融云通讯能力库 IMLib 实现单群聊的阅读回执
Web篇
作为小白接融云 IM SDK 新路体验~
微信小程序集成融云 SDK (即时通讯) 集成必备条件
Web 端使用融云 SDK 集成实现滑动加载历史消息
融云IM SDK web 端集成 — 表情采坑篇
融云 Web SDK 如何实现表情的收发 ?
集成融云小程序 SDK 遇到的问题
使用融云 Web SDK 撤回消息
Web 端集成融云 SDK 如何发送正确图片消息给移动端展示?
融云 Web 播放声音 — Flash 篇 (播放 AMR、WAV)
融云 AMR(Aduio) 播放 AMR 格式 Base64 码音频
社区福利
【领取见面礼】限量 100份 GeekOnline加油包!等你来拿
【有奖调研】Geek Online 2020 编程挑战赛参赛调研
【征稿活动】Geek Online 社区第一期投稿激励计划已启动!
GeekOnline编程挑战赛
Geek Online 2020 编程挑战赛 GitHub 仓库
2 个月激烈角逐,15 支队伍突围决赛路演!Geek Online 2020 编程挑战赛完美收官!
一张图回顾 Geek Online 2020 编程挑战赛精彩瞬间!
“这些项目不是什么赚大钱的项目,但是它们足够有趣。”丨关于 Geek Online 2020 编程挑战赛,选手们如是说
融云 CTO 杨攀: Geek Online 2020 编程挑战赛 让开发者站上 C 位
【参赛攻略】你想了解的Geek Online 2020 编程挑战赛常见问题这里都有!
【融云集成常见问题整理】Geek Online 2020 编程挑战赛选手提问整理
求职招聘
持续更新....
融云 IMKit 音频录制参数
IM即时通讯 • 王叫兽 发表了文章 • 0 个评论 • 215 次浏览 • 2021-01-11 15:14
场景:
使用融云自带的界面进行语音消息的播放。
自己进行音频录制。
使用的融云的
RCHQMessage
问题:
语音消息 iOS 和 Android 不互通,接收到消息之后无法播放。
解决方案:
经过与融云开发者的确认,使用时必须保证如下录制参数:
iOS AVAudioRecorder 录制参数如下设置:
AVFormatIDKey : @(kAudioFormatMPEG4AAC_HE),
AVSampleRateKey : @(44100.0),
AVNumberOfChannelsKey : @1,
AVEncoderBitRateKey : @(16000)
Android MediaRecorder 录制参数如下:
setAudioSamplingRate(44100);
setAudioEncodingBitRate(16000);
setAudioChannels(1);
setAudioSource(MediaRecorder.AudioSource.MIC);
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
其他一些内容的使用可以自己去官网文档搜索:
融云文档:https://docs.rongcloud.cn/v4/
融云会话页面刷新不及时问题
IM即时通讯 • 徐凤年 发表了文章 • 0 个评论 • 227 次浏览 • 2021-01-11 15:14
项目用的融云 IMKit SDK,调试中发现收到消息的时候,不刷新,上拉一下才会显示。排查方法是直接使用 SDK 的会话页面,排除是子类代码的问题,替换后发现还是有此问题。后来和技术人员沟通发现是使用了 RCIMClient 中的初始化接口,这样会影响 UI 刷新的。替换为 RCIM 的初始化方法,问题解决!希望此文字可以帮助到后续开发者!
/*!
初始化融云SDK
@param appKey 从融云开发者平台创建应用后获取到的App Key
@discussion 您在使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化SDK。
在App整个生命周期中,您只需要执行一次初始化。
@warning 如果您使用IMKit,请使用此方法初始化SDK;
如果您使用IMLib,请使用RCIMClient中的同名方法初始化,而不要使用此方法。
*/
- (void)initWithAppKey:(NSString *)appKey;
友情提示融云官网:(www.rongcloud.cn)
融云自定义消息不显示
IM即时通讯 • 徐凤年 发表了文章 • 0 个评论 • 118 次浏览 • 2021-01-11 15:14
项目用的融云,IMKit SDK(自带 UI),但是出现一个问题,就是自定义消息在会话页面刚收到的时候能显示,但是退出会话页面再进入就不显示了。非常的纳闷啊。查询了存储策略,编解码方法,都没有问题。后来提交工单,技术人员给了反馈才发现自己把消息的注册放到了初始化 appkey 前边,然后人家融云写的很明确:使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化 SDK。可见认真查看文档接口注释的重要性!!
/*!
初始化融云SDK
@param appKey 从融云开发者平台创建应用后获取到的App Key
@discussion 您在使用融云SDK所有功能(包括显示SDK中或者继承于SDK的View)之前,您必须先调用此方法初始化SDK。
在App整个生命周期中,您只需要执行一次初始化。
@warning 如果您使用IMKit,请使用此方法初始化SDK;
如果您使用IMLib,请使用RCIMClient中的同名方法初始化,而不要使用此方法。
*/
- (void)initWithAppKey:(NSString *)appKey;
融云(www.rongcloud.cn)
如何利用融云 IMLib 来实现一个阅后即焚功能
IM即时通讯 • 柠檬^ 发表了文章 • 0 个评论 • 212 次浏览 • 2021-01-11 15:14
场景
项目需要在私聊中来实现一个阅后即焚的功能,即 A 用户给 B 用户发送消息,B 用户在进入聊天页面查看之后 A 用户删除此消息,B 用户开始进入倒计时,倒计时结束后,删除此消息。
思考
大体的梳理一下具体的逻辑
A -> B
B 进入会话页面
B 将此消息开始倒计时
通知 A 我已进行阅读
A 删除消息
从上面内容我们来大体的设计一下我们需要用户的技术
单例类
自定义消息,用来告诉 A 我已经开始阅读了,你删除吧
一个用于维护阅后即焚消息的管理类
一个存储 A 给 B 发送的所有的阅后即焚的消息的容器 A k 为 targetid ,v 为 messageIDs
一个存储每条阅后即焚消息的容器 B k 为 messageId, v 为当前消息还剩的倒计时时间。
一个用来存储所有阅后即焚消息的容器 C K:ID V:msg
两个处理队列 一个处理时间 一个处理消息
对外暴露接口
代理 接收方焚烧消息的每秒倒计时
通知 接收方收到对方已阅读某条消息的通知
详解
初始化我们的所有容器
收到消息,在合适的业务时机将此消息加入到焚烧队列
查询消息是否已经在焚烧队列
如果不在,添加到 A B C容器
执行倒计时
倒计时操作
遍历 C 是否有消息
给发送方发送消息,通知我已经开始焚烧 A 里的消息了 并在 A 容器删除此会话
发送方收到消息发送通知
接收方遍历 B 容器,判断每条消息是否到时
如果消息焚烧时间到 在 A、B 容器删除,并触发代理
如果没到时间,就触发代理并修改 此消息在 B 容器的时长。
融云 SDK 如何实现群组操作
IM即时通讯 • 柠檬^ 发表了文章 • 0 个评论 • 203 次浏览 • 2021-01-11 15:14
融云 SDK 如何实现群组操作
背景
在集成融云 SDK 后,需要实现群组操作的消息通知。包括:
群创建、销毁通知
群公告通知
群人员加入、退出通知
群昵称修改通知
...
融云现有的 SDK 仅提供了 RCGroupNotificationMessage
,内部封装了几种简单的类型操作,且扩展性不强,无法完成现有的操作。
解决方案:
使用自定义消息重新来构建群组通知消息。
参考 sealtlak 中的 RCDGroupNotificationMessage
,也是单独对群组操作内容,重新进行了封装处理
/*!
群组通知消息
*/
@interface RCDGroupNotificationMessage : RCMessageContent
//操作名
@property (nonatomic, copy) NSString *operation;
//操作人
@property (nonatomic, copy) NSString *operatorUserId;
//操作对象
@property (nonatomic, strong) NSArray<NSString *> *targetUserIds;
//内容
@property (nonatomic, copy) NSString *message;
//获取摘要
- (NSString *)getDigest:(NSString *)groupId;
@end
这个类预定义了下面几种操作类型消息,具体内容可参考名字定义
extern NSString *const RCDGroupCreate;
extern NSString *const RCDGroupMemberAdd;
extern NSString *const RCDGroupMemberQuit;
extern NSString *const RCDGroupMemberKicked;
extern NSString *const RCDGroupRename;
extern NSString *const RCDGroupBulletin;
extern NSString *const RCDGroupOwnerTransfer;
extern NSString *const RCDGroupDismiss;
extern NSString *const RCDGroupMemberJoin;
extern NSString *const RCDGroupMemberManagerSet;
extern NSString *const RCDGroupMemberManagerRemove;
extern NSString *const RCDGroupMemberProtectionOpen;
extern NSString *const RCDGroupMemberProtectionClose;
.m 的实现还是按照自定义消息的实现进行处理。唯一有区别的是在获取摘要的方法,在这个方法中对消息内容进行了处理,根据操作名的不同,来对显示的内容进行各种适配。此处根据根据自己的业务进行修改。
- (NSString *)getDigest:(NSString *)groupId {
NSString *content;
//获取用户信息
NSString *operationName = [self getDisplayNames:@[ self.operatorUserId?self.operatorUserId:@""] groupId:groupId];
NSString *targetNames = [self getDisplayNames:self.targetUserIds groupId:groupId];
//是否当前用户操作
BOOL isMeOperate = NO;
if ([self.operatorUserId isEqualToString:[RCIMClient sharedRCIMClient].currentUserInfo.userId]) {
isMeOperate = YES;
}
//判断操作类型
if ([self.operation isEqualToString:RCDGroupCreate]) {
content =
[NSString stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveCreated" : @"GroupCreated",
@"RongCloudKit", nil),
operationName];
} else if ([self.operation isEqualToString:RCDGroupMemberAdd]) {
if (self.targetUserIds.count == 1 && [self.targetUserIds containsObject:self.operatorUserId]) {
content = [NSString
stringWithFormat:NSLocalizedStringFromTable(@"GroupJoin", @"RongCloudKit", nil), operationName];
} else {
content = [NSString
stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveInvited" : @"GroupInvited",
@"RongCloudKit", nil),
operationName, targetNames];
}
} else if ([self.operation isEqualToString:RCDGroupMemberJoin]) {
content =
[NSString stringWithFormat:NSLocalizedStringFromTable(@"GroupJoin", @"RongCloudKit", nil), operationName];
} else if ([self.operation isEqualToString:RCDGroupMemberQuit]) {
content = [NSString stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveQuit" : @"GroupQuit",
@"RongCloudKit", nil),
operationName];
} else if ([self.operation isEqualToString:RCDGroupMemberKicked]) {
content =
[NSString stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveRemoved" : @"GroupRemoved",
@"RongCloudKit", nil),
operationName, targetNames];
} else if ([self.operation isEqualToString:RCDGroupRename]) {
content = [NSString stringWithFormat:NSLocalizedStringFromTable(@"GroupChanged", @"RongCloudKit", nil),
operationName, self.targetGroupName];
} else if ([self.operation isEqualToString:RCDGroupDismiss]) {
content =
[NSString stringWithFormat:NSLocalizedStringFromTable(isMeOperate ? @"GroupHaveDismiss" : @"GroupDismiss",
@"RongCloudKit", nil),
operationName];
} else if ([self.operation isEqualToString:RCDGroupOwnerTransfer]) {
content = [NSString stringWithFormat:RCDLocalizedString(@"GroupHasNewOwner"), targetNames];
} else if ([self.operation isEqualToString:RCDGroupMemberManagerSet]) {
content = [NSString stringWithFormat:RCDLocalizedString(@"GroupSetManagerMessage"), targetNames];
} else if ([self.operation isEqualToString:RCDGroupMemberProtectionOpen]) {
content = RCDLocalizedString(@"openMemberProtection");
} else if ([self.operation isEqualToString:RCDGroupMemberProtectionClose]) {
content = [NSString stringWithFormat:RCDLocalizedString(@"closeMemberProtection"), operationName];
} else {
content = NSLocalizedStringFromTable(@"unknown_message_cell_tip", @"RongCloudKit", nil);
}
return content;
}
此外,还有一个获取名称的方法,用来维护用户信息。
- (NSString *)getDisplayNames:(NSArray<NSString *> *)userIds groupId:(NSString *)groupId
关于融云 SDK 在使用 p8 证书的坎坷~
IM即时通讯 • 木土走召 发表了文章 • 0 个评论 • 208 次浏览 • 2021-01-11 15:14
新上的项目使用了融云的 IM SDK,但在项目集成 APNs 推送的时候,尝鲜使用了一下开发者后台的 p8 证书,此文记录使用 p8 的辛酸史~
P8 简介
官网给出了这种更 "快" 的推送通道: Establishing a Token-Based Connection to APNs,并且这个生成的这个 key 可以适用于当前账户的所有 APP,为开发人员省了不少力气。福音啊~
想想那一堆证书...... 脑阔痛!
辛酸史
起因是这样的,在融云开发者后台上传了 p8 之后,发现 debug 环境,一直无法收到推送,在经过和融云提供的推送文档进行严格的比对之后,发现没毛病啊~
最后终于在融云开发人员的帮助下找到了问题~,融云后台目前阶段只支持生产环境~ OMG,我打你信不~
区别
p8 是可以同时支持生产和测试环境的,那么为什么融云收不到呢~
让我们大胆猜测一下:
之前基于证书进行校验的时候,一套证书是基于开发者后台一个 AppKey 绑定的,那么我用了哪个 AppKey,后端就基于 AppKey 解析对应的证书,这样就可以发送到对应的 push 环境去了,那么问题来了?使用了 p8 之后,他怎么区分呢?
我也不知道~ 哈哈哈,但我猜测应该是没有解析都去走了生产环境,因为提示我环境不匹配~
苹果 APNs 服务
Development server: api.sandbox.push.apple.com:443
Production server: api.push.apple.com:443
融云 Flutter IM SDK 解析
IM即时通讯 • 木土走召 发表了文章 • 0 个评论 • 226 次浏览 • 2021-01-11 15:14
最近准备使用融云的 Flutter SDK,所以顺便记录一下。
融云 Flutter IM SDK 地址:传送门
融云的 Flutter SDK 是基于 融云 IMLib 层做的封装,封装了 IMLib 的部分接口提供给 Flutter 开发者使用。此文章只介绍了 Flutter 层做的一些操作。
目录结构
整体 SDK 的结构规规矩矩,核心内容参考红色箭头即可。
SDK 层包含 三个目录:android:此目录包含了和原生 SDK 交互的所有 Java 文件
ios:此目录包含了和原生 SDK 交互的所有 oc 文件
lib: 此目录为使用 dart 编写的 Flutter SDK 文件
其他目录:doc:主要是融云开发者提供的一些文档相关
example:是融云开发者基于此 SDK 提供的一个简单示例,整体较为简陋,且有细微 bug,仅供参考
FunctionList.md
是融云开发者提供的一个功能清单,
大体如下:
# RongCloud IM Flutter SDK 功能清单
## 连接
初始化
连接
断开连接
连接状态兼容
## 配置
设置服务器地址( im 服务;文件服务)
## 会话
获取会话列表,支持全量获取,分页获取
获取单个会话
删除指定会话
## 消息
当前仅支持 文本消息,语音消息,图片消息,小视频消息
收发消息(可以携带 pushContent)
自定义消息
获取批量本地历史消息
获取单条本地历史消息
获取批量远端历史消息
插入消息
删除批量本地消息
获取未读数
清除指定会话未读数
## 免打扰
设置会话免打扰
获取会话免打扰
## 会话置顶
设置会话置顶
备注:获取会话是可以获取到会话置顶状态
## 黑名单
加入黑名单
移除黑名单
获取黑名单列表
检查特定用户的黑名单状态
## 聊天室
加入聊天室
退出聊天室
获取聊天室信息
都是一些接口层的操作。
剩下的文件基本可以忽略。
解析
我们开始从 lib
目录开始分析
这两个文件是核心文件,我们所有的调用接口都在这里。
rong_im_client.dart
是最新版本的接口类,我们只关心这个即可。
rong_im_plugin.dart
是旧版本的接口类,已经废弃。
common_define.dart
是定义了 SDK 内使用的所有枚举和状态码。
method_key.dart
是定义了 Flutter SDK 和原生层进行交互时标识的唯一的常量字符串。
然后就是剩下的三个文件目录:
info
: 其实就是对象 model 类
message:
这个是 Flutter SDK提供的所有内置的消息类型,包括聊天室KV消息、合并消息、文件消息、GIF消息、图片消息、位置消息、撤回消息、引用消息、图文消息、视频消息、文本消息、语音消息。
其中有一个比较特殊的 dart 类就是 message_content.dart
, 这个类是所有消息的基类。
每个消息都需要继承此类,并复写里面的方法进行编解码。
util
: 这个目录就是一个工具目录。
message_factory.dart
主要是进行消息封装,字典转模型,模型转字典,根本原因我猜就是 Flutter 和 原生仅有的交互类型限制。
type_util.dart
:略
以上就是 SDK 在 Flutter 层做的所有的操作,内容整体不多,而且所有代码都是开源的,看看基本上都了解。
与原生层的交互
整体都是通过 invokeMethod
与原生进行通信的,后面的key 就是之前说的常量字符串,用来保证唯一性。
而在 iOS
和 Android
都提供了对应的定义。
并通过触发 iOS 和 Android 层对应的方法来进行处理。
原生层
Android:
整体核心的处理都在 RCIMFlutterWrapper.java
这个类处理了 dart 代码传递过来的数据,并与融云 IMLib 的 SDK 进行了处理。
iOS:
同样,iOS 的核心代码也都在 RCIMFlutterWrapper.m
这个类处理。具体内容大家可以自己看一下。
到此整个内容我们也就大体明白了。
整体看来其实就是 flutter 中 rong_im_client.dart
和 原生的两个 Wrapper
类做交互,其他的都是助攻。
整体看来不难,搞起~
融云文档:传送门
干货分享——使用融云通讯能力库 IMLib 实现单群聊的阅读回执
IM即时通讯 • 王叫兽 发表了文章 • 0 个评论 • 219 次浏览 • 2021-01-11 15:14
今天的干货分享是关于“阅读回执”功能,这是一个很普遍的功能,但是针对使用融云的 SDK 去实现,还是有些坑在等着我们的,下面就开始分(bì)享(kēng)喽~
分享之前先做一些准备工作,先找到我们需要调用的接口文档
根据不同的会话类型以及消息的发送方和接收方,要分别处理
单聊
接收方 :在阅读消息后,调用 RCIMClient 类的发送阅读回执接口,参数如下:
conversationType 单聊会话类型
targetId 消息的会话 ID
time 会话最后一条消息的发送时间(sentTime)
/*!
发送某个会话中消息阅读的回执
@param conversationType 会话类型
@param targetId 会话 ID
@param timestamp 该会话中已阅读的最后一条消息的发送时间戳
@param successBlock 发送成功的回调
@param errorBlock 发送失败的回调[nErrorCode: 失败的错误码]
@discussion 此接口只支持单聊, 如果使用 IMLib 可以注册监听
RCLibDispatchReadReceiptNotification 通知,使用 IMKit 直接设置RCIM.h
中的 enabledReadReceiptConversationTypeList。
@warning 目前仅支持单聊。
@remarks 高级功能
*/
- (void)sendReadReceiptMessage:(RCConversationType)conversationType
targetId:(NSString *)targetId
time:(long long)timestamp
success:(void (^)(void))successBlock
error:(void (^)(RCErrorCode nErrorCode))errorBlock;
发送方:监听下面这个通知,在接收后修改消息的展示
/*!
@const 收到已读回执的 Notification
@discussion 收到消息已读回执之后,IMLib 会分发此通知。
Notification 的 object 为 nil,userInfo 为 NSDictionary 对象,
其中 key 值分别为 @"cType"、@"tId"、@"messageTime",
对应的 value 为会话类型的 NSNumber 对象 、会话的 targetId 、已阅读的最后一条消息的 sendTime。
如:
NSNumber *ctype = [notification.userInfo objectForKey:@"cType"];
NSNumber *time = [notification.userInfo objectForKey:@"messageTime"];
NSString *targetId = [notification.userInfo objectForKey:@"tId"];
NSString *fromUserId = [notification.userInfo objectForKey:@"fId"];
收到这个消息之后可以更新这个会话中 messageTime 以前的消息 UI 为已读(底层数据库消息状态已经改为已读)。
@remarks 事件监听
*/
FOUNDATION_EXPORT NSString *const RCLibDispatchReadReceiptNotification;
群聊
发送方:
在发送消息 A 后,需要针对该消息发送回执请求,message 传之前发的消息 A
/*!
请求消息阅读回执
@param message 要求阅读回执的消息
@param successBlock 请求成功的回调
@param errorBlock 请求失败的回调[nErrorCode: 失败的错误码]
@discussion 通过此接口,可以要求阅读了这条消息的用户发送阅读回执。
@remarks 高级功能
*/
- (void)sendReadReceiptRequest:(RCMessage *)message
success:(void (^)(void))successBlock
error:(void (^)(RCErrorCode nErrorCode))errorBlock;
设置下面代理函数,在接收到发送方发来的阅读回执响应后,修改消息的展示
/*!
IMlib消息接收的监听器
@discussion
设置IMLib的消息接收监听器请参考RCIMClient的setReceiveMessageDelegate:object:方法。
@warning 如果您使用IMlib,可以设置并实现此Delegate监听消息接收;
如果您使用IMKit,请使用RCIM中的RCIMReceiveMessageDelegate监听消息接收,而不要使用此监听器,否则会导致IMKit中无法自动更新UI!
*/
@protocol RCIMClientReceiveMessageDelegate <NSObject>
/*!
消息已读回执响应(收到阅读回执响应,可以按照 messageUId 更新消息的阅读数)
@param messageUId 请求已读回执的消息ID
@param conversationType conversationType
@param targetId targetId
@param userIdList 已读userId列表
*/
- (void)onMessageReceiptResponse:(RCConversationType)conversationType
targetId:(NSString *)targetId
messageUId:(NSString *)messageUId
readerList:(NSMutableDictionary *)userIdList;
接收方:
设置下面代理函数,在接收到消息 A 后,还会接收到针对消息 A 的阅读回执请求
/*!
IMlib消息接收的监听器
@discussion
设置IMLib的消息接收监听器请参考RCIMClient的setReceiveMessageDelegate:object:方法。
@warning 如果您使用IMlib,可以设置并实现此Delegate监听消息接收;
如果您使用IMKit,请使用RCIM中的RCIMReceiveMessageDelegate监听消息接收,而不要使用此监听器,否则会导致IMKit中无法自动更新UI!
*/
@protocol RCIMClientReceiveMessageDelegate <NSObject>
/*!
请求消息已读回执(收到需要阅读时发送回执的请求,收到此请求后在会话页面已经展示该 messageUId 对应的消息或者调用
getHistoryMessages 获取消息的时候,包含此 messageUId 的消息,需要调用 sendMessageReadReceiptResponse
接口发送消息阅读回执)
@param messageUId 请求已读回执的消息ID
@param conversationType conversationType
@param targetId targetId
*/
- (void)onMessageReceiptRequest:(RCConversationType)conversationType
targetId:(NSString *)targetId
messageUId:(NSString *)messageUId;
在代理方法中,调用下面接口发送阅读回执响应给发送方
/*!
发送阅读回执
@param conversationType 会话类型
@param targetId 会话 ID
@param messageList 已经阅读了的消息列表
@param successBlock 发送成功的回调
@param errorBlock 发送失败的回调[nErrorCode: 失败的错误码]
@discussion 当用户阅读了需要阅读回执的消息,可以通过此接口发送阅读回执,消息的发送方即可直接知道那些人已经阅读。
@remarks 高级功能
*/
- (void)sendReadReceiptResponse:(RCConversationType)conversationType
targetId:(NSString *)targetId
messageList:(NSArray<RCMessage *> *)messageList
success:(void (^)(void))successBlock
error:(void (^)(RCErrorCode nErrorCode))errorBlock;
总结
阅读回执需要区分会话类型处理,且单聊的阅读回执是针对会话的,群聊的阅读回执是针对某一条消息的:
单聊:接收方阅读某个会话的消息后,发送阅读回执 ——发送方接到阅读回执,更新 UI
群聊:发送方发送消息 A, 针对该消息,发送阅读回执请求 —— 接收方实现监听代理,接收到消息 A 的阅读回执请求 —— 接收方发送阅读回执响应 —— 发送方收到阅读回执响应,更新 UI
如何设置融云用户信息
IM即时通讯 • dht1212 发表了文章 • 0 个评论 • 222 次浏览 • 2021-01-08 11:35
最近在使用融云,由于第一次使用,遇到了一个小坑,在这里记录一下,希望能帮助到后续开发者
问题是使用了融云的 IMKit 组件,也就是自带 UI 的,对于快速试错的产品来说,工期必须短,所以使用 IMKit 是非常方便的,省去了很大部分时间去搞界面。但是使用过程中发现,没有用户的头像和昵称。后来经过阅读文档发现,需要设置“用户信息提供者”代理方法。SDK 在需要显示头像和昵称的时候,会通过这个代理找开发者索取用户信息,开发者只要遵循代理,且实现代理方法,返回用户信息即可。
上代码:
1.遵循代理
@interface AppDelegate () <RCIMUserInfoDataSource>
@end
2.设置代理
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//必须先初始化
[[RCIM sharedRCIM] initWithAppKey:"开发者自己的 appkey"];
[[RCIM sharedRCIM] connectWithToken:"当前用户的 token" dbOpened:^(RCDBErrorCode code) {
} success:^(NSString *userId) {
} error:^(RCConnectErrorCode errorCode) {
}];
//设置当前用户信息
RCUserInfo *currentUser = [[RCUserInfo alloc] initWithUserId:@"tiezhu" name:@"铁柱" portrait:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1573646812313&di=116350f184eda99d91393304fa83a6ea&imgtype=0&src=http%3A%2F%2Fimg.jinse.com%2F712431_image3.png"];
[RCIM sharedRCIM].currentUserInfo = currentUser;
//设置代理
[RCIM sharedRCIM].userInfoDataSource = self;
}
3.实现代理方法
- (void)getUserInfoWithUserId:(NSString *)userId completion:(void (^)(RCUserInfo *userInfo))completion {
//这里最好是从开发者自己服务器获取用户信息,然后返回。此处仅为示例
RCUserInfo *user = nil;
if ([userId isEqualToString:@"tiezhu"]) {
user = [[RCUserInfo alloc] initWithUserId:@"tiezhu" name:@"铁柱" portrait:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1570172426&di=01d14daa81f320235376d9c4dede0493&imgtype=jpg&er=1&src=http%3A%2F%2Fgss0.baidu.com%2F-vo3dSag_xI4khGko9WTAnF6hhy%2Fzhidao%2Fpic%2Fitem%2Fd788d43f8794a4c240e9466f0ef41bd5ac6e39af.jpg"];
}
if (completion) {
completion(user);
}
}
到此就搞定了兄嘚,值一杯秋天的奶茶