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];

如果你不是在董铂然博客园看到本文,请点击查看原文

正在整理关于信息发送模块的各种细节,有兴趣的可以关注

时间: 2024-10-05 17:12:01

xmpp整理笔记:用户网络连接及好友的管理的相关文章

xmpp整理笔记:发送图片信息和声音信息

图片和音频文件发送的基本思路就是: 先将图片转化成二进制文件,然后将二进制文件进行base64编码,编码后成字符串.在即将发送的message内添加一个子节点,节点的stringValue(节点的值)设置这个编码后的字符串.然后消息发出后取出消息文件的时候,通过messageType 先判断是不是图片信息,如果是图片信息先通过自己之前设置的节点名称,把这个子节点的stringValue取出来,应该是一个base64之后的字符串, 往期回顾: xmpp整理笔记:聊天信息的发送与显示  http:/

xmpp整理笔记:聊天信息的发送与显示

任何一个信息的发送都需要关注两个部分,信息的发出,和信息在界面中的显示 往期回顾: xmpp整理笔记:环境的快速配置(附安装包)  http://www.cnblogs.com/dsxniubility/p/4304570.html xmpp整理笔记:xmppFramework框架的导入和介绍  http://www.cnblogs.com/dsxniubility/p/4307057.html xmpp整理笔记:用户网络连接及好友管理http://www.cnblogs.com/dsxniub

xmpp整理笔记:xmppFramework框架的导入和介绍

一个将要开发xmpp的项目,建议在项目刚创建就导入框架,这样可以避免一些自己操作失误造成不必要的损失. xmpp中最常用的框架就是 xmppFrameWork 往期回顾: xmpp整理笔记:环境的快速配置(附安装包)  http://www.cnblogs.com/dsxniubility/p/4304570.html 如果你不是在董铂然博客园看到本文请 点击查看原文 第一种方法直接拖 1> 拖入文件夹 在网盘链接的xmppFramework文件夹 :http://pan.baidu.com/s

xmpp整理笔记:环境的快速配置(附安装包)

现在虽然环信的xmpp框架很火,但是也有一些弊端.环信的框架部分代码不开源,而且收费模式不科学,用户量一直低于免费线则好,一旦超过,收费极高. xmpp感觉还是从xmppFramework框架学起比较科学.能够更清楚的了解即时通讯里各个操作的api,就算以后出了新的框架底层也要这么用的.主要用到的工具软件有Openfire,mysql,javajdk,phpMyAdmin,Adium等 将本文拉到最下面能看到配置完成之后的聊天效果. 附:需要用到的软件地址是 http://pan.baidu.c

网络连接相关基础知识笔记

一.常说的TCP/IP的含义 TCP/IP协议簇并不仅仅指TCP协议和IP协议,实际它包括了一系列协议组成的集合,如:TCP,IP,UDP,FTP,SMTP,DNS,ARP,PPP等 TCP与UDP协议都属于传输层协议,但有很大不同,TCP是面向连接的协议,提供的是可靠的数据流服务,TCP采用"带重传的肯定确认"机制来实现传输的可靠性,实现了一种"虚电路",因为从物理上来说,并不是真正在两台主机间建立了连接,这种连接只是存在于逻辑上的.最大的开销出现在通信前建立连接

网易云音乐如何从0到亿级用户整理笔记

为什么要做网易云音乐? l  老板是发烧友 l  市面音乐不喜欢,市面上音乐质量比较匮乏 l  做这件事对音乐行业有啥帮助,对公司有啥帮助,对用户有啥帮助 它是如何做出来的? 好口碑是如何打造的? 主要从互联网音乐市场的现状分析.如何做产品定位.如何跨越鸿沟.探索过程中用到哪些手段.需求挖掘与用户引导五个方面来解析 互联网音乐市场的现状分析: 主流:当时主流市场是酷狗,QQ,酷我: 第二市场是百度,天天动听,虾米,豆瓣fm, 多米,jinfm等 缺乏创新的大市场:主流市场是曲库型产品, 播放器型

Silverlight项目笔记6:Linq求差集、交集&检查网络连接状态&重载构造函数复用窗口

一.使用Linq求差集.交集 使用场景: 需要从数据中心获得用户数据,并以此为标准,同步系统的用户信息,对系统中多余的用户进行删除操作,缺失的用户进行添加操作,对信息更新了的用户进行编辑操作更新. 所以需要通过对数据中心以及系统现有用户信息进行比较,分为三部分: (1) Linq取差集,找出需要删除的用户数据,进行删除(USERNAME为唯一值字段). 使用的是Except这个方法. (2)使用Linq提供的Intersect方法,取得两个用户集合的交集,遍历检查进行更新. (3)同样再次取差集

Linux笔记之VMware网络连接

概述 VMware有三种网络连接模式,即Bridged.NAT和Host-only: 当安装完VMware Workstation后,宿主机上会自动模拟出两块虚拟网卡:VMnet1和VMnet8,其中VMnet1对应于Host-only模式,VMnet8对应于NAT模式: VMware----->虚拟机----->设置----->网络适配器 VMware----->编辑---->虚拟网络编辑器 右击网络连接图标----->打开网络和共享中心----->更改适配器设

JDBC学习笔记(18):通过代理模式来保持用户关闭连接的习惯

在前面的JdbcUtils包中,在关闭连接的时候使用了conn.close()方法,如果关闭了连接,那么放回连接池中的连接就成为无效的连接,为了规范用户关闭连接的习惯,使用代理模式来将连接放回连接池而又不改变用户的程序: 将JdbcUtils工具包改变回原来的情形: 1 package com.xxyh.jdbc; 2 import java.sql.Connection; 3 import java.sql.ResultSet; 4 import java.sql.SQLException;