一、导入XMPP框架

  1. 下载 XMPPFramework 框架

    GitHub: XMPPFramework

  2. 导入依赖框架

    • CocoaLumberjack : 日志框架

    • CocoaAsyncSocket : 底层网络框架
      需要添加 CFNetwork & Security 框架依赖(XCode 6+ 无需导入)

    • KissXML : XML解析框架
      需要添加libxml2.dylib框架依赖
      需要指定如下编译选项:
      Other Linker Flags = -lxml2
      Header Search Paths = /usr/include/libxml2

    • libidn

  3. 导入一下文件夹

    • Authentication
    • Categories
    • Core
    • Utilities
    • 添加依赖:libresolv.dylib
  4. 导入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是面向模块的,每一个大的动能都属于某一个模块,需要使用时,就在头文件中将其暴露出来(原本是被注释了的)。

  1. 工作原理:

    添加用户信息模块之后,XMPPFramework框架会自动从服务器获取用户信息,并使用CoreData保存到本地的数据库中,使用XMPPvCardTempModule可以访问数据

  2. XMPPFramework.h中将以下的头文件前面的注释去掉:

    // 电子名片模块
    #import "XMPPvCardTempModule.h"
    #import "XMPPvCardCoreDataStorage.h" // 头像模块
    #import "XMPPvCardAvatarModule.h"
  3. 初始化模块

    //添加电子名片模块
    _vCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
    _vCard = [[XMPPvCardTempModule alloc] initWithvCardStorage:_vCardStorage]; //激活
    [_vCard activate:_xmppStream]; //添加头像模块
    _avatar = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_vCard];
    [_avatar activate:_xmppStream];

      

  4. 应用

    //xmpp提供了一个方法,直接获取个人信息
    XMPPvCardTemp *myVCard =[WCXMPPTool sharedWCXMPPTool].vCard.myvCardTemp; // 设置头像
    if(myVCard.photo){
    self.haedView.image = [UIImage imageWithData:myVCard.photo];
    } // 设置昵称
    self.nicknameLabel.text = myVCard.nickname;

      

五、好友

与用户信息模块相似,添加相应的好友花名册模块即可。

  1. 头文件

    // 花名册模块
    #import "XMPPRoster.h"
    #import "XMPPRosterCoreDataStorage.h"
  2. 初始化

    // 添加花名册模块【获取好友列表】
    _rosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
    _roster = [[XMPPRoster alloc] initWithRosterStorage:_rosterStorage];
    [_roster activate:_xmppStream];

      

  3. 应用

    //使用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并设置代理,如果数据库的内容发生了变化,这个类会自动通知代理,就可以设置界面的数据,做到实时更新。

六、消息

  1. 头文件

    • 注意:这几个头文件没在XMPPFramework.h文件中,需要自己添加
    // 消息模块
    #import "XMPPMessageArchiving.h"
    #import "XMPPMessageArchivingCoreDataStorage.h"
  2. 初始化

    // 添加聊天模块
    _msgStorage = [[XMPPMessageArchivingCoreDataStorage alloc] init];
    _msgArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:_msgStorage];
    [_msgArchiving activate:_xmppStream];

      

  3. 应用

    // 上下文
    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);
    }

      

七、文件传送(图片,音频)

  1. 原理分析

    • 使用base64将文件转化为字符串,然后再通过XMPPFramework传输。
    • 先将文件上传到服务器,再将文件网址通过XMPPFramework转输给好友,好友收到后再自行下载文件。
  1. 难点解析

    • 需要给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#

