一、导入XMPP框架
- 下载
XMPPFramework
框架GitHub: XMPPFramework
- 导入依赖框架
CocoaLumberjack
: 日志框架CocoaAsyncSocket
: 底层网络框架
需要添加CFNetwork
&Security
框架依赖(XCode 6+ 无需导入)KissXML
: XML解析框架
需要添加libxml2.dylib
框架依赖
需要指定如下编译选项:
Other Linker Flags = -lxml2
Header Search Paths = /usr/include/libxml2libidn
- 导入一下文件夹
Authentication
Categories
Core
Utilities
- 添加依赖:
libresolv.dylib
- 导入XMPP扩展框架
Extensions
文件夹- 导入
Sample_XMPPFramework.h
并更名为:XMPPFramework.h
- 添加PCH文件:
Add New File
->Other
->PCH文件
- 添加
#import<UIKit/UIKit.h>
到PCH文件中 - 设置编译选项,
Build Settings
->Precompile prefix Header
选择Yes
- 设置编译选项,
Build Settings
->Prefix Header
设置PCH文件名:“项目名/“PCH文件名”
二、登录 & 注销
实现用户登录的步骤如下:
1. 实例化XMPPStream并设置代理,同时添加代理到工作队列
2. 使用JID连接至服务器,默认端口为5222,JID字符串中需要包含服务器的域名
3. 在完成连接的代理方法中验证用户密码,连接完成后XMPPStream的isConnect属性为YES
4. 在验证代理方法中判断用户是否登录成功
5. 上线或者下线成功后,向服务器发送Presence数据,以更新用户在服务器的状态
各部分的实现代码如下:
- 初始化
XMPPStream
并设置代理:-(void)setupXMPPStream{ _xmppStream = [[XMPPStream alloc] init]; // 设置代理 [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; }
- 连接到服务器
-(void)connectToHost{ NSLog(@"开始连接到服务器"); if (!_xmppStream) { [self setupXMPPStream]; } // 设置登录用户JID //resource 标识用户登录的客户端 iphone android XMPPJID *myJID = [XMPPJID jidWithUser:@"aaa" domain:@"bourne-mbp.local" resource:@"iphone" ]; _xmppStream.myJID = myJID; // 设置服务器域名 _xmppStream.hostName = @"bourne-mbp.local";//不仅可以是域名,还可是IP地址 // 设置端口 如果服务器端口是5222,可以省略 _xmppStream.hostPort = 5222; // 连接 NSError *err = nil; if(![_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&err]){ NSLog(@"%@",err); } }
- 连接成功后发送密码验证
-(void)sendPwdToHost{ NSLog(@"再发送密码授权"); NSError *err = nil; [_xmppStream authenticateWithPassword:@"123456" error:&err]; if (err) { NSLog(@"%@",err); } }
- 授权成功后,发送
在线
消息#pragma mark 授权成功后,发送"在线" 消息
-(void)sendOnlineToHost{ NSLog(@"发送 在线 消息"); XMPPPresence *presence = [XMPPPresence presence]; NSLog(@"%@",presence); [_xmppStream sendElement:presence]; }
需要实现的几个代理方法
#pragma mark 与主机连接成功
-(void)xmppStreamDidConnect:(XMPPStream *)sender{ NSLog(@"与主机连接成功"); // 主机连接成功后,发送密码进行授权 [self sendPwdToHost]; }
#pragma mark 与主机断开连接 -(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error{ // 如果有错误,代表连接失败 NSLog(@"与主机断开连接 %@",error); } #pragma mark 授权成功 -(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{ NSLog(@"授权成功"); [self sendOnlineToHost]; } #pragma mark 授权失败 -(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{ NSLog(@"授权失败 %@",error); }
注销登录
- 发送
离线
信息 - 断开连接
-(void)logout{ // 1." 发送 `离线` 消息" XMPPPresence *offline = [XMPPPresence presenceWithType:@"unavailable"]; [_xmppStream sendElement:offline]; // 2. 与服务器断开连接 [_xmppStream disconnect]; }
三、注册
- 与登录一样,首先发送帐号建立连接
- 连接成功后,发送注册的密码
- 注册成功后,框架会通知代理
实现以下代理方法
- (void)xmppStreamDidRegister:(XMPPStream *)sender { NSLog(@"注册成功"); if (_resultBlock) { _resultBlock(BWXMPPLoginResultSuccessed); } } - (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error { if (_resultBlock) { _resultBlock(BWXMPPLoginResultFailure); } }
四、用户信息
XMPP是面向模块的,每一个大的动能都属于某一个模块,需要使用时,就在头文件中将其暴露出来(原本是被注释了的)。
- 工作原理:
添加用户信息模块之后,
XMPPFramework框架
会自动从服务器获取用户信息,并使用CoreData
保存到本地的数据库中,使用XMPPvCardTempModule
可以访问数据 - 在
XMPPFramework.h
中将以下的头文件前面的注释去掉:// 电子名片模块 #import "XMPPvCardTempModule.h" #import "XMPPvCardCoreDataStorage.h" // 头像模块 #import "XMPPvCardAvatarModule.h"
- 初始化模块
//添加电子名片模块 _vCardStorage = [XMPPvCardCoreDataStorage sharedInstance]; _vCard = [[XMPPvCardTempModule alloc] initWithvCardStorage:_vCardStorage]; //激活 [_vCard activate:_xmppStream]; //添加头像模块 _avatar = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_vCard]; [_avatar activate:_xmppStream];
- 应用
//xmpp提供了一个方法,直接获取个人信息 XMPPvCardTemp *myVCard =[WCXMPPTool sharedWCXMPPTool].vCard.myvCardTemp; // 设置头像 if(myVCard.photo){ self.haedView.image = [UIImage imageWithData:myVCard.photo]; } // 设置昵称 self.nicknameLabel.text = myVCard.nickname;
五、好友
与用户信息模块相似,添加相应的好友花名册模块即可。
- 头文件
// 花名册模块 #import "XMPPRoster.h" #import "XMPPRosterCoreDataStorage.h"
- 初始化
// 添加花名册模块【获取好友列表】 _rosterStorage = [[XMPPRosterCoreDataStorage alloc] init]; _roster = [[XMPPRoster alloc] initWithRosterStorage:_rosterStorage]; [_roster activate:_xmppStream];
- 应用
//使用CoreData获取数据 // 1.上下文【关联到数据库XMPPRoster.sqlite】 NSManagedObjectContext *context = [WCXMPPTool sharedWCXMPPTool].rosterStorage.mainThreadManagedObjectContext; // 2.FetchRequest【查哪张表】 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"XMPPUserCoreDataStorageObject"]; // 3.设置过滤和排序 // 过滤当前登录用户的好友 NSString *jid = [WCUserInfo sharedWCUserInfo].jid; NSPredicate *pre = [NSPredicate predicateWithFormat:@"streamBareJidStr = %@",jid]; request.predicate = pre; //排序 NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"displayName" ascending:YES]; request.sortDescriptors = @[sort]; // 4.执行请求获取数据 _resultsContrl = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; _resultsContrl.delegate = self; NSError *err = nil; [_resultsContrl performFetch:&err]; if (err) { WCLog(@"%@",err); }
- 注意:使用
NSFetchedResultsController
并设置代理,如果数据库的内容发生了变化,这个类会自动通知代理,就可以设置界面的数据,做到实时更新。
- 注意:使用
六、消息
- 头文件
- 注意:这几个头文件没在
XMPPFramework.h
文件中,需要自己添加
// 消息模块 #import "XMPPMessageArchiving.h" #import "XMPPMessageArchivingCoreDataStorage.h"
- 注意:这几个头文件没在
- 初始化
// 添加聊天模块 _msgStorage = [[XMPPMessageArchivingCoreDataStorage alloc] init]; _msgArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:_msgStorage]; [_msgArchiving activate:_xmppStream];
- 应用
// 上下文 NSManagedObjectContext *context = [WCXMPPTool sharedWCXMPPTool].msgStorage.mainThreadManagedObjectContext; // 请求对象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"XMPPMessageArchiving_Message_CoreDataObject"]; // 过滤、排序 // 1.当前登录用户的JID的消息 // 2.好友的Jid的消息 NSPredicate *pre = [NSPredicate predicateWithFormat:@"streamBareJidStr = %@ AND bareJidStr = %@",[WCUserInfo sharedWCUserInfo].jid,self.friendJid.bare]; NSLog(@"%@",pre); request.predicate = pre; // 时间升序 NSSortDescriptor *timeSort = [NSSortDescriptor sortDescriptorWithKey:@"timestamp" ascending:YES]; request.sortDescriptors = @[timeSort]; // 查询 _resultsContr = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; NSError *err = nil; // 代理 _resultsContr.delegate = self; [_resultsContr performFetch:&err]; NSLog(@"%@",_resultsContr.fetchedObjects); if (err) { WCLog(@"%@",err); }
七、文件传送(图片,音频)
- 原理分析
- 使用
base64
将文件转化为字符串,然后再通过XMPPFramework
传输。 - 先将文件上传到服务器,再将文件网址通过
XMPPFramework
转输给好友,好友收到后再自行下载文件。
- 使用
- 难点解析
- 需要给
XMPPFramework
的``数据体添加一个信息类型字段。
XMPPMessage *msg = [XMPPMessage messageWithType:@"chat" to:self.friendJid]; //text 纯文本 //image 图片 [msg addAttributeWithName:@"bodyType" stringValue:bodyType]; // 设置内容 [msg addBody:text]; NSLog(@"%@",msg); [[WCXMPPTool sharedWCXMPPTool].xmppStream sendElement:msg];
- 根据消息类型解析消息
```objc
XMPPMessageArchiving_Message_CoreDataObject *msg = _resultsContr.fetchedObjects[indexPath.row]; // 判断是图片还是纯文本 NSString *chatType = [msg.message attributeStringValueForName:@"bodyType"]; if ([chatType isEqualToString:@"image"]) { //下图片显示 [cell.imageView sd_setImageWithURL:[NSURL URLWithString:msg.body] placeholderImage:[UIImage imageNamed:@"DefaultProfileHead_qq"]]; cell.textLabel.text = nil; } else if ([chatType isEqualToString:@"text"]){ //显示消息 if ([msg.outgoing boolValue]) {//自己发 cell.textLabel.text = msg.body; }else{//别人发的 cell.textLabel.text = msg.body; } cell.imageView.image = nil; }
- 需要给
```
声明:
以上内容转自:
http://www.jianshu.com/p/c7bbbad90639#
时间: 2024-10-14 03:17:42