xmpp整理笔记:用户网络连接及好友的管理
xmpp中的用户连接模块包括用户的上线与下线信息展现,用户登录,用户的注册; 好友模块包括好友的添加,好友的删除,好友列表的展示。
在xmpp中 负责数据传输的类是xmppStream,开发的过程中,针对不同的传输内容,会调用不同的代理方法,在使用XMPPFramework开发时,只需要在不同的代理方法中,填写相同的代码即可。
往期回顾:
xmpp整理笔记:xmppFramework框架的导入和介绍 http://www.cnblogs.com/dsxniubility/p/4307057.html
xmpp整理笔记:环境的快速配置(附安装包) http://www.cnblogs.com/dsxniubility/p/4304570.html
如果你不是在董铂然博客园看到本文,请点击查看原文
一。大概的连接过程如下
1.运行后需要和服务器建立一个长连接,系统会反馈链接是否成功
2.成功时需要告诉服务器的用户的密码,服务器判断是否给予授权
3.成功授权后,告诉服务器上线了。
4.将要离开时告诉服务器,我需要断开链接了。
5.服务器反馈你可以断开了,然后你再告诉服务器你下线了
二。首先,需要知道 XMPPStreamDelegate 和 XMPPRosterDelegate 的一些代理方法
如果你不是在董铂然博客园看到本文 请点击查看原文
xmpp流代理方法:
连接成功时调用
- (void)xmppStreamDidConnect:(XMPPStream *)sender
断开连接时调用
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
授权成功时调用
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
授权失败时调用
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error
注册成功时调用
- (void)xmppStreamDidRegister:(XMPPStream *)sender
注册失败时调用
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error
xmppRoster花名册代理方法
接收到好友请求时调用
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
三。用户的登录:
用户需要在连接成功后的代理方法中 将自己的密码发送给服务器,自己的密码应该是在点击登录的时候就和其他信息一起存入偏好设置了,在现在需要的时候可以轻而易举的取出来。在发送验证请求的时候会用到这个方法authenticateWithPassword: 后面的error在实际开发中建议必须处理,我在这就偷懒了如下所示
/** 连接成功时调用 */
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
NSLog(@"连接成功"); NSString *password = [[NSUserDefaults standardUserDefaults] valueForKey:SXLoginPasswordKey]; // 将用户密码发送给服务器,进行用户登录
[self.xmppStream authenticateWithPassword:password error:NULL];
}
然后等待结果,在授权成功后来到授权成功代理方法在这应该先告诉服务器用户上线,然后给发出成功通知,自己的AppDelegate在远处接收,一旦接收到通知马上更换应用程序的根控制器到进入后的界面,这里要注意这些代理方法都是在异步的,所以这里要用到线程间通讯,在主线程发送通知
// 通知服务器用户上线
[self goOnline];
// 在主线程利用通知发送广播
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SXLoginResultNotification object:@(YES)];
});
如果授权失败的话,应该断开与服务器的链接,并且把开始存储的用户偏好清空(因为这些是错误的没用),然后再到主线程更新UI弹出一个框显示密码错误,并且发出失败通知,让APPDelegate切换根控制器到登录界面 (董铂然原创)
// 断开与服务器的连接
[self disconnect];
// 清理用户偏好
[self clearUserDefaults];
// 在主线程更新UI
if (self.failed) {
dispatch_async(dispatch_get_main_queue(), ^ {self.failed(@"用户名或者密码错误!");});
}
// 在主线程利用通知发送广播
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SXLoginResultNotification object:@(NO)];
});
四。用户的上线和下线:
关于用户的上线和下线,需要用到一个类XMPPPresence 类。这个类是XMPPElement的子类,主要用来管理某些信息的展现。首先要实例化一个对象,这其中会用到一个presenceWithType 方法,有两个选择@"unavailable"代表下线,@"available"代表上线,一般情况上线的时候后面就可以直接省略。实例化之后用xmpp流发出去。如下所示
#pragma mark - ******************** 用户的上线和下线
- (void)goOnline {
XMPPPresence *p = [XMPPPresence presence]; [self.xmppStream sendElement:p];
} - (void)goOffline {
XMPPPresence *p = [XMPPPresence presenceWithType:@"unavailable"]; [self.xmppStream sendElement:p];
}
对用户是否在线状态的判断
// 取出用户
XMPPUserCoreDataStorageObject *user = [self.fetchedResultsController objectAtIndexPath:indexPath];
用户的 user.section 就是用户的状态
// section // 0 在线 // 1 离开 // 2 离线
五。用户注册:
自己在UI里搭建好注册页面,里面需要用户填写好用户信息。在点击注册按钮时,把单例类里自己设定的一个布尔值isRegisterUser 设置为YES。 然后重新发送连接请求。最终还是会来到,连接成功时的代理方法,刚才在这里发送用户密码登录的,现在可以加一层判断,如果isRegisterUser的值为YES 就不是发送用户密码登录了,而是发送用户密码注册,这里将会用到一个方法registerWithPassword:
if (self.isRegisterUser) {
// 将用户密码发送给服务器,进行用户注册
[self.xmppStream registerWithPassword:password error:NULL];
// 将注册标记复位
self.isRegisterUser = NO;
}
然后有两个代理方法,注册成功和注册失败,分别写上合适的操作。
六。添加好友:
搭建一个加好友的UI只需要一个文本框和一个按钮。
在文本框的回车按钮点击代理方法中,做文本框是否为空得判断,不为空就添加好友,(添加好友方法可以抽出来写使得结构更加清晰)
添加好友方法如下:有两个注意点一个是判断用户是否写了域名,如果只是单单写了个账号,也可以自动帮他拼接个域名然后注册。还有个就是判断是否已经是自己的好友,如果是就不做任何操作。如果不是好友 那就马上添加。最后让导航控制器返回到登陆界面
// 添加好友
- (void)addFriendWithName:(NSString *)name { // 你写了域名那更好,你没写系统就自动帮你补上
NSRange range = [name rangeOfString:@"@"];
// 如果没找到 NSNotFound,不要写0
if (range.location == NSNotFound) {
name = [name stringByAppendingFormat:@"@%@", [SXXMPPTools sharedXMPPTools].xmppStream.myJID.domain];
} // 如果已经是好友就不需要再次添加
XMPPJID *jid = [XMPPJID jidWithString:name]; BOOL contains = [[SXXMPPTools sharedXMPPTools].xmppRosterCoreDataStorage userExistsWithJID:jid xmppStream:[SXXMPPTools sharedXMPPTools].xmppStream]; if (contains) {
[[[UIAlertView alloc] initWithTitle:@"提示" message:@"已经是好友,无需添加" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];
return;
} [[SXXMPPTools sharedXMPPTools].xmppRoster subscribePresenceToUser:jid]; [self.navigationController popViewControllerAnimated:YES];
}
这里会用到一个通过JID加好友的方法subscribePresenceToUser: 但是这个方法是通过Roster 调用的所以要在单例类里导入头文件 声明属性,遵守协议,实现代理方法(董铂然原创)
在单例类里所有特殊类的操作都要写在xmppStream的懒加载里
// 实例化
_xmppReconnect = [[XMPPReconnect alloc]init];
_xmppRosterCoreDataStorage = [XMPPRosterCoreDataStorage sharedInstance];
_xmppRoster = [[XMPPRoster alloc]initWithRosterStorage:_xmppRosterCoreDataStorage dispatchQueue:dispatch_get_global_queue(0, 0)];
// 激活
[_xmppRoster activate:_xmppStream];
// 添加代理
[_xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
接受到加好友请求的代理方法
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
在这个方法中,先要拼接提示的字符串,就是从 presence.from(申请人的id)的人请求加你为好友。然后设置弹窗,确定和拒绝,点击确定按钮后
// 接受好友请求
[self.xmppRoster acceptPresenceSubscriptionRequestFrom:presence.from andAddToRoster:YES];
这个弹窗建议使用iOS8的新功能 UIAlertController。 这样可以不用写alertDelegate 也能设置确定按钮点击事件 。用 alert addAction: 添加按钮,把点击事件写在block里,最后再取到当前窗口的根控制器弹出presentViewController,相当于以前的show 。iOS8苹果的思想渐渐是想把所有弹出控制器的各种方法都慢慢统一到present。
补充:这个功能就是QQ上所谓的加好友不需要验证,是布尔值可以控制开关。
// 取消接收自动订阅功能,需要确认才能够添加好友!
_xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = NO;
七。好友列表的展示。
这里需要用到查询结果调度器
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
// 指定查询的实体
NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:@"XMPPUserCoreDataStorageObject"]; // 在线状态排序
NSSortDescriptor *sort1 = [NSSortDescriptor sortDescriptorWithKey:@"sectionNum" ascending:YES];
// 显示的名称排序
NSSortDescriptor *sort2 = [NSSortDescriptor sortDescriptorWithKey:@"displayName" ascending:YES]; // 添加排序
request.sortDescriptors = @[sort1,sort2]; // 添加谓词过滤器
request.predicate = [NSPredicate predicateWithFormat:@"!(subscription CONTAINS 'none')"]; // 添加上下文
NSManagedObjectContext *ctx = [SXXMPPTools sharedXMPPTools].xmppRosterCoreDataStorage.mainThreadManagedObjectContext; // 实例化结果控制器
_fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request managedObjectContext:ctx sectionNameKeyPath:nil cacheName:nil]; // 设置他的代理
_fetchedResultsController.delegate = self; return _fetchedResultsController;
}
写完了结果调度器之后要切记在viewdidload页面首次加载中加上一句,否则不干活
// 查询数据
[self.fetchedResultsController performFetch:NULL];
结果调度器有一个代理方法,一旦上下文改变触发,也就是刚加了好友,或删除好友时会触发
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
NSLog(@"上下文改变");
[self.tableView reloadData];
}
整个tableview的数据源方法如下
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.fetchedResultsController.fetchedObjects.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"ContactCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; XMPPUserCoreDataStorageObject *user = [self.fetchedResultsController objectAtIndexPath:indexPath]; // 显示此好友是否相互关注
NSString *str = [user.jidStr stringByAppendingFormat:@" | %@",user.subscription]; cell.textLabel.text = str ;
// 这里有个自定义方法传入section 通过switch判断返回汉字。section关系到是否在线
cell.detailTextLabel.text = [self userStatusWithSection:user.section]; return cell;
}
其中subscription是用户的好友互加情况
// 如果是none表示对方还没有确认 // to 我关注对方 // from 对方关注我 // both 互粉
再提一下 user.section 就是用户的状态
// section // 0 在线 // 1 离开 // 2 离线
当有好友上线,上下文改变时,结果调度器会重新排序,然后在线的好友会显示在上面。
八。删除好友
好友的列表显示界面可以给tableView添加滑动删除。(开启编辑模式)
#pragma mark - ******************** 开启编辑模式删除好友
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) {
XMPPUserCoreDataStorageObject *user = [self.fetchedResultsController objectAtIndexPath:indexPath]; XMPPJID *jid = user.jid;
// 接下来是设置弹窗
在弹窗的点击事件里面删除好友用到的方法是
[[SXXMPPTools sharedXMPPTools].xmppRoster removeUser:jid];
如果你不是在董铂然博客园看到本文,请点击查看原文
正在整理关于信息发送模块的各种细节,有兴趣的可以关注
xmpp整理笔记:用户网络连接及好友的管理的更多相关文章
- xmpp整理笔记:发送图片信息和声音信息
图片和音频文件发送的基本思路就是: 先将图片转化成二进制文件,然后将二进制文件进行base64编码,编码后成字符串.在即将发送的message内添加一个子节点,节点的stringValue(节点的值) ...
- xmpp整理笔记:聊天信息的发送与显示
任何一个信息的发送都需要关注两个部分,信息的发出,和信息在界面中的显示 往期回顾: xmpp整理笔记:环境的快速配置(附安装包) http://www.cnblogs.com/dsxniubilit ...
- xmpp整理笔记:xmppFramework框架的导入和介绍
一个将要开发xmpp的项目,建议在项目刚创建就导入框架,这样可以避免一些自己操作失误造成不必要的损失. xmpp中最常用的框架就是 xmppFrameWork 往期回顾: xmpp整理笔记:环境的快速 ...
- xmpp整理笔记:环境的快速配置(附安装包)
现在虽然环信的xmpp框架很火,但是也有一些弊端.环信的框架部分代码不开源,而且收费模式不科学,用户量一直低于免费线则好,一旦超过,收费极高. xmpp感觉还是从xmppFramework框架学起比较 ...
- lesson - 1 笔记 网络连接 /putty 密钥登陆
---笔记 一.网络连接配置 1. 查看电脑ip 地址: ifconfig -a 2. 自动获取ip 地址: dhclient 默认BOOTPROTO=dhcp 和真机同一网段 3. 手动配置 ...
- Hi3516开发笔记(二):Hi3516虚拟机基础环境搭建之串口调试、网络连接以及sftp文件传输
前言 搭建Hi3516的基础虚拟机,为交叉编译环境搭建前期工作.后续会编译一个基本的C语言程序Demo,在HI3516上跑. 虚拟机 开发本对虚拟机做了一些基本要求,如下图: 其实重 ...
- Silverlight项目笔记6:Linq求差集、交集&检查网络连接状态&重载构造函数复用窗口
1.使用Linq求差集.交集 使用场景: 需要从数据中心获得用户数据,并以此为标准,同步系统的用户信息,对系统中多余的用户进行删除操作,缺失的用户进行添加操作,对信息更新了的用户进行编辑操作更新. 所 ...
- Python学习笔记整理总结【网络编程】【线程/进程/协程/IO多路模型/select/poll/epoll/selector】
一.socket(单链接) 1.socket:应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socke ...
- Kafka技术内幕 读书笔记之(二) 生产者——服务端网络连接
KafkaServer是Kafka服务端的主类, KafkaServer中和网络层有关的服务组件包括 SocketServer.KafkaApis 和 KafkaRequestHandlerPool后 ...
随机推荐
- 【Android】[转] Android Handler应设为static
android开发中,使用Lint检测时会提示这么一句话 : This Handler class should be static or leaks might occur.意为handler应用s ...
- 用caffe跑自己的数据,基于WINDOWS的caffe
本文详细介绍,如何用caffe跑自己的图像数据用于分类. 1 首先需要安装过程见 http://www.cnblogs.com/love6tao/p/5706830.html 同时依据上面教程,生成了 ...
- ansible写一个简单的playbook
前言 实现的功能很简单,就是通过ansible批量完成某个账户sudo权限的开通或关闭 目录结构 ├── group_vars #放置各种变量的目录,我这里没用 ├── hosts #主机和组配置,默 ...
- 阅读《LEARNING HARD C#学习笔记》知识点总结与摘要系列文章索引
从发表第一篇文章到最后一篇文章,时间间隔有整整一个月,虽只有5篇文章,但每一篇文章都是我吸收<LEARNING HARD C#学习笔记>这本书的内容要点及网上各位大牛们的经验,没有半点废话 ...
- 【转载】css3 content 生成内容
content一般和:before,:after一起使用,用来生成内容(img和input没有该属性),content的内容一般可以为以下四种: none: 不生成任何值. attr: 插入标签属性值 ...
- AdjustWindowRect与AdjustWindowRectEx
AdjustWindowRect 根据所需的矩形大小,计算所需的矩形的大小;然后,窗口矩形可以传递给CreateWindow函数创建一个窗口. AdjustWindowRectEx 是AdjustWi ...
- SQL去除回车符,换行符,空格和水平制表符
MS SQL去除回车符,换行符,空格和水平制表符,参考下面语句,一般情况是SQL接受富文本或是textarea的内容.在数据库接收到这些数据之后,还是对其做一些处理. ),),),''),' ','' ...
- asp.net网站优化经验之谈
最近公司一个项目上线后,经常崩溃,于是开始重视性能问题,在网上看到了许多相关文章,整理下发了上来.以备参考. 在用ASP.NET开发网站的时候,性能是永远需要考虑和关注的问题,性能不仅仅只是程序代码执 ...
- 【C#】让DataGridView输入中实时更新数据源中的计算列
本文适用Winform开发,且DataGridView的数据源为DataTable/DataView的情况. 理解前提:熟知DataTable.DataView 求:更好方案 考虑这样一个场景: 某D ...
- MySQL Workbench 修改快捷键
在安装根目录查到\data\main_menu.xml这个文件 例如,修改执行sql语句的快捷键为F5 <value type="object" struct-name=&q ...