上帝说:要约炮!于是有了XMPP的更多相关文章

  1. 技术笔记:XMPP之openfire+spark+smack

    在即时通信这个领域目前只找到一个XMPP协议,在其协议基础上还是有许多成熟的产品,而且是开源的.所以还是想在这个领域多多了解一下. XMPP协议:具体的概念我就不写了,毕竟这东西网上到处是.简单的说就 ...

  2. xmpp

    xmpp学习 下载: Openfire 服务器:Openfire 4.0.2 客户端:Spark 2.7.7 安装 Openfire安装: 根据提示一直下一步,服务器域名设置为:localhost(p ...

  3. iOS XMPP 通信协议实现 图形化直观感受

    第一次随笔,实在不知写点什么有用的东西,那就分享一下本人最近的研究所得吧! 是关于iOS-XMPP-通信协议的实现,具体代码比较复杂,三言两句也实在难表达清楚,网上已有很多关于iOS XMPP协议的讲 ...

  4. (转)C# XMPP客户端与openfire通信(Matrix Xmpp 授权破解教程)

    FROM:http://www.cnblogs.com/crabo/p/CRACK_MATRIX_XMPP.html 如此著名的XMPP , 居然试过jabber-net, agsXmpp,matri ...

  5. XMPP iOS客户端实现三:登录、注册

    1.创建一个单例模式来管理xmpp的连接和操作 +(XMPPManager *)share { static XMPPManager *_share=nil; static dispatch_once ...

  6. XMPP iOS客户端实现二:xcode项目配置

    1.下载XMPPFramework,下载地址:https://github.com/robbiehanson/XMPPFramework 2.创建项目并将XMPP库引入: 3.添加需要的库文件: 4. ...

  7. Openfire/XMPP学习之——一个简单的Smack样例

    昨天讲了Openfire的搭建和配置,今天来讲一下Smack.如果对如何搭建和配置Openfire的,可以参考Openfire/XMPP学习之——Openfire的安装.配置. Smack是一个开源, ...

  8. MAC下的XMPP环境搭建

    实现即时通信有多种方式,下面讲的是Mac下使用XMPP来实现. XML Messages Presence Protocol 可扩展消息处理协议 简单讲就是基于XML语言的点对点即时通信协议  原理: ...

  9. XMPP开发环境配置

    首先配置XMPP开发环境配置需要的软件 先安装xampp-osx-1.8.3-5-installer.dmg 安装成功后launchpad里会多出一个XAMPP(其他),点开里面的manager-os ...

随机推荐

  1. 2017西安网络赛B_Coin

    样例输入 2 2 1 1 3 1 2 样例输出 500000004 555555560 思路: n重伯努利实验概率分布题. 设q=1-p,p为事件概率. Y为出现偶数次的概率. 所以  Y=1/2*( ...

  2. hdu5924Mr. Frog’s Problem

    Mr. Frog's Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  3. 模拟 URAL 1149 Sinus Dances

    题目传送门 /* 模拟:找到规律分别输出就可以了,简单但是蛮有意思的 */ #include <cstdio> #include <algorithm> #include &l ...

  4. JSON使用讲解

    前端操作json  一.JSON字符串与JSON对象的区别 1. 一个对象以“{”  开始,     “}”结束.   每个“名称”后跟一个“:”(冒号):“‘名称/值’ 对”之间运用 “,”(逗号) ...

  5. STL---vector的内存分配策略

    2级策略,过程如下: 第一级 __malloc_alloc_template内存分配器 该分配器是对malloc.realloc以及free的封装: 第二级  __default_alloc_temp ...

  6. VMware workstation 14 CentOs 7.5.1804 虚拟机网卡设置为NAT模式并设置固定IP

    一.背景知识     虚拟机网络模式 无论是vmware workstation,virtual box,virtual pc等虚拟机软件,一般来说,虚拟机有三种网络模式: 1.桥接 2.NAT 3. ...

  7. [ HDOJ 3826 ] Squarefree number

    \(\\\) \(Description\) \(T\)组数据,每次给出一个正整数 \(N\) ,判断其是否能被任意一个完全平方数整除. \(T\le 20,N\le 10^{18}\) \(\\\) ...

  8. responsive-navigator

    html 代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...

  9. JavaScript(七)数组

    Array类型 1.创建数组 字面量 var arr = [];//不要在低版本的浏览其中创建字面量的时候最后 //一个item后面加 逗号 低版本会 再新建一个空的item 构造函数 var arr ...

  10. python自动化--语言基础一数据类型及类型转换

    Python中核心的数据类型有哪些?变量(数字.字符串.元组.列表.字典) 什么是数据的不可变性?哪些数据类型具有不可变性数据的不可变是指数据不可更改,比如: a = () #定义元组 #a[]= # ...