现在环信SDK(EaseMobSDK)更新到了3.0,我开始使用的时候只是2.3或者2.4的版本。使用的时候在视频聊天的时候体验不太好,经常看不到对方,后来更新到了最新的版本,改善了很多。不过UI我使用的依然是之前的版本,不得不说之前的UI满满的iOS6即视感。
首先到官网上注册应用
需要上传一个开发和发布环境下的p12文件,在发送消息时需使用推送。
下载SDK后按照官方文档导入项目,做好配置。
在AppDelegate+EaseMob中做了初始化和推送的一些操作。
方法里面的代码,在官方Demo中有所体现,按照自己项目的需求自行改动。
在项目首页,加了个扩展类BNHomePageViewController+EaseMob,主要处理通讯中的一些全局事件,诸如好友请求、加群申请、消息推送、挤退下线等,首页这个类在整个生命周期中一直存在。代码如下
具体方法里的实现代码在官网Demo中也有所体现,按照自己项目的需求自行改动。有些方法并不是必须的,项目中我只用到了私聊和聊天室功能,群相关功能没有用到,所以加群请求等方法不需要实现。
这样一些配置就实现了,接下来进行功能开发。
登陆
1 2 3 4 5 6 7 8 9 10
| [[EaseMob sharedInstance].chatManager asyncLoginWithUsername:response[@"username"] password:response[@"password"] completion:^(NSDictionary *loginInfo, EMError *error) { if (!error) {
}else{ NSLog(@"error=%@",error) } } onQueue:nil]
|
这里我是在当前项目登陆之后调用的环信登陆,环信登陆成功之后才进入的首页。这样就有可能环信如果挂掉,就进入不到首页,停留在登录页面。可以先登陆本应用,进入首页之后再调用环信的登陆方法,这样也会遇到一个问题,进入首页后环信如果一直登陆不上去,那环信相关的功能也都使用不了。而且环信的登陆需要较强的网络,类似于登陆、视频聊天等还是有小部分几率是不成功的。使用第三方SDK这种问题难以避免,只能寄希望与它们的SDK能够给力点。
退出
1 2 3 4 5 6 7
| [[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:YES completion:^(NSDictionary *info, EMError *error){ [(AppDelegate *)[UIApplication sharedApplication].delegate goToLoginPage]
} onQueue:nil]
|
退出环信登陆后跳回登陆页面,其实还有个退出本应用的操作。这一步也会面临登陆同样的问题,即操作失败。这样在登陆的时候就需要先判断当前是否已登陆,如果已登陆则先退出再重新登录。
挤退下线
1 2 3 4 5 6 7 8 9
| - (void)didLoginFromOtherDevice { [[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:NO completion:^(NSDictionary *info, EMError *error) { [(AppDelegate *)[UIApplication sharedApplication].delegate goToLoginPage]; [PublicAlertUnit showNormalAlert:@")didLoginFromOtherDevice"]; } onQueue:nil]; }
|
didLoginFromOtherDevice这个方法官方有提供,是个长连接,一旦该账号在别的设备登陆就会调用这个方法。didRemovedFromServer这个方法是账号从服务器上被删除会调用的方法。
统计未读消息数
1 2 3 4 5 6 7 8 9 10 11
| -(void)setupUnreadMessageCount { NSArray *conversations = [[[EaseMob sharedInstance] chatManager] conversations]; NSInteger unreadCount = 0; for (EMConversation *conversation in conversations) { if (conversation.conversationType == eConversationTypeChat) { unreadCount += conversation.unreadMessagesCount; } }
|
拿到的会话有可能是群聊或聊天室,所以需要判断类型,这里只统计私聊
得到最后消息的时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| NSMutableArray *ret = nil; NSArray* sorte = [conversations sortedArrayUsingComparator: ^(EMConversation *obj1, EMConversation* obj2){ EMMessage *message1 = [obj1 latestMessage]; EMMessage *message2 = [obj2 latestMessage]; if(message1.timestamp > message2.timestamp) { return(NSComparisonResult)NSOrderedAscending; }else { return(NSComparisonResult)NSOrderedDescending; } }]; ret = [[NSMutableArray alloc] initWithArray:sorte]; if (ret.count != 0) { EMConversation *conversation = ret[0]; time = [self lastMessageTimeByConversation:conversation]; } -(NSString *)lastMessageTimeByConversation:(EMConversation *)conversation { NSString *ret = @""; EMMessage *lastMessage = [conversation latestMessage];; if (lastMessage) { ret = [NSDate formattedTimeFromTimeInterval:lastMessage.timestamp]; } return ret; }
|
这里需要显示最后一条消息的时间,所以先把会话时间排序,再分别获取每个会话最后一条消息的时间
保存头像
1 2 3 4 5
| NSString *chatter = conversation.chatter chatController = [[ChatViewController alloc] initWithChatter:chatter conversationType:conversation.conversationType] chatController.delelgate = self chatController.title = title [self.navigationController pushViewController:chatController animated:YES]
|
环信并不处理用户头像,是为了减少对用户信息的入侵。所以用户头像需我们自己处理,这里用的是我们应用中用户的头像。根据用户id请求我门自己的后台链接,请求成功后将头像存储本地,一旦本地存储,则不再请求,只需要从中获取。在退出会话页则删除本地存储,原因是当前用户可能会更改头像,每次进入聊天页面都需要从新请求一次,也可以不删除本地头像存储,但在用户更换头像的时候更新本地存储。但是,你无法知道对方(你与之聊天的人)什么时候更换了头像,也有可能是在聊天过程中更换了头像,所以可以在发送消息的时候传入头像,接收方再解析显示。
透传消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| EMChatCommand *cmdChat = [[EMChatCommand alloc] init]; EMCommandMessageBody *body = [[EMCommandMessageBody alloc] initWithChatObject:cmdChat]; EMMessage *message = [[EMMessage alloc] initWithReceiver:receiver bodies:@[body]]; NSDictionary *dic=@{@"BidId":[NSString stringWithFormat:@"%ld",self.bidID]}; message.ext = @{@"Customer Key":dic, };
message.messageType = eMessageTypeChat; [[EaseMob sharedInstance].chatManager asyncSendMessage:message progress:nil prepare:^(EMMessage *message, EMError *error) { } onQueue:nil completion:^(EMMessage *message, EMError *error) { } } onQueue:nil];
|
透传消息有别于正常的收发消息,类似于推送,对方不在线的时候接收方法是didReceiveOfflineCmdMessages,对方在线接收方法是didReceiveCmdMessage。应用场景是我需要在双方聊天的时候传送一些商品信息,在聊天页上显示商品信息,所以就使用了透传,对方在接收消息后保存在本地,打开聊天页的时候需遍历本地数据库判断是否应该显示保存的商品信息。
加入聊天室
1 2 3 4 5 6 7 8 9 10 11
| ChatViewController *chatPersonally = [[ChatViewController alloc]initWithChatter:roomID conversationType:eConversationTypeChatRoom];
_chatPersonally = chatPersonally;
chatPersonally.delelgate = self;
chatPersonally.view.frame = CGRectMake(0, 0, CGRectGetWidth(self.noDataChatView.frame), CGRectGetHeight(self.noDataChatView.frame));
[self.noDataChatView addSubview:chatPersonally.view];
[self addChildViewController:chatPersonally];
|
- 用户可以同时加入多个聊天室
- 退出聊天室聊天记录即清空
- 服务器监听到当前用户不在线不会继续给此用户推送
- 如果用户当前不在线,且聊天室有消息(则该用户进入聊天室后给推10条消息)
- 进入聊天室后,杀掉程序,再次进入后记录依然存在(除非调用退出聊天室的方法,否则不算退出)
- 会话列表页不显示聊天室信息
发送信息
相关方法在Demo有所体现,可自行查看。
Demo中ChatViewController包含的方法比较多,包括发送消息、解析消息、显示位置、语音、视频聊天等,可以直接将这个类拖至项目中使用,但要注意上下文使用环境,也可以自己布局UI,仅使用相关方法。
牵扯到聊天相关一般都比较繁杂,文档只起到辅助的作用,还是需要花时间去好好研究!
如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!
Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!
微信公众号OldDriverWeekly
,欢迎关注并提出宝贵意见
老司机iOS周报,欢迎关注或订阅
刚刚在线工作室,欢迎关注或提出建设性意见!
刚刚在线论坛, 欢迎踊跃提问或解答!
如有转载,请注明出处,谢谢!