给我一个及时的问候——XMPP
XMPP总的来说就是:基于XML数据结构,点对点的,及时通讯协议
是 Linux操作系统+Apache软件+mySql数据库 + php 编程语言 组成
开始时要导入 XMPPFrameWork框架:【附带框架如下】
具体的框架下载地址:http://pan.baidu.com/s/1hqoB4pQ
如果要搭建XMPP开发环境 可以从下面获取一些必要的安装软件:
我把需要安装的软件都已经整理好了,下次给大家分享一下如何搭建的问题:
安装好环境接下来就进入最有意思的环节写代码:
首先将值之前下载的框架引入我们的文件中:
引入完框架接下来县创建一个XMPPManager的类用来放置通道管理器:XMPPStream
,用户类:XMPPRoster和XMPP的CoreData储存的类:并创建登陆和注册方法获取用户名和密码:
具体代码如下:
// 1、通道管理器类 在服务器之间创建通道
@property(nonatomic,strong)XMPPStream * XMPPStream; // 好友关系(好友花名册,添加好友信息)2、 用户类
@property(nonatomic,strong)XMPPRoster * XMPPRoSter; // 这两个属性是聊天记录用到的
// XMPP的CoreData存储的类 @property(nonatomic,strong)XMPPMessageArchiving * achivimg; @property(nonatomic,strong)NSManagedObjectContext * context; // 创建单例 放进不会重复初始化的东西 +(instancetype)defaultManager; // 登陆 -(void)loginWithUserName:(NSString *)userName andPassWorld:(NSString *)password; // 注册 -(void)registerWithUserName:(NSString *)userName andPassword:(NSString *)password;
在XMPPManager的.m文件中还需要使用一个XMPPJID的类来记录用户的一些信息,主要的工作是对通道管理器类进行初始化,设置自己的服务器名,设置端口号遵循
XMPPStreamDelegate,XMPPRosterDelegate这两个代理。初始化方法如下:
-(id)init{ self = [super init];
if (self) {
// 初始化自己的通道管理器类 self.XMPPStream =[[XMPPStream alloc]init]; // 服务器的名字,(在openfire后台管理里面看) self.XMPPStream.hostName = @"127.0.0.1"; // 设置端口号, 默认是5222
self.XMPPStream.hostPort = ;
// 设置代理在主线程里面
[self.XMPPStream addDelegate:self delegateQueue:(dispatch_get_main_queue())];
XMPPRosterCoreDataStorage * coreDataStorage =[XMPPRosterCoreDataStorage sharedInstance]; // 初始化用户管理
self.XMPPRoSter = [[XMPPRoster alloc]initWithRosterStorage:coreDataStorage dispatchQueue:(dispatch_get_main_queue())];
// 在主线程中添加代理方法
[self.XMPPRoSter addDelegate:self delegateQueue:(dispatch_get_main_queue())];
// 将用户类放进通道管理器类里面
[self.XMPPRoSter activate:self.XMPPStream];
XMPPMessageArchivingCoreDataStorage * coreData = [XMPPMessageArchivingCoreDataStorage sharedInstance];
self.achivimg =[[XMPPMessageArchiving alloc]initWithMessageArchivingStorage:coreData dispatchQueue:(dispatch_get_main_queue())];
// 将消息类放进管理器通道类里面
[self.achivimg activate:self.XMPPStream]; self.context = coreData.mainThreadManagedObjectContext; }
return self;
}
接着实现代理方法:
通道管理器类作为一个信息传输的通道,需要每次进行连接,在连接的同时我们可以通过JID获取用户的信息实现具体的连接类用来获取用户数:
-(void)connectionWithUserName:(NSString *)userName andPassWord:(NSString *)passwod { // 在发生登录注册的时候,需要让我的通道类连接断掉,防止出现连接混乱的情况 if ([self.XMPPStream isConnected]) { // 仅允许一个终端在线登录(不允许重复登录)
[self.XMPPStream disconnect];
} self.password = passwod; // 3、XMPPJId 保存的是一些用户的信息
// 这个类当这个通道和服务器连接,保存的是一些用户的信息
// 可以知道是给别人发消息,还是别人发来的消息 XMPPJID * jid =[XMPPJID jidWithUser:userName domain:@"127.0.0.1" resource:@"iOS"]; // 可以知道是发送消息还是接收消息 // 在jid保存到XMPPStream里面
self.XMPPStream.myJID = jid; // 让通道管理器类建立连接 [self.XMPPStream connectWithTimeout:1.0f error:nil]; }
除此之外要使用代理中的方法,判断连接的状态,这也是使用管理器连接成功的关键:
代理方法如下:
// 当连接成功
-(void)xmppStreamDidConnect:(XMPPStream *)sender
{
switch (self.myConnectMode) {
case connectIsLogin:
[self.XMPPStream authenticateWithPassword:self.password error:nil]; break;
case connectIsRefister:
[self.XMPPStream registerWithPassword:self.password error:nil];
break; default:
break;
} }
// 连接失败 -(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{ }
// 将要失去连接 -(void)xmppStreamWillConnect:(XMPPStream *)sender
{ }
这样基本上我们就把我们的XMPPManager类给写好了接下来就是登录和注册页面:
可以简单的使用storyboard将登录和注册页面拖拽出来:
使用storyboard时应该有三点需要注意的尤其对于新手来讲:首先如果存在代理,遵循代理(比如tableView),接着要记得绑定相应的页面,最后记得设置storyboard Id
在登录和注册页面中都要遵循 <XMPPStreamDelegate>代理:并将其放进主线程中
在注册页面中主要实现的方法有:
登录成功执行的方法主要是为了想服务器发送上线的消息
// 登录成功执行的方法
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
// 连接成功后发送消息,发送有效消息,上线消息
XMPPPresence * presence =[XMPPPresence presenceWithType:@"available"]; // 上线的消息通过XMPPStream 发送 [[XMPPManager defaultManager].XMPPStream sendElement:presence];
NSLog(@"登录成功"); AppDelegate * app = [UIApplication sharedApplication].delegate; RootViewController * roster =[[UIStoryboard storyboardWithName:@"Main" bundle:nil]instantiateViewControllerWithIdentifier:@"rootVC"]; app.window.rootViewController = roster; }
当点击登录按钮时需要将用户的用户名和密码发送
- (IBAction)LoginAction:(id)sender {
// 调用XMPPManager里面的登录注册的方法 // 调用XMPP里面的登录注册的方法获取用户名密码
[[XMPPManager defaultManager]loginWithUserName:self.nameTextFild.text andPassWorld:self.passwordTextFild.text]; }
在注册的界面中主要要实现的方法是:
注册成功的方法:
-(void)xmppStreamDidRegister:(XMPPStream *)sender
{ UIAlertView * alertView =[[UIAlertView alloc]initWithTitle:@"提示" message:@"恭喜您注册成功" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
[alertView show]; LoginViewController * longinVC =[[UIStoryboard storyboardWithName:@"Main" bundle:nil]instantiateViewControllerWithIdentifier:@"loginVC"]; [self showViewController:longinVC sender:nil]; }
之后登录注册页面就这样简单的完成了,做好了登录和注册就想发送消息就想把冬天的那句暖暖的问候发送给你,但是我需要知道你的信息才行,接下来我们可以建立用户的好友列表界面:
在好友列表界面中要遵循<XMPPRosterDelegate>用户类的代理方法,主要实现的方法包括:
// 获取好友列表 -(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item
{
// 通过获取好友列表这个方法有助于获得各个好友的信息,通过item获取
if ([[[item attributeForName:@"subscription"]stringValue]isEqualToString:@"both"]) {
// 获取item里面节点的数据
NSString * jidStr =[[item attributeForName:@"jid"]stringValue];
// 通过在item里面获取到的数据初始化一个XMPPJID
XMPPJID * jid =[XMPPJID jidWithString:jidStr];
// 把这个jid放到数据源数组里面
[self.dataArray addObject:jid]; // 使界面中的信息能够自动下翻
[self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.dataArray.count - inSection:]] withRowAnimation:UITableViewRowAnimationAutomatic]; }
}
还有两个好友列表的代理方法根据需要来实现:
/ 开始获取好友列表 -(void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender
{
NSLog(@"开始获取");
} // 结束获取好友列表 -(void)xmppRosterDidEndPopulating:(XMPPRoster *)sender
{
NSLog(@"结束获取");
}
有了你的信息我就想加你为好友接下来在XMPPManager里面设置加好友的方法:
// 收到好友的请求的代理方法 -(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
// 获取来自于好友的请求
self.fromJID = presence.from; // 弹框 UIAlertView * view =[[UIAlertView alloc]initWithTitle:@"收到好友请求" message:@"加我为好友吧~~" delegate:self cancelButtonTitle:@"残忍拒绝" otherButtonTitles:@"乐意加入", nil]; [view show]; }
根据自己的选择实现UIAlertView的代理方法来进行好友的添加:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (buttonIndex) {
case : // 拒绝来自fromJID的加入
[self.XMPPRoSter rejectPresenceSubscriptionRequestFrom:self.fromJID];
break; // 接受来自fromJID的数据
case :
[self.XMPPRoSter acceptPresenceSubscriptionRequestFrom:self.fromJID andAddToRoster:YES];
break; default:
break;
}
}
有了好友,接下来就是做信息处理了我们在建立一个MessageViewController用来处理信息:
首先在MessageViewController设置一个JID的属性确定和我聊天的是谁
接着在.m文件中需要实现的代理方法有:
首先我们要在CoreData中获取数据:
// 获取发送的信息数据
-(NSArray *)findData
{ NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:[XMPPManager defaultManager].context];
[fetchRequest setEntity:entity];
// Specify criteria for filtering which objects to fetch //bareJidStr 参数代表的是和我聊天的人
//streamBareJidStr 参数代表的是我自己
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bareJidStr = %@ AND streamBareJidStr = %@", self.toJid.bare, [XMPPManager defaultManager].XMPPStream.myJID.bare];
[fetchRequest setPredicate:predicate];
// Specify how the fetched objects should be sorted
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp"ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]]; NSError *error = nil;
NSArray *fetchedObjects = [[XMPPManager defaultManager].context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
// 查询的数据不存在则返回一个数组 return [NSArray array];
}else{
// 返回查询的数据
return fetchedObjects;
} }
接着就设置接收消息的方法:
// 接收消息时
-(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
[self.dataArray removeAllObjects];
[self.dataArray setArray:[self findData]]; [self.tableView reloadData]; // 代码自动滚动
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:self.dataArray.count - inSection:] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }
发送消息是的代理方法:
// 发送时遵循的代理 -(void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message
{
[self.dataArray removeAllObjects]; [self.dataArray setArray:[self findData]]; [self.tableView reloadData];
// 代码自动滚动
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:self.dataArray.count - inSection:] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
这样我们的消息类也处理完成了,运行程序可以看到:
首先是保证我们的服务器都已经开启:
接着注册
然后点击注册:
接着登陆
此时点击登陆后我们跳转到的是好友列表界面因为没有添加好友所以目前是空的
我们打开Spark登陆我们之前在服务器中注册的一个账号
:
添加windsSunShine为好友:
此时我们的模拟器会收到邀请信息:
选择加入就成功添加好友,然后点击聊天就可以把你的问候传递给你的朋友啦~~~
具体的代码可以上我的GitHub上下载欢迎点星:
欢迎转载,请注明转载和原文出处:http://www.cnblogs.com/windsSunShine/p/4986234.html
给我一个及时的问候——XMPP的更多相关文章
- XMPP iOS客户端实现三:登录、注册
1.创建一个单例模式来管理xmpp的连接和操作 +(XMPPManager *)share { static XMPPManager *_share=nil; static dispatch_once ...
- SIP vs XMPP
sip和xmpp都是应用层的协议,主要用来在互联网上发送语音和即时通讯IM,rfc3521定义了sip,rfc3920定义了xmpp.xmpp来自即时通讯系统,sip类似语音和视频通信. xmpp协议 ...
- TCP/IP,Http,Socket,XMPP的区别
大学学习网络基础的时候老师讲过,网络由下往上分为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层.通过初步的了解,我知道IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用 ...
- 基于XMPP协议的手机多方多端即时通讯方案
一.开发背景 1.国际背景 随着Internet技术的高速发展,即时通信已经成为一种广泛使用的通信方式.1996年Mirabilis公司推出了世界上第一个即时通信系统ICQ,不到10年间,即时通信(I ...
- 基于XMPP的即时通信系统的建立(二)— XMPP详解
XMPP详解 XMPP(eXtensible Messaging and Presence Protocol,可扩展消息处理和现场协议)是一种在两个地点间传递小型结构化数据的协议.在此基础上,XMPP ...
- 转:XMPP协议、MQTT协议、HTTP协议、CoAP协议的基本比较
一.先看下相关国外的专业数据对四大协议的比较: Protocol CoAP XMP ...
- iOS开发——网络编程OC篇&(一)XMPP简单介绍与准备
XMPP简单介绍与准备 一.即时通讯简单介绍 1.简单说明 即时通讯技术(IM)支持用户在线实时交谈.如果要发送一条信息,用户需要打开一个小窗口,以便让用户及其朋友在其中输入信息并让交谈双方都看到交谈 ...
- XMPP协议的基本理解
即时通讯技术简介 即时通讯技术(IM)支持用户在线实时交谈.如果要发送一条信息,用户需要打开一个小窗口,以便让用户及其朋友在其中输入信息并让交谈双方都看到交谈的内容.大多数常用的即时通讯发送程序都会提 ...
- 即时通讯协议之XMPP
目前IM即时通信有四种协议 1.即时信息和空间协议(IMPP) 2.空间和即时信息协议(PRIM) 3.针对即时通讯和空间平衡扩充的进程开始协议SIP 4.XMPP协议: 该协议的前身是Jabber, ...
随机推荐
- Unity3D 中 Generic 动画导入设置和 Root Motion 之间的关系
2条评论 Unity3D 的 Mecanim 动画系统可以直接复用 3DS MAX 中制作的动画文件中的位移,这个就是通过 applyRootMotion 来达成的,我们只需要在使用 Animator ...
- p2p研究
p2p网络结构 中央集中式结构 无集中式非结构 混合式以超级节点结构 穿透原理 防火墙为克隆型(cone net),对称型(Symmetric NAT) 只有克隆型才能用打洞方式穿透 开源方案 htt ...
- Malek Dance Club(递推)
Malek Dance Club time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- [原]如何用Android NDK编译FFmpeg
我们知道在Ubuntu下直接编译FFmpeg是很简单的,主要是先执行./configure,接着执行make命令来编译,完了紧接着执行make install执行安装.那么如何使用Android的ND ...
- Using HiveServer2 - Authentication
To configure Hive for use with HiveServer2, include the following configuration properties in the .. ...
- Fireasy新版本发布
1.5.40.42028 2015-2-4 ** Fireasy.Common 1.DynamicBuilder新增使用表达式SetCustomAttribute的重载方法 2.DateTimeEx ...
- [转] C#反射设置属性值和获取属性值
/// /// 获取类中的属性值 /// /// /// /// public string GetModelValue(string FieldName, object obj) { try { T ...
- Knockout 新版应用开发教程之"text"绑定
目的 DOM元素显示文本的值是你传递的参数,前提是text先绑定到该元素上 典型的常用元素 <span>或者<em>习惯性的用来显示文本,但是在技术上来说你可以用任何元素的. ...
- 前端模块化:RequireJS
前言 前端模块化能解决什么问题? 模块的版本管理 提高可维护性 -- 通过模块化,可以让每个文件职责单一,非常有利于代码的维护 按需加载 -- 提高显示效率 更好的依赖处理 -- 传统的开发模式,如果 ...
- 开发者讨厌你API的十个原因
PS:原文是PDF(E文),原书名称:10ReasonsWhyDevelopersHateYourAPI 1.文档的吸引力太弱 解决之道 采用大图片:示例站点 文档清晰度:示例站点 文档易于查找:示例 ...