环信SDK
来源:互联网 发布:多益网络 社招 编辑:程序博客网 时间:2024/05/30 04:30
一. 即时通讯技术方案
1. 第三方SDK: 环信, 融云, 网易云信, 腾讯 中小型公司/初创型: 建议使用第三方. 好处: 快, 符合快速开发的需求, 自己和后台人员不需要做什么操作 缺点: 你的数据会经过人家的服务器, 可能会不安全 2. 使用XMPP: XMPPFramework, 以前做即时通讯, 基本都在使用XMPP 好处: 源码开源, 可以自行拓展功能, 网上也有很多案例 缺点: 自己和后台人员需要做很多的操作(后台需要额外提供一些接口), 聊天服务器的稳定性可能不够好(看公司自己的运维人员技术是否够好), XML会耗流量 3. 自定义协议: 大型公司/专业即时通讯公司 好处: 接口可以自定义, 可以使用低流量的传输格式 缺点: 需要一定的自定义协议的经验, 包括对数据处理的经验, 对技术能力有一定的要求
二. 环信集成
1. 环信SDK介绍
环信V3版本使用了自定义协议环信之前的版本是基于XMPP封装的APP 服务器与环信服务器的集成环信只是即时通讯的消息通道。环信本身不提供用户体系,环信既不保存任何 APP 业务数据,也不保存任何 APP 的用户信息。比如说,你的 APP 是一个婚恋交友 APP,那么你的 APP 用户的头像、昵称、身高、体重、三围、电话号码等信息是保存在你自己的 APP 业务服务器上,这些信息不需要告诉环信,环信也不想知道。环信这样设计的目的有2个:1. 自己公司一定会有后台服务器, 可以存储用户的数据2. 用户数据非常核心, 不应该保存, 也不太敢存到其他地方环信服务器提供了 REST API 服务用来集成用户和好友体系:1. 环信提供API, 快速将公司自己的账号体系, 转换成环信账号体系2. 环信也提供了好友体系(正常开发中, 不要使用.我们目前为了方便, 可以使用)
2. 集成SDK
3. 环信初始化&UI搭建
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ //AppKey:注册的AppKey,详细见下面注释。 //apnsCertName:推送证书名(不需要加后缀),详细见下面注释。 EMOptions *options = [EMOptions optionsWithAppkey:@"czbk#hmwechat"]; options.apnsCertName = nil; [[EMClient sharedClient] initializeSDKWithOptions:options]; return YES;}// APP进入后台- (void)applicationDidEnterBackground:(UIApplication *)application{ //之后的消息, 应该发送远程推送 [[EMClient sharedClient] applicationDidEnterBackground:application];}// APP将要从后台返回- (void)applicationWillEnterForeground:(UIApplication *)application{ //之后的消息, 取消远程推送 [[EMClient sharedClient] applicationWillEnterForeground:application];}
4. 注册&登录&退出
- 注册&登录
#warning 将来注册和登录, 应该调用服务器的接口, 这里只是为了方便测试, 使用的环信接口- (IBAction)loginClick:(id)sender { EMError *error = [[EMClient sharedClient] loginWithUsername:self.usernameTF.text password:self.passwordTF.text]; if (!error) { NSLog(@"登录成功"); //跳转根控制器 UIStoryboard *mainSB = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; HMTabBarController *tabBarC = [mainSB instantiateViewControllerWithIdentifier:@"HMTabBar"]; [UIApplication sharedApplication].keyWindow.rootViewController = tabBarC; }}- (IBAction)registerClick:(id)sender { /* 注册模式分两种,开放注册和授权注册。 只有开放注册时,才可以客户端注册。开放注册是为了测试使用,正式环境中不推荐使用该方式注册环信账号。 授权注册的流程应该是您服务器通过环信提供的 REST API 注册,之后保存到您的服务器或返回给客户端。 */ EMError *error = [[EMClient sharedClient] registerWithUsername:self.usernameTF.text password:self.passwordTF.text]; if (error==nil) { NSLog(@"注册成功"); }}
- 退出&被动退出
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == 3) { /* 退出登录分两种类型:主动退出登录和被动退出登录。 主动退出登录:调用 SDK 的退出接口; 被动退出登录:1. 正在登录的账号在另一台设备上登录;2. 正在登录的账号被从服务器端删除。 logout:YES: (远程推送)是否解除 device token 的绑定,在被动退出时 SDK 内部处理,需要调用退出方法。 */ EMError *error = [[EMClient sharedClient] logout:YES]; if (!error) { NSLog(@"退出成功"); //切换到登陆界面 UIStoryboard *mainSB = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; HMLoginViewController *loginVC = [mainSB instantiateViewControllerWithIdentifier:@"HMLogin"]; [UIApplication sharedApplication].keyWindow.rootViewController = loginVC; } }}
//添加回调监听代理:[[EMClient sharedClient] addDelegate:self delegateQueue:nil];#pragma mark - 被动退出/*! * 当前登录账号在其它设备登录时会接收到该回调 */- (void)userAccountDidLoginFromOtherDevice { EMError *error = [[EMClient sharedClient] logout:NO]; if (!error) { NSLog(@"退出成功"); //切换到登陆界面 UIStoryboard *mainSB = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; HMLoginViewController *loginVC = [mainSB instantiateViewControllerWithIdentifier:@"HMLogin"]; [UIApplication sharedApplication].keyWindow.rootViewController = loginVC; }}/*! * 当前登录账号已经被从服务器端删除时会收到该回调 */- (void)userAccountDidRemoveFromServer { EMError *error = [[EMClient sharedClient] logout:NO]; if (!error) { NSLog(@"退出成功"); //切换到登陆界面 UIStoryboard *mainSB = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; HMLoginViewController *loginVC = [mainSB instantiateViewControllerWithIdentifier:@"HMLogin"]; [UIApplication sharedApplication].keyWindow.rootViewController = loginVC; }}
5. 自动登录&自动重连
#warning 将来注册和登录, 应该调用服务器的接口, 这里只是为了方便测试, 使用的环信接口- (IBAction)loginClick:(id)sender { EMError *error = [[EMClient sharedClient] loginWithUsername:self.usernameTF.text password:self.passwordTF.text]; if (!error) { NSLog(@"登录成功"); //设置自动登录 [[EMClient sharedClient].options setIsAutoLogin:YES]; }}
/* 自动登录在以下几种情况下会被取消: 用户调用了 SDK 的登出动作; 用户在别的设备上更改了密码,导致此设备上自动登录失败; 用户的账号被从服务器端删除; 用户从另一个设备登录,把当前设备上登录的用户踢出。 所以,在您调用登录方法前,应该先判断是否设置了自动登录,如果设置了,则不需要您再调用。 */ //判断是否有自动登录 BOOL isAutoLogin = [EMClient sharedClient].options.isAutoLogin; if (!isAutoLogin) { //跳转登录界面 UIStoryboard *mainSB = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; HMLoginViewController *loginVC = [mainSB instantiateViewControllerWithIdentifier:@"HMLogin"]; //如果是AppDelegate里, 切换控制器应该使用self.window self.window.rootViewController = loginVC; }
#pragma mark - 自动重连/*! * SDK连接服务器的状态变化时会接收到该回调 * * 有以下几种情况,会引起该方法的调用: * 1. 登录成功后,手机无法上网时,会调用该回调 * 2. 登录成功后,网络状态变化时,会调用该回调 * * @param aConnectionState 当前状态 */- (void)connectionStateDidChange:(EMConnectionState)aConnectionState { NSLog(@"重连状态: %zd", aConnectionState); //将来断网了可以弹出一些提示/或者UI发生一些改变, 让用户知道断网了}
三. 好友关系
注:环信不是好友也可以聊天,不推荐使用环信的好友机制。如果你有自己的服务器或好友关系,请自己维护好友关系。
将来开发中, 记得使用公司的接口实现
1. 添加好友
#pragma mark - UITextFieldDelegate- (BOOL)textFieldShouldReturn:(UITextField *)textField { EMError *error = [[EMClient sharedClient].contactManager addContact:textField.text message:@"我想加您为好友"]; if (!error) { NSLog(@"添加成功"); [self.navigationController popViewControllerAnimated:YES]; } return YES;}
//注册好友回调[[EMClient sharedClient].contactManager addDelegate:self delegateQueue:nil];
2. 接受好友
#pragma mark - 好友添加/*! * 用户A发送加用户B为好友的申请,用户B会收到这个回调 * * @param aUsername 用户名 * @param aMessage 附属信息 */- (void)friendRequestDidReceiveFromUser:(NSString *)aUsername message:(NSString *)aMessage { //这里暂时弹出一个提示框, 让用户选择同意, 或者拒绝 //同意好友请求 EMError *error = [[EMClient sharedClient].contactManager acceptInvitationForUsername:aUsername]; if (!error) { NSLog(@"同意请求"); } //拒绝好友请求 EMError *error = [[EMClient sharedClient].contactManager declineInvitationForUsername:aUsername]; if (!error) { NSLog(@"拒绝请求"); }}/*! @method @brief 用户A发送加用户B为好友的申请,用户B同意后,用户A会收到这个回调 */- (void)friendRequestDidApproveByUser:(NSString *)aUsername { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"好友通知" message:[NSString stringWithFormat:@"%@已经成为您的好友", aUsername] preferredStyle:UIAlertControllerStyleAlert]; [self.window.rootViewController presentViewController:alertController animated:YES completion:nil]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [alertController dismissViewControllerAnimated:YES completion:nil]; });}/*! @method @brief 用户A发送加用户B为好友的申请,用户B拒绝后,用户A会收到这个回调 */- (void)friendRequestDidDeclineByUser:(NSString *)aUsername { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"好友通知" message:[NSString stringWithFormat:@"%@拒绝和您成为好友", aUsername] preferredStyle:UIAlertControllerStyleAlert]; [self.window.rootViewController presentViewController:alertController animated:YES completion:nil]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [alertController dismissViewControllerAnimated:YES completion:nil]; });}
3. 好友列表
//暂时模拟实时刷新- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; //已进入就刷新好友数据 [self reloadContactData];}#pragma mark - 从服务器获取所有的好友- (void)reloadContactData { EMError *error = nil; self.contactArray = [[EMClient sharedClient].contactManager getContactsFromServerWithError:&error]; [self.tableView reloadData];}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellID = @"contactCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath]; cell.textLabel.text = self.contactArray[indexPath.row]; return cell;}
添加好友//发送通知, 让通讯录界面刷新
4. 删除好友
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // 删除好友 //deleteContact: 要删除的用户 //isDeleteConversation: 是否删除对应的会话和消息 删除缓存 EMError *error = [[EMClient sharedClient].contactManager deleteContact:self.contactArray[indexPath.row] isDeleteConversation:YES]; if (!error) { NSLog(@"删除成功"); [self reloadContactData]; } }}
四. 单聊
1. 发送消息
#pragma mark 发送消息- (BOOL)textFieldShouldReturn:(UITextField *)textField { //1. 构造文字消息 EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:textField.text]; //来自于谁--我 NSString *from = [[EMClient sharedClient] currentUsername]; //生成Message //ConversationID: 会话ID, 用于表示和某人的聊天记录, 不传, 默认就会使用to的内容 EMMessage *message = [[EMMessage alloc] initWithConversationID:nil from:from to:self.userName body:body ext:nil]; message.chatType = EMChatTypeChat;// 设置为单聊消息 //message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 //message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 //2. 发送消息 [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *message, EMError *error) { if (error) { NSLog(@"error: %@", error); } else { NSLog(@"发送成功"); } }]; //3.清空文本框 textField.text = @""; [textField resignFirstResponder]; return YES;}
2. 读取消息列表
- (void)viewDidLoad { [super viewDidLoad]; self.tableView.estimatedRowHeight = 90; self.tableView.rowHeight = UITableViewAutomaticDimension; self.messageArrayM = [NSMutableArray array]; [self reloadMessageData:YES];}
- (void)reloadMessageData:(BOOL)isFirst { /* 会话:操作聊天消息 EMMessage 的容器,在 SDK 中对应的类型是 EMConversation。 新建/获取一个会话 根据 conversationId 创建一个 conversation。 getConversation:创建与8001的会话 type:会话类型 createIfNotExist:不存在是否创建 EMConversationTypeChat 单聊会话 EMConversationTypeGroupChat 群聊会话 EMConversationTypeChatRoom 聊天室会话 */ EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:self.userName type:EMConversationTypeChat createIfNotExist:YES]; /*! * 从数据库获取指定数量的消息,取到的消息按时间排序,并且不包含参考的消息,如果参考消息的ID为空,则从最新消息取 * * @param aMessageId 参考消息的ID * @param count 获取的条数 * @param aDirection 消息搜索方向 * @param aCompletionBlock 完成的回调 */ [conversation loadMessagesStartFromId:nil count:isFirst ? 20 : 1 searchDirection:EMMessageSearchDirectionUp completion:^(NSArray *aMessages, EMError *aError) { if (aError) { NSLog(@"数据库查询消息有问题: %@", aError); } else { [self.messageArrayM addObjectsFromArray:aMessages]; NSLog(@"self.messageArray: %@", self.messageArrayM); [self.tableView reloadData]; } }];}
//2. 发送消息 [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *message, EMError *error) { if (error) { NSLog(@"error: %@", error); } else { NSLog(@"发送成功"); //重新读取并刷新 [self reloadMessageData:NO]; } }];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *leftID = @"leftCell"; static NSString *rightID = @"rightCell"; EMMessage *message = self.messageArrayM[indexPath.row]; UITableViewCell *cell; //消息的方向可以去分, 是谁发的 if (message.direction) { //接收的消息 cell = [tableView dequeueReusableCellWithIdentifier:leftID forIndexPath:indexPath]; } else { //发送的消息 cell = [tableView dequeueReusableCellWithIdentifier:rightID forIndexPath:indexPath]; } EMMessageBody *msgBody = message.body; switch (msgBody.type) { case EMMessageBodyTypeText: { // 收到的文字消息 EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody; UILabel *label = [cell viewWithTag:1002]; label.text = textBody.text; } break; default: break; } return cell;}
3. 接收消息
//注册消息回调[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
#pragma mark - 接收普通消息/*! @method @brief 接收到一条及以上非cmd消息 */- (void)messagesDidReceive:(NSArray *)aMessages { //需要发送通知, 告诉正在聊天的控制器进行数据刷新 //通知时, 可以传递消息的数量 --> 7 [[NSNotificationCenter defaultCenter] postNotificationName:@"HMMessagesDidReceiveNotification" object:nil userInfo:@{@"messageCount": @(aMessages.count)}]; NSLog(@"aMessages: %@", aMessages);}
- (void)viewDidLoad { [super viewDidLoad]; self.tableView.estimatedRowHeight = 90; self.tableView.rowHeight = UITableViewAutomaticDimension; self.messageArrayM = [NSMutableArray array]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(messagesDidReceiveNotification:) name:@"HMMessagesDidReceiveNotification" object:nil]; //首次刷新抓20条数据 [self reloadMessageDataWithCount:20];}
//这里还有一个通知的方法, 通知的方法中需要根据消息的个数, 重新读取数据reloadMessageDataWithCount:7- (void)messagesDidReceiveNotification:(NSNotification *)notification{ int count = [notification.userInfo[@"messageCount"] intValue]; [self reloadMessageDataWithCount:count];}
阅读全文
0 0
- 环信SDK集成
- 环信SDK
- iOS-环信SDK讲解
- iOS 环信集成方法之集成环信SDK
- Apple Watch 集成环信SDK
- 环信ONE SDK架构介绍
- 01环信iOS SDK的集成
- 环信ONE SDK架构介绍
- 环信及时通讯的整合SDK
- IOS环信3.1 -SDK集成
- 环信SDK使用过程中问题
- 环信android sdk接入的过程
- 浅谈Android如何集成环信SDK
- 环信客服SDK接入-----(一)
- 环信android SDK 音频文件接收
- 环信SDK-自定义扩展消息
- 环信 即时通讯sdk实现客服功能
- 环信ONE SDK架构介绍
- 二级购物车完整版
- Struts tiles使用中遇到的问题
- 6000字跟你讲清数据运营到底是做什么的?
- 共享单车并购的背后是共享产品质量的竞争还是资金
- 决策树 实现
- 环信SDK
- Virtual Box安装Windows XP系统
- 第十五篇 Android中使用Fiddler实现手机抓包的基本设置
- Weblogic数据源配置
- NanoPi K2 (Amlogic 905) 自行编译内核启动不起来
- filter在spring框架中使用配置文件参数的一种方法
- npm --save和--save-dev区别
- 补充:php7.0.8 + Apache2.4 + MySQL5.7.13 + phpMyAdmin4.6.3
- Java代码和Oracle数据库对日期转换时的差别