集成刚说完,这里接直接说使用吧缓存
1、初始化服务器
导入头文件 微信
#import <RongIMKit/RongIMKit.h> #import <RongIMLib/RongIMLib.h>
初始化网络
//AppKey要对应,必定注意开发环境和生产环境对应的AppKey [[RCIM sharedRCIM] initWithAppKey:RONGCLOUDAPPKEY];
链接服务器:融云提供的connectWithToken:success:error:tokenIncorrect:
方法,须要传入融云的token值,这个token值是在登陆本身服务器时,后台所传过来的,同时传过来的数据中要保存融云的userId,头像和昵称,这些在会话列表和聊天界面都要用到。app
//若是存在token,直接进行链接,不存在就访问本身的服务器,拿到token以后再次进行链接 NSString *ryToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"rytoken"]; NSLog(@"进入首页ryToken:%@",ryToken); if(ryToken){ [[RCIM sharedRCIM] connectWithToken: ryToken success:^(NSString *userId) { NSLog(@" 微信 登录登录成功。当前登陆的用户ID:%@", userId); } error:^(RCConnectErrorCode status) { NSLog(@"微信 登录登录的错误码为:%lu", status); } tokenIncorrect:^{ //token过时或者不正确。 //若是设置了token有效期而且token过时,请从新请求您的服务器获取新的token //若是没有设置token有效期却提示token错误,请检查您客户端和服务器的appkey是否匹配,还有检查您获取token的流程。 NSLog(@"微信 登录token错误"); }]; }else{ //访问本身服务器,获取融云token值 [self getRongCloudToken]; }
还有一些其余的添加:curl
//是否在发送的全部消息中携带当前登陆的用户信息 [RCIM sharedRCIM].enableMessageAttachUserInfo = YES; RCUserInfo *_currentUserInfo = [[RCUserInfo alloc] initWithUserId:[[NSUserDefaults standardUserDefaults] objectForKey:@"ryuid"] name:[[NSUserDefaults standardUserDefaults] objectForKey:@"nickname"] portrait:[[NSUserDefaults standardUserDefaults] objectForKey:@"headimgurl"]]; [RCIM sharedRCIM].currentUserInfo = _currentUserInfo; //设置日志级别 输出错误、警告和通常的日志 [RCIMClient sharedRCIMClient].logLevel = RC_Log_Level_Info; //开启用户信息和群组信息的持久化 [RCIM sharedRCIM].enablePersistentUserInfoCache = YES; //设置用户信息源和群组信息源(这个须要本身实现,写成单例就能够,下面补充) [RCIM sharedRCIM].userInfoDataSource = HYNRCDData; [RCIM sharedRCIM].groupInfoDataSource = HYNRCDData; //是否在发送的全部消息中携带当前登陆的用户信息 [RCIM sharedRCIM].enableMessageAttachUserInfo = YES; //开启消息撤回功能 [RCIM sharedRCIM].enableMessageRecall = YES; // 设置头像为圆形 [RCIM sharedRCIM].globalMessageAvatarStyle = RC_USER_AVATAR_CYCLE; [RCIM sharedRCIM].globalConversationAvatarStyle = RC_USER_AVATAR_CYCLE; // 设置优先使用WebView打开URL [RCIM sharedRCIM].embeddedWebViewPreferred = YES; //开启多端未读状态同步 [RCIM sharedRCIM].enableSyncReadStatus = YES; //设置显示未注册的消息 //如:新版本增长了某种自定义消息,可是老版本不能识别,开发者能够在旧版本中预先自定义这种未识别的消息的显示 [RCIM sharedRCIM].showUnkownMessage = YES; [RCIM sharedRCIM].showUnkownMessageNotificaiton = YES;
设置本身的数据源信息:HYNRCDataSource:async
//HYNRCDataSource.h文件 #import <Foundation/Foundation.h> #import <RongIMKit/RongIMKit.h> #define HYNRCDData [HYNRCDataSource shareInstance] //遵照协议 @interface HYNRCDataSource : NSObject<RCIMUserInfoDataSource, RCIMGroupInfoDataSource> + (HYNRCDataSource *)shareInstance; @end //HYNRCDataSource.m文件 #import "HYNRCDataSource.h" static HYNRCDataSource *_dataSource = nil; @implementation HYNRCDataSource +(HYNRCDataSource *)shareInstance { static dispatch_once_t once; dispatch_once(&once, ^{ _dataSource = [[[self class] alloc] init]; }); return _dataSource; } //获取群组信息 #pragma mark - RCIMUserInfoDataSource - (void)getGroupInfoWithGroupId:(NSString *)groupId completion:(void (^)(RCGroup *))completion { if ([groupId length] == 0) return; //从本身的服务器中获取群的基本信息,而后传到融云的SDK中,在会话列表页面就能够显示圈子的图片和圈子的名字 NSString *url = [NSString stringWithFormat:@"%@%@",NEW_BASEURL,GETGROUPINFO]; NSDictionary *param = @{@"ry_gid":groupId}; [[HTTPRequest sharedInstance] GET:url parameters:param succeed:^(id responseObject) { NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil]; if([dic[@"code"] isEqualToString:@"200"]){ RCGroup *info = [[RCGroup alloc] init]; info.groupId = groupId; info.groupName = dic[@"groupinfo"][@"gname"]; info.portraitUri = dic[@"groupinfo"][@"picurl"]; return completion(info); } } failure:^(NSError *error) { NSLog(@"获取圈聊信息 失败error:%@",error); }]; } // 获取用户信息 #pragma mark - RCIMUserInfoDataSource - (void)getUserInfoWithUserId:(NSString *)userId completion:(void (^)(RCUserInfo *))completion { // NSLog(@"getUserInfoWithUserId ----- %@", userId); RCUserInfo *user = [RCUserInfo new]; if (userId == nil || [userId length] == 0) { user.userId = userId; user.portraitUri = @""; user.name = @""; completion(user); return; } //从本身的服务器中获取单聊用户的基本信息,而后传到融云的SDK中,在会话列表页面就能够显示单聊的的头像和名字 if([userId isEqualToString: [[NSUserDefaults standardUserDefaults] objectForKey:@"ryuid"]]){ //若是当前用户信息是本身的信息,就传入本身的基本信息 RCUserInfo *info = [[RCUserInfo alloc] initWithUserId:userId name:[[NSUserDefaults standardUserDefaults] objectForKey:@"nickname"] portrait:[[NSUserDefaults standardUserDefaults] objectForKey:@"headimgurl"]]; NSLog(@"--------------RCUserInfo-----info:%@",info); //更新SDK中的用户信息缓存(可保证用户在更换头像时,App的头像能更换) [[RCIM sharedRCIM] refreshUserInfoCache:user withUserId:user.userId]; return completion(info); }else{ //若是当前用户不是本身,就访问本身服务器获取用户的基本信息,传入SDK NSString *url = [NSString stringWithFormat:@"%@%@",NEW_BASEURL,GETUSERINFO]; NSDictionary *param = @{@"user_ryid":userId}; [[HTTPRequest sharedInstance] GET:url parameters:param succeed:^(id responseObject) { NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil]; if([dic[@"code"] isEqualToString:@"200"]){ RCUserInfo *user = [[RCUserInfo alloc]init]; user.userId = userId; user.name = dic[@"userinfo"][@"nickname"]; user.portraitUri = dic[@"userinfo"][@"headimgurl"]; return completion(user); } } failure:^(NSError *error) { NSLog(@"获取用户信息 失败error:%@",error); }]; } } @end
2、推送ide
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) { //注册推送, iOS 8 UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound |UIUserNotificationTypeAlert) categories:nil]; [application registerUserNotificationSettings:settings]; } //融云即时通信 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMessageNotification:) name:RCKitDispatchMessageNotification object:nil]; } - (void)didReceiveMessageNotification:(NSNotification *)notification { NSNumber *left = [notification.userInfo objectForKey:@"left"]; if ([RCIMClient sharedRCIMClient].sdkRunningMode == RCSDKRunningMode_Background && 0 == left.integerValue) { int unreadMsgCount = [[RCIMClient sharedRCIMClient] getUnreadCount:@[ @(ConversationType_PRIVATE),@(ConversationType_GROUP)]]; dispatch_async(dispatch_get_main_queue(), ^{ [UIApplication sharedApplication].applicationIconBadgeNumber = unreadMsgCount; }); } } //注册用户通知设置 - (void)application:(UIApplication *)application didRegisterUserNotificationSettings: (UIUserNotificationSettings *)notificationSettings { // register to receive notifications [application registerForRemoteNotifications]; } //将获得的deviceToken传给SDK - (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{ //融云推送 NSString *token = [[[[deviceToken description] stringByReplacingOccurrencesOfString:@"<" withString:@""] stringByReplacingOccurrencesOfString:@">" withString:@""] stringByReplacingOccurrencesOfString:@" " withString:@""]; [[RCIMClient sharedRCIMClient] setDeviceToken:token]; } //注册deviceToken失败 - (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error{ NSLog(@"deviceToken-----error -- %@",error); } // APP进入后台 - (void)applicationDidEnterBackground:(UIApplication*)application { // 为消息分享保存会话信息 [self saveConversationInfoForMessageShare]; } // APP将要从后台返回 - (void)applicationWillEnterForeground:(UIApplication*)application { if ([[RCIMClient sharedRCIMClient] getConnectionStatus] == ConnectionStatus_Connected) { // 插入分享消息 [self insertSharedMessageIfNeed]; } } //为消息分享保存会话信息 - (void)saveConversationInfoForMessageShare { NSArray *conversationList = [[RCIMClient sharedRCIMClient] getConversationList:@[@(ConversationType_PRIVATE), @(ConversationType_GROUP)]]; NSMutableArray *conversationInfoList = [[NSMutableArray alloc] init]; if (conversationList.count > 0) { for (RCConversation *conversation in conversationList) { NSMutableDictionary *conversationInfo = [NSMutableDictionary dictionary]; [conversationInfo setValue:conversation.targetId forKey:@"targetId"]; [conversationInfo setValue:@(conversation.conversationType) forKey:@"conversationType"]; if (conversation.conversationType == ConversationType_PRIVATE) { RCUserInfo * user = [[RCIM sharedRCIM] getUserInfoCache:conversation.targetId]; [conversationInfo setValue:user.name forKey:@"name"]; [conversationInfo setValue:user.portraitUri forKey:@"portraitUri"]; }else if (conversation.conversationType == ConversationType_GROUP){ RCGroup *group = [[RCIM sharedRCIM] getGroupInfoCache:conversation.targetId]; [conversationInfo setValue:group.groupName forKey:@"name"]; [conversationInfo setValue:group.portraitUri forKey:@"portraitUri"]; } [conversationInfoList addObject:conversationInfo]; } } NSURL *sharedURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.cn.rongcloud.im.share"]; NSURL *fileURL = [sharedURL URLByAppendingPathComponent:@"rongcloudShare.plist"]; [conversationInfoList writeToURL:fileURL atomically:YES]; NSUserDefaults *shareUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.cn.rongcloud.im.share"]; [shareUserDefaults setValue:[RCIM sharedRCIM].currentUserInfo.userId forKey:@"currentUserId"]; [shareUserDefaults setValue:[[NSUserDefaults standardUserDefaults] objectForKey:@"UserCookies"] forKey:@"Cookie"]; [shareUserDefaults synchronize]; } //插入分享消息 - (void)insertSharedMessageIfNeed { NSUserDefaults *shareUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.cn.rongcloud.im.share"]; NSArray *sharedMessages = [shareUserDefaults valueForKey:@"sharedMessages"]; if (sharedMessages.count > 0) { for (NSDictionary *sharedInfo in sharedMessages) { RCRichContentMessage *richMsg = [[RCRichContentMessage alloc]init]; richMsg.title = [sharedInfo objectForKey:@"title"]; richMsg.digest = [sharedInfo objectForKey:@"content"]; richMsg.url = [sharedInfo objectForKey:@"url"]; richMsg.imageURL = [sharedInfo objectForKey:@"imageURL"]; richMsg.extra = [sharedInfo objectForKey:@"extra"]; // long long sendTime = [[sharedInfo objectForKey:@"sharedTime"] longLongValue]; // RCMessage *message = [[RCIMClient sharedRCIMClient] insertOutgoingMessage:[[sharedInfo objectForKey:@"conversationType"] intValue] targetId:[sharedInfo objectForKey:@"targetId"] sentStatus:SentStatus_SENT content:richMsg sentTime:sendTime]; RCMessage *message = [[RCIMClient sharedRCIMClient] insertOutgoingMessage:[[sharedInfo objectForKey:@"conversationType"] intValue] targetId:[sharedInfo objectForKey:@"targetId"] sentStatus:SentStatus_SENT content:richMsg]; [[NSNotificationCenter defaultCenter] postNotificationName:@"RCDSharedMessageInsertSuccess" object:message]; } [shareUserDefaults removeObjectForKey:@"sharedMessages"]; [shareUserDefaults synchronize]; } } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { //融云推送 [[RCIMClient sharedRCIMClient] recordRemoteNotificationEvent:userInfo]; } - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { /** * 统计推送打开率3 */ [[RCIMClient sharedRCIMClient] recordLocalNotificationEvent:notification]; // //震动 // AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); // AudioServicesPlaySystemSound(1007); } - (void)applicationWillResignActive:(UIApplication *)application { RCConnectionStatus status = [[RCIMClient sharedRCIMClient] getConnectionStatus]; if (status != ConnectionStatus_SignUp) { int unreadMsgCount = [[RCIMClient sharedRCIMClient] getUnreadCount:@[ @(ConversationType_PRIVATE), @(ConversationType_GROUP) ]]; application.applicationIconBadgeNumber = unreadMsgCount; } } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:RCKitDispatchMessageNotification object:nil]; }
3、检测融云网络状态变化布局
//当前用户在其余设备上登陆,此设备被踢下线 - (void)onRCIMConnectionStatusChanged:(RCConnectionStatus)status { if (status == ConnectionStatus_KICKED_OFFLINE_BY_OTHER_CLIENT) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message: @"您的账号在别的设备上登陆," @"您被迫下线!" delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]; [alert show]; //跳转到本身的登陆页面 HYNLoginController *loginVC = [[HYNLoginController alloc] init]; self.window.rootViewController = loginVC; } }
4、聊天界面和会话列表post
1.聊天界面:
作过环信,再作这个聊天界面,就至关简单,建立一个继承融云聊界面RCConversationViewController的聊天控制器便可,如下代码为点击私聊进入聊天界面
HYNRCChatViewController *chatVC = [[HYNRCChatViewController alloc] initWithConversationType:ConversationType_GROUP targetId:_ry_gid]; chatVC.title = self.navigationItem.title; HYNNavigationController *nav = [[HYNNavigationController alloc] initWithRootViewController:chatVC]; //标题 chatVC.title = _dataSourDict[@"grpinfo"][@"gname"]; [self.navigationController pushViewController:chatController animated:YES];
如图:
2.会话列表:要实现的界面,如图
与聊天列表同样,建立一个继承融云会话列表RCConversationListViewController的控制器,在这个界面中添加本身须要的UI布局。
坑:融云会话列表能够继承,可是可变性不大,如上图需求,在使用环信时,UITableView能够设置group属性,而后建立2个section,section1为本身的需求界面,section2为聊天的会话列表;可是融云不能够,若是这样布局,那么提供的 self.conversationListDataSource 数据源就为空,没有任何会话数据,这个问题融云的技术给了回复,说是不推荐这样使用,给出的解决方法就是:把上面的本身须要的界面加载到表头或者建立2个UITableView,二选一就直接加载到headerView上,这样最简单。
代码:
//建立融云聊天所须要的类型 - (id)init { self = [super init]; if (self) { //设置要显示的会话类型,可根据需求,这里只实现了单聊和群聊 [self setDisplayConversationTypes:@[ @(ConversationType_PRIVATE), @(ConversationType_GROUP), ]]; //聚合会话类型 // [self setCollectionConversationType:@[ @(ConversationType_SYSTEM) ]]; } return self; } -(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; //获取传声筒未读数 // [self loadMessageCound]; //消息的提示信息 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNeedRefreshNotification:) name:@"kRCNeedReloadDiscussionListNotification" object:nil]; RCUserInfo *groupNotify = [[RCUserInfo alloc] initWithUserId:@"__system__" name:@"" portrait:nil]; [[RCIM sharedRCIM] refreshUserInfoCache:groupNotify withUserId:@"__system__"]; [self updateBadgeValueForTabBarItem]; }
代码:
//注销通知 - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"kRCNeedReloadDiscussionListNotification" object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"GotoNextCoversation" object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"RCDSharedMessageInsertSuccess" object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"RefreshConversationList" object:nil]; //清除badge角标 [self.tabBarController.tabBar hideBadgeOnItemIndex:1]; } - (void)receiveNeedRefreshNotification:(NSNotification *)status { __weak typeof(&*self) __blockSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ if (__blockSelf.displayConversationTypeArray.count == 1 && [self.displayConversationTypeArray[0] integerValue] == ConversationType_DISCUSSION) { [__blockSelf refreshConversationTableViewIfNeeded]; } }); }
代码:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. _titleArr= @[@"评论",@"点赞",@"同问",@"传声筒"]; _userToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"userToken"]; //设置表头(本身的UI布局) self.conversationListTableView.tableHeaderView = self.headerView; // 设置在NavigatorBar中显示链接中的提示 self.showConnectingStatusOnNavigatorBar = YES; //定位未读数会话 self.index = 0; //接收定位到未读数会话的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(GotoNextCoversation) name:@"GotoNextCoversation" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateForSharedMessageInsertSuccess) name:@"RCDSharedMessageInsertSuccess" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshCell:) name:@"RefreshConversationList" object:nil]; //网络判断 //[self networkStateView]; }
通知的方法的实现
代码:
-(void) GotoNextCoversation { NSUInteger i; //设置contentInset是为了滚动到底部的时候,避免conversationListTableView自动回滚。 self.conversationListTableView.contentInset = UIEdgeInsetsMake(0, 0, self.conversationListTableView.frame.size.height, 0); for (i = self.index + 1; i < self.conversationListDataSource.count; i++) { RCConversationModel *model = self.conversationListDataSource[i]; if (model.unreadMessageCount > 0) { NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:i inSection:0]; self.index = i; [self.conversationListTableView scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; break; } } //滚动到起始位置 if (i >= self.conversationListDataSource.count) { // self.conversationListTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); for (i = 0; i < self.conversationListDataSource.count; i++) { RCConversationModel *model = self.conversationListDataSource[i]; if (model.unreadMessageCount > 0) { NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:i inSection:0]; self.index = i; [self.conversationListTableView scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; break; } } } } - (void)updateForSharedMessageInsertSuccess{ [self refreshConversationTableViewIfNeeded]; } -(void)refreshCell:(NSNotification *)notify { [self refreshConversationTableViewIfNeeded]; } - (void)updateBadgeValueForTabBarItem { __weak typeof(self) __weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ int count = [[RCIMClient sharedRCIMClient] getUnreadCount:self.displayConversationTypeArray]; if (count > 0) { NSLog(@"count:%d",count); [__weakSelf.tabBarController.tabBar showBadgeOnItemIndex:1 badgeValue:count]; } else { [__weakSelf.tabBarController.tabBar hideBadgeOnItemIndex:1]; } }); }
headerView的就不说了,这样会话列表已经能够显示了,点击行单元跳转聊天界面
代码:
//点击会话列表时调用 - (void)onSelectedTableRow:(RCConversationModelType)conversationModelType conversationModel:(RCConversationModel *)model atIndexPath:(NSIndexPath *)indexPath { RCConversationViewController *conversationVC = [[RCConversationViewController alloc]init]; conversationVC.conversationType = model.conversationType; conversationVC.targetId = model.targetId; conversationVC.title = model.conversationTitle; [self.navigationController pushViewController:conversationVC animated:YES]; } //设置行高 - (CGFloat)rcConversationListTableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 70; }
此外:若是修改了我的的头像和名称时,要记得刷新融云的我的信息,一样圈聊的信息也要刷新,这样聊天的头像和昵称以及圈聊的头像和名字就可以在修改后马上见效。
//刷新融云的我的信息 -(void)refreshRongCloudInfo { //修改以后的我的信息 RCUserInfo *info = [[RCUserInfo alloc] initWithUserId:[[NSUserDefaults standardUserDefaults] objectForKey:@"ryuid"] name:[[NSUserDefaults standardUserDefaults] objectForKey:@"nickname"] portrait:[[NSUserDefaults standardUserDefaults] objectForKey:@"headimgurl"]]; //传给融云的SDK中 [[RCIM sharedRCIM] refreshUserInfoCache:info withUserId:[[NSUserDefaults standardUserDefaults] objectForKey:@"ryuid"]]; }
//更新融云群聊的信息 -(void)refreshCirclePhotoWithimageUrl:(NSString *)imgUrl { //修改以后的群聊信息 RCGroup *info = [[RCGroup alloc] init]; info.groupId = _dataDict[@"ry_gid"]; info.groupName = _dataDict[@"gname"]; info.portraitUri = imgUrl; //传递给融云的SDK [[RCIM sharedRCIM] refreshGroupInfoCache:info withGroupId:info.groupId]; }
写的比较匆忙,只是稍做整理,有不足之处,感谢留言,谢谢!