在项目APP中接入IM的功能,有环信和融云的两种选择,在纠结以后,选择了融云进行开发。
首先可以参照官网:https://www.rongcloud.cn/docs/ios.html#prepare来进行基本的融云包的导入和集成到工程中。
通过在控制台中API的调用https://developer.rongcloud.cn/apitool/A0dLuQBjI8MJKehwuu0=来模拟接口调用的过程。
集成融云,就是能用好他所提供的API,就能完成大部分的工作,用好IMKit和IMLib。IMKit主要就是页面,可以在它的基础上进行我们自己页面的自定义,IMLib就是通讯的API,通过使用它暴露的方法来实现及时通讯,单聊,群聊,以及自定义消息的发送。
导入融云,连接融云
在APPDelegate中注册自定义的消息类型和做消息推送相关的内容。
最好是在登录APP的时候,让服务端返回userId和rongcloudToken,获取到Token以后,登录融云的服务器。可以写一个单例的工具类,来处理融云的登录,断开连接,和<RCIMUserInfoDataSource, RCIMReceiveMessageDelegate,RCIMConnectionStatusDelegate>用户数据源的一些方法的实现。
用户信息和群组信息的数据源
因为融云已经做好了基本的聊天通讯的功能,我们要做的就是处理用户昵称,头像和群组的一些信息的处理,设置
1 | //设置用户信息源 |
用户信息需要通过实现RCIMUserInfoDataSource的方法
1 | - (void)getUserInfoWithUserId:(NSString *)userId completion:(void (^)(RCUserInfo *userInfo))completion; |
我们需要在这个方法里面调用自己的接口来获取用户的相关信息,就是头像和昵称,然后把获取到的数据放到RCUserInfo对象的userId,name,和portraitUri中,也把这个数据存到FMDB数据库中。这样在聊天列表展示聊天cell的时候,可以通过RCUserInfo *user = [[RCIM sharedRCIM] getUserInfoCache:model.targetId];
这个方法,如果User存在的话,直接赋值,如果不存在的话,再次调用getUserInfoWithUserId这个来获取用户的信息,获取到以后刷新用户信息,并存到数据库中。
1 | [[RCIM sharedRCIM] refreshUserInfoCache:user withUserId:user.userId]; |
群组信息实现RCIMGroupInfoDataSource方法
1 | - (void)getGroupInfoWithGroupId:(NSString *)groupId completion:(void (^)(RCGroup *groupInfo))completion; |
融云自带的群组的信息类是RCGroup,只包含groupId,groupName和portraitUri,我们如果需要更多的信息存储,只需要继承自RCGroup,
如果我们需要在群组名称中携带很多信息的话,只需要把相关的信息放到一个字典中然后后转化成json字符串赋值给groupName
群组成员实现
我们可以写个单例来实现这三个方法。在方法实现中通过调用自己的接口获取到相关的数据,然后调用融云的接口refreshGroupInfoCache存储起来。
消息列表
消息列表需要继承自RCConversationListViewController,只要继承了这个,然后通过其暴露的属性和方法来设置基本列表的样式,当有消息的时候就能展示出来融云自带的聊天cell。如果我们要自定义的消息列表的cell。主要实现的方法:
重写方法:插入自定义会话model
1 | -(NSMutableArray *)willReloadTableData:(NSMutableArray *)dataSource{ |
注:在该方法内筛选数据源dataSource中具体的会话类型及消息的model,将model 类型必须修改为 model.conversationModelType=RC_CONVERSATION_MODEL_TYPE_CUSTOMIZATION
如果需要插入类似微博消息列表中的点赞、评论,关注和系统消息的自定义cell,需要在这个方法中自定义Model,并且拼接到DataSource中。
代码如下:
1 | if (_isShowServiceSystem == NO) { |
重写返回 cell 高度的方法
1 | - (CGFloat)rcConversationListTableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; |
如果需要显示不同高度测自定义的cell,只需要在这个方法中,根据判断的类型返回高度值。
自定义会话Cell显示时的回调
1 | -(RCConversationBaseCell *)rcConversationListTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath |
或者是即将显示cell的时候把用户信息和群组信息放到cell里面
1 | - (void)willDisplayConversationTableCell:(RCConversationBaseCell *)cell atIndexPath:(NSIndexPath *)indexPath |
如果使用的都是自定义的cell的话,要设置在model.conversationModelType == RC_CONVERSATION_MODEL_TYPE_CUSTOMIZATION)先区分数据模型是自定义的,再区分是单聊还是群聊conversationType。对于每一种会话类型,自定义我们需要的cell的样式,然后通过取出对应index的Model。
RCConversationModel *model = self.conversationListDataSource[indexPath.row];
来把Model中的头像、昵称、最近消息、时间、未读数、一些信息放到cell对应的位置。
点击事件 –点击cell的回调
1 | - (void)onSelectedTableRow:(RCConversationModelType)conversationModelType |
在点击事件中,根据你自定义cell类型的不同,跳转到不同的页面,如果是单聊,群聊跳转到聊天会话页面,如果是系统消息:评论回复、点赞、关注、系统消息,跳转到自己写的页面,融云提供了这种系统消息的通知的接口,我们可以通过它的接口就可以实现通知的推送,不需要接入第三方极光等来进行推送。只需要把这些通知调用发送接口,作为消息发送给用户。
例如:评论和回复页面:继承自RCConversationViewController,隐藏下面的输入栏self.chatSessionInputBarControl.hidden = YES;
注册自定义的消息和数据模型:[self registerClass:[JRServiceCommentCell class] forMessageClass:[JRServiceCommentModel class]];
通过接收到通知以后,在会话页面插入一条消息并展示:
1 | //在会话页面中插入一条消息并展示 |
评论和回复的cell继承自RCMessageBaseCell。可以自己写这个cell的样式。再说一下这个cell的数据源,也是自己自定义的CommentModel继承自RCMessageContent,就和自定义消息类型一样的,需要把消息内容编码成JSON,然后将JSON解码成消息内容,定义消息的类型名(与融云消息不要名字一样),类似我们平时用网络请求后的JSON数据解析,把NSData的data消息解码成字典,NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
然后把字典中的dictionary[@”content”]取出来,判断是字典还是字符串类型,如果是字典的话就用YYModel解析到一个Model中来使用。如果是字符串的话就用方法把JSON字符串转化为字典,
消息会话
消息会话展示
- 单聊不显示对方名称:RCMessageModel的model.isDisplayNickname来设置
2.群聊显示身份的名称:获取到群成员数组以后,遍历数组,把身份和成员的昵称存到RCUserInfo的name中,并保存到SDK中,再把 [self.conversationMessageCollectionView reloadData];
重要的方法:
1 | - (void)sendMessage:(RCMessageContent *)messageContent pushContent:(NSString *)pushContent; |
在发送自定义消息和通知的时候使用,当我在发送一个邀请好友进入聊天室的自定义cell的时候,使用
1 | JRInviteMessage *inviteMsg = [JRInviteMessage messageWithGroupId:self.groupId |
对于文字,图片和自定义的消息的cell都可以重写,文字继承自RCTextMessageCell,语音继承自RCVoiceMessageCell,图片继承自RCImageMessageCell,其他自定义邀请好友进入群聊的cell继承自RCMessageCell或者是它的父类RCMessageBaseCell,在方法中实现- (void)setDataModel:(RCMessageModel *)model
来设置自己想要的属性的样式.
进入会话页面要从服务器获取用户或是群组的信息并更新本地数据库
这样做的目的就是:用户换了头像或者是昵称以后,在会话页面可以更新用户的数据,
自定义Cell的点击
1 | - (void)didTapMessageCell:(RCMessageModel *)model |
推送
就像上面的会话列表里面的评论和回复一样,只要在这个的地方,调用自己服务端在融云基础上开发的接口,就能把Model传过去,把需要发送的数据放在一个字典里面,然后jsonStringWithObject把字典转换成JSON字符串
遇到的问题
1.修改聊天气泡以及一些图标
直接把要替换的图片替换RongCloud.bundle文件中的图片即可。
2.当融云SDK和BlocksKit被引入到同一工程,通过融云的聊天UI界面去选择照片、拍摄照片并发送时,无法正常选择和发送。
问题的本质:
UIImagePickerController代理中的方法冲突了,导致融云SDK中选择并发送照片的功能失效。
解决方法:
BlocksKit是开源方法,直接编辑UIImagePickerController+BlocksKit.m文件,注释红框部分,问题便可解决。
3.//点击消息发送失败红点的回调
1 | - (void)didTapmessageFailedStatusViewForResend:(RCMessageModel *)model{ |