XMPPFramework是一个OS X/iOS平台的开源项目,使用Objective-C实现了XMPP协议(RFC-3920),同时还提供了用于读写XML的工具,大大简化了基于XMPP的通信应用的开发。

1. 登录和好友上下线

1.1XMPP中常用对象们

  • XMPPStream:xmpp基础服务类

  • XMPPRoster:好友列表类

  • XMPPRosterCoreDataStorage:好友列表(用户账号)在core data中的操作类

  • XMPPvCardCoreDataStorage:好友名片(昵称,签名,性别,年龄等信息)在core data中的操作类

  • XMPPvCardTemp:好友名片实体类,从数据库里取出来的都是它

  • xmppvCardAvatarModule:好友头像

  • XMPPReconnect:如果失去连接,自动重连

  • XMPPRoom:提供多用户聊天支持

  • XMPPPubSub:发布订阅

1.2登录操作,也就是连接xmpp服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)connect {
    if (self.xmppStream == nil) {
        self.xmppStream = [[XMPPStream alloc] init];
        [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    if (![self.xmppStream isConnected]) {
        NSString *username = [[NSUserDefaults standardUserDefaults] objectForKey:@"username"];
        XMPPJID *jid = [XMPPJID jidWithUser:username domain:@"lizhen" resource:@"Ework"];
        [self.xmppStream setMyJID:jid];
        [self.xmppStream setHostName:@"10.4.125.113"];
        NSError *error = nil;
        if (![self.xmppStream connect:&error]) {
            NSLog(@"Connect Error: %@", [[error userInfo] description]);
        }
    }
}

connect成功之后会依次调用XMPPStreamDelegate的方法,首先调用

1
2
3
- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket
...

然后

1
- (void)xmppStreamDidConnect:(XMPPStream *)sender

在该方法下面需要使用xmppStream 的authenticateWithPassword方法进行密码验证,成功的话会响应delegate的方法,就是下面这个

1
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender

1.3上线

实现 - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender 委托方法

1
2
3
4
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
    [self.xmppStream sendElement:presence];
}

1.4退出并断开连接

1
2
3
4
5
6
- (void)disconnect {
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    [self.xmppStream sendElement:presence];
      
    [self.xmppStream disconnect];
}

1.5好友状态

获取好友状态,通过实现

1
2
3
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
...

方法,当接收到 presence 标签的内容时,XMPPFramework 框架回调该方法

一个 presence 标签的格式一般如下:

presence 的状态:

  • available 上线

  • away 离开

  • do not disturb 忙碌

  • unavailable 下线

1
2
3
4
5
6
7
8
9
10
11
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
    NSString *presenceType = [presence type];
    NSString *presenceFromUser = [[presence from] user];
    if (![presenceFromUser isEqualToString:[[sender myJID] user]]) {
        if ([presenceType isEqualToString:@"available"]) {
            //
        else if ([presenceType isEqualToString:@"unavailable"]) {
            //
        }
    }
}

2. 接收消息和发送消息

2.1接收消息

通过实现

1
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message;

方法

当接收到 message 标签的内容时,XMPPFramework 框架回调该方法

根据 XMPP 协议,消息体的内容存储在标签 body 内

1
2
3
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
    NSString *messageBody = [[message elementForName:@"body"] stringValue];
}

2.2发送消息

发送消息,我们需要根据 XMPP 协议,将数据放到标签内,例如:

1
2
3
4
5
6
7
8
9
10
- (void)sendMessage:(NSString *) message toUser:(NSString *) user {
    NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
    [body setStringValue:message];
    NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
    [message addAttributeWithName:@"type" stringValue:@"chat"];
    NSString *to = [NSString stringWithFormat:@"%@@example.com", user];
    [message addAttributeWithName:@"to" stringValue:to];
    [message addChild:body];
    [self.xmppStream sendElement:message];
}

3. 获取好友信息和删除好友

3.1好友列表和好友名片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[_xmppRoster fetchRoster];//获取好友列表
//获取到一个好友节点
- (void)xmppRoster:(XMPPRoster *)sender didRecieveRosterItem:(NSXMLElement *)item
//获取完好友列表
- (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender
//到服务器上请求联系人名片信息
- (void)fetchvCardTempForJID:(XMPPJID *)jid;
//请求联系人的名片,如果数据库有就不请求,没有就发送名片请求
- (void)fetchvCardTempForJID:(XMPPJID *)jid ignoreStorage:(BOOL)ignoreStorage;
//获取联系人的名片,如果数据库有就返回,没有返回空,并到服务器上抓取
- (XMPPvCardTemp *)vCardTempForJID:(XMPPJID *)jid shouldFetch:(BOOL)shouldFetch;
//更新自己的名片信息
- (void)updateMyvCardTemp:(XMPPvCardTemp *)vCardTemp;
//获取到一盒联系人的名片信息的回调
- (void)xmppvCardTempModule:(XMPPvCardTempModule *)vCardTempModule 
        didReceivevCardTemp:(XMPPvCardTemp *)vCardTemp 
                     forJID:(XMPPJID *)jid

3.2添加好友

1
2
3
4
5
6
7
8
9
    //name为用户账号
    - (void)XMPPAddFriendSubscribe:(NSString *)name
    {
        //XMPPHOST 就是服务器名,  主机名
        XMPPJID *jid = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@%@",name,XMPPHOST]];
        //[presence addAttributeWithName:@"subscription" stringValue:@"好友"];
        [xmppRoster subscribePresenceToUser:jid];
          
    }

3.3收到添加好友的请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    - (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
    {
        //取得好友状态
        NSString *presenceType = [NSString stringWithFormat:@"%@", [presence type]]; //online/offline
        //请求的用户
        NSString *presenceFromUser =[NSString stringWithFormat:@"%@", [[presence from] user]];
        NSLog(@"presenceType:%@",presenceType);
          
        NSLog(@"presence2:%@  sender2:%@",presence,sender);
          
        XMPPJID *jid = [XMPPJID jidWithString:presenceFromUser];
        //接收添加好友请求
        [xmppRoster acceptPresenceSubscriptionRequestFrom:jid andAddToRoster:YES];
          
    }

3.4删除好友

1
2
3
4
5
6
7
//删除好友,name为好友账号
- (void)removeBuddy:(NSString *)name  
{  
    XMPPJID *jid = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@%@",name,XMPPHOST]];  
        
    [self xmppRoster] removeUser:jid];  
}

4. 聊天室

初始化聊天室

1
2
3
4
5
6
    XMPPJID *roomJID = [XMPPJID jidWithString:ROOM_JID];
      
    xmppRoom = [[XMPPRoom alloc] initWithRoomStorage:self jid:roomJID];
      
    [xmppRoom activate:xmppStream];
    [xmppRoom addDelegate:self delegateQueue:dispatch_get_main_queue()];

创建聊天室成功

1
2
3
4
    - (void)xmppRoomDidCreate:(XMPPRoom *)sender
    {
        DDLogInfo(@"%@: %@", THIS_FILE, THIS_METHOD);
    }

加入聊天室,使用昵称

1
    [xmppRoom joinRoomUsingNickname:@"quack" history:nil];

获取聊天室信息

1
2
3
4
5
6
7
    - (void)xmppRoomDidJoin:(XMPPRoom *)sender
    {
        [xmppRoom fetchConfigurationForm];
        [xmppRoom fetchBanList];
        [xmppRoom fetchMembersList];
        [xmppRoom fetchModeratorsList];
    }

如果房间存在,会调用委托

1
2
3
4
5
6
    // 收到禁止名单列表
    - (void)xmppRoom:(XMPPRoom *)sender didFetchBanList:(NSArray *)items;
    // 收到好友名单列表
    - (void)xmppRoom:(XMPPRoom *)sender didFetchMembersList:(NSArray *)items;
    // 收到主持人名单列表
    - (void)xmppRoom:(XMPPRoom *)sender didFetchModeratorsList:(NSArray *)items;

房间不存在,调用委托

1
2
3
    - (void)xmppRoom:(XMPPRoom *)sender didNotFetchBanList:(XMPPIQ *)iqError;
    - (void)xmppRoom:(XMPPRoom *)sender didNotFetchMembersList:(XMPPIQ *)iqError;
    - (void)xmppRoom:(XMPPRoom *)sender didNotFetchModeratorsList:(XMPPIQ *)iqError;

离开房间

1
[xmppRoom deactivate:xmppStream];

XMPPRoomDelegate的其他代理方法:

离开聊天室

1
2
3
4
    - (void)xmppRoomDidLeave:(XMPPRoom *)sender
    {
        DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    }

新人加入群聊

1
2
3
4
    - (void)xmppRoom:(XMPPRoom *)sender occupantDidJoin:(XMPPJID *)occupantJID
    {
        DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    }

有人退出群聊

1
2
3
4
    - (void)xmppRoom:(XMPPRoom *)sender occupantDidLeave:(XMPPJID *)occupantJID
    {
        DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    }

有人在群里发言

1
2
3
4
    - (void)xmppRoom:(XMPPRoom *)sender didReceiveMessage:(XMPPMessage *)message fromOccupant:(XMPPJID *)occupantJID
    {
        DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
    }

5. 消息回执

这个是XEP-0184协议的内容

协议内容:

发送消息时附加回执请求

代码实现

1
2
3
4
5
6
7
    NSString *siID = [XMPPStream generateUUID];
    //发送消息
    XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:jid elementID:siID];
    NSXMLElement *receipt = [NSXMLElement elementWithName:@"request" xmlns:@"urn:xmpp:receipts"];
    [message addChild:receipt];
    [message addBody:@"测试"];
    [self.xmppStream sendElement:message];

收到回执请求的消息,发送回执

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
    {
        //回执判断
        NSXMLElement *request = [message elementForName:@"request"];
        if (request)
        {
            if ([request.xmlns isEqualToString:@"urn:xmpp:receipts"])//消息回执
            {
                //组装消息回执
                XMPPMessage *msg = [XMPPMessage messageWithType:[message attributeStringValueForName:@"type"] to:message.from elementID:[message attributeStringValueForName:@"id"]];
                NSXMLElement *recieved = [NSXMLElement elementWithName:@"received" xmlns:@"urn:xmpp:receipts"];
                [msg addChild:recieved];
                  
                //发送回执
                [self.xmppStream sendElement:msg];
            }
        }else
        {
            NSXMLElement *received = [message elementForName:@"received"];
            if (received)
            {
                if ([received.xmlns isEqualToString:@"urn:xmpp:receipts"])//消息回执
                {
                    //发送成功
                    NSLog(@"message send success!");
                }  
            }  
        }  
          
        //消息处理  
        //...  
    }

6. 添加AutoPing

为了监听服务器是否有效,增加心跳监听。用XEP-0199协议,在XMPPFrameWork框架下,封装了 XMPPAutoPing 和 XMPPPing两个类都可以使用,因为XMPPAutoPing已经组合进了XMPPPing类,所以XMPPAutoPing使用起来更方便。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//初始化并启动ping
-(void)autoPingProxyServer:(NSString*)strProxyServer
{
    _xmppAutoPing = [[XMPPAutoPingalloc] init];
    [_xmppAutoPingactivate:_xmppStream];
    [_xmppAutoPingaddDelegate:selfdelegateQueue:  dispatch_get_main_queue()];
    _xmppAutoPing.respondsToQueries = YES;
    _xmppAutoPing.pingInterval=2;//ping 间隔时间
    if (nil != strProxyServer)
    {
       _xmppAutoPing.targetJID = [XMPPJID jidWithString: strProxyServer ];//设置ping目标服务器,如果为nil,则监听socketstream当前连接上的那个服务器
    }
}
//卸载监听
 [_xmppAutoPing   deactivate];
  [_xmppAutoPing   removeDelegate:self];
   _xmppAutoPing = nil;
//ping XMPPAutoPingDelegate的委托方法:
- (void)xmppAutoPingDidSendPing:(XMPPAutoPing *)sender
{
    NSLog(@"- (void)xmppAutoPingDidSendPing:(XMPPAutoPing *)sender");
}
- (void)xmppAutoPingDidReceivePong:(XMPPAutoPing *)sender
{
    NSLog(@"- (void)xmppAutoPingDidReceivePong:(XMPPAutoPing *)sender");
}
   
- (void)xmppAutoPingDidTimeout:(XMPPAutoPing *)sender
{
    NSLog(@"- (void)xmppAutoPingDidTimeout:(XMPPAutoPing *)sender");
}

转载于:https://www.cnblogs.com/fengmin/p/4973848.html

iOS 的 XMPPFramework 简介相关推荐

  1. iOS 版 MWeb 简介— Markdown 编辑利器

    原文地址:http://zh.mweb.im/introducing-mweb-for-ios.html MWeb 首先是一个 Markdown 编辑器,所使用的 Markdown 语法为 Githu ...

  2. iOS手势操作简介(三)

    监听触摸事件的做法 如果想监听一个view上面的触摸事件,之前的做法是 自定义一个view 实现view的touches方法,在方法内部实现具体处理代码 通过touches方法监听view触摸事件,有 ...

  3. iOS手势操作简介(一)

    iOS中能够响应手势操作的类必须要继承自UIResponder,才能够处理手势响应操作. 默认继承了UIResponder的类有:UIApplication UIViewController UIVi ...

  4. iOS 模拟器(Simulator) 简介

    1. 硬件方面的区别 部分硬件功能在模拟器上并不支持,如下 陀螺仪.加速计 音频,视频输入 近物体传感器 气压计 光感器 2. OpenGL ES的区别 模拟器已经实现了 OpenGL ES 1.1, ...

  5. 【Xamarin.iOS】tvOS简介

    最近,苹果公司宣布推出AppleTV 4K,这是2015年推出的AppleTV的改进版本,为我们带来了一个在tvOS上开发的新平台. 借助支持触摸的Siri遥控器,我们有了一种与大屏幕上的应用程序进行 ...

  6. iOS - GATT Profile 简介

    1.引言 现在低功耗蓝牙(BLE)连接都是建立在 GATT (Generic Attribute Profile) 协议之上.GATT 是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范,这些很短 ...

  7. Apple iOS MDM service 简介

    2019独角兽企业重金招聘Python工程师标准>>> 转载:http://blog.nienyiho.com/apple-ios-mdm-service-introduction/ ...

  8. iOS Universal Link 简介

    一.什么是Universal Link Universal Link(通用链接)是什么,相信iOS开发的同学一定对这个东西非常熟悉.这是Apple在iOS9推出的一种能通过HTTPS链接直接启动手机A ...

  9. ios的Framework简介

    Framework 简介 Mac OS X 扩展了 framework 的功能,让我们能够利用它来共享代码和资源.framework 在概念上有点像 Window 下的库,但是比库更加强大,通过 fr ...

最新文章

  1. 「镁客·请讲」NOLO VR张道宁:空间定位技术加持下的VR,是可以搞出商业价值的...
  2. ubuntu c/c++ IDE编程环境
  3. 【联盛德W806上手笔记】一、开发环境和烧录程序
  4. jQuery插件_SuperSlide插件(焦点图切换、标签切换、多个slide组合)
  5. Android 更新UI的两种方法——handler和runOnUiThread()
  6. QQ自动登录 发消息给某人C++/C
  7. cmd 复制文件语法不正确
  8. 解决 jq ui 弹框 select2 input 失效问题
  9. PCB正片和负片的区别与使用
  10. red linux更换显卡,转:Linux(centos6.0/redhat) 安装 ATI / Nvidia 显卡驱动
  11. 汉诺塔怎么加计数次数c语言,C语言算汉诺塔,递归时的输出是怎么一步一步来的?如图,求大神帮忙...
  12. 诚诚富众选择投资理财产品
  13. Java使用cookie和session管理用户状态
  14. 搭建p2p文件服务器,linux 搭建 p2p 服务器
  15. VHDL硬件描述语言(五)VHDL的顺序语句
  16. 【时序】Informer:用于长序列预测的高效 Transformer 论文笔记
  17. java8安装包打不开_Win7系统下安装JDK提示“无法打开此安装包请确认该程序包存在”怎么办?...
  18. 中国石油大学(北京)-《石油加工工程》第二阶段在线作业
  19. Spring Boot 热部署(热加载)
  20. 华为畅享20和华为畅享z哪个好

热门文章

  1. 卷积神经网络(高级篇) Inception Moudel
  2. 处理相对时间(Day.js、Moment.js)(案例:结合vue的过滤器使用)
  3. LeetCode MySQL 178. 分数排名(dense_rank连续排名)
  4. LeetCode 366. 寻找二叉树的叶子节点(上下翻转二叉树+BFS)
  5. LeetCode 466. 统计重复个数(循环节)
  6. LeetCode 58. 最后一个单词的长度
  7. LeetCode 297. 二叉树的序列化与反序列化(前序遍历层序遍历)
  8. mysql 连接 内存溢出_mysql - MySQL中止连接未知错误 - 堆栈内存溢出
  9. mysql 坚向变横向_(排班表一)使用SQL语句使数据从坚向排列转化成横向排列
  10. 基坑监测日报模板_基坑监测有多重要?实录基坑坍塌过程,不亲身经历,不知道现场有多恐怖!...