上帝说:要约炮!于是有了XMPP

一、导入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#
时间: 2024-10-14 03:17:42

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

问外好么就越团只

大将军的身后级法师上将军级刺客偏将军级牧师运粮将军级的狂战士隐藏进阶职业破冰战狂骁骑将一身的暗金器装备泛着暗金色光泽显然八百骑的王牌玩家就是他了一个隐藏职业的狂战士配合着一身的暗金器想必爆发力不可小觑点但是怪物多大概有十个左右如果不是我闪得快恐怕真的就要被秒了凌雪眨着眼睛说道 但是凌月的雪却隐藏着绝强的杀伤力下一刻突然一大片冰雪在血饮的人群中爆开顿时傲世狂人和傲世嗜血均是大惊失色忍不住道居然那么高的防御 刺客忙不迭的点头队长我知道了我稻花香此时绝对是最强的输出灵魂封印术和灵魂锁链两大王牌技能让很

Openfire分析之一:Openfire与XMPP协议

引言 上帝说,要有光,于是就有了光. 有点玄. 如果将时光回溯无数岁月,到几百万年的蛮荒时代,人类史上第一次发生信息交换,会是什么样子?是转一下脑袋,还是眨一下眼? 但不管是什么形式,于是有了信息,有了通信.而后几百万年的时代变迁物种生灭,以及后来古文明时代.封建社会.再到如今的互联网时代,不管是峰烟战火,还是市井喧嚣,都充斥着各式各样的信息,每个角落都无时无刻的发生着信息交换.信息交换的载体,从以前可能挥下手势.到如今全球高速网络信道-. 信息在这个世界里,扮演着一个什么样的角色,是人在控制信

风云寻炮网的注意事项

众所周知,风云寻炮网已经经历了五个春秋.为广大朋友提供了非常大的便利和服务. 一直以来受到很多朋友的支持.当然也有朋友说,我们的会员质量不高.都是些歪瓜裂枣.这话我是不赞同的.是的,我们的女会员,大多年岁偏大.甚至50岁的都有. 但是主力队伍都是三四十的,尤其是四十多的偏多.25以下的非常少.但是不要忘了,朋友们不是选老婆的.朋友们是来找娘们玩的.这样还为什么这么挑剔呢. 目前这样的服务,互联网只此一家.虽然屡受打击,但是依然存活.如果想很容易的邀请到女战友实战.劝君还是找年岁偏大的.大的欲望强

Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送

Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送,写这个系列真的很要命,你要去把他们的API文档大致的翻阅一遍,而且各种功能都实现一遍,解决各种bug各种坑,不得不说,极光推送真坑,大家使用还是要慎重,我们看一下极光推送的官网 https://www.jpush.cn/common/ 推送比较使用,很多软件有需要,所以在这个点拿出来多讲讲,我们本节

XMPP即时通讯

XMPP:XMPP是基于XML的点对点通讯协议,The Extensible Messaging and Presence Protocol(可扩展通讯和表示协议). XMPP可用于服务类实时通讯,表示和需求响应服务中的XML数据元流失传输.XMPP以Jabber协议为基础,而Jabber是即时通讯中常用的开放式协议. 基本结构. XML是一个典型的C/S架构,而不是像大多数即时通讯软件一样,使用P2P客户端到客户端的架构,也就是说在大多数情况下,当两个客户端进行通讯时,他们的消息都是通过服务器

风云寻炮网的最新链接

很多人由于不搜藏好风云寻炮网的更新邮件,导致链接更新后, 到处问别人,希望这类人做事用心点,举手之劳的时候不做,最后到处问别人. 目前的连接是  http://hyhws.cn由于躲避打击,有时候会更换连接.链接的更新邮件是  [email protected]

XMPP系列(四)---发送和接收文字消息,获取历史消息功能

今天开始做到最主要的功能发送和接收消息.获取本地历史数据. 先上到目前为止的效果图:              首先是要在XMPPFramework.h中引入数据存储模块: //聊天记录模块的导入 #import "XMPPMessageArchiving.h" #import "XMPPMessageArchivingCoreDataStorage.h" #import "XMPPMessageArchiving_Contact_CoreDataObje

没枪没炮 照样把网站推广好

记得中国以前的游击队就是在没枪没炮的情况,夺取战争的胜利,在今天激烈的网络竞争里,像我们这些小站长们,何尝不是又回到打游击战的时代呢?目前笔者就在打游击战!    对于小站长来说,要人没人,要钱没钱,要广告没广告,要什么就没什么,何尝不像当年的游击队呢?当年的中国游击队为什么能成功,凭什么成功呢?我们这些小站长应该多学习学习. 今天我们又重复着历史的脚步,在走着现代的脚步,自从笔者开始推广自己的博客后,又感觉回到了游击战时期,在大公司的话,肯定不需要打这样的游击战,但是在小公司里,这样的游击战是

TYVJ1716 上帝造题的七分钟

时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 裸体就意味着身体. 描述 “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵.第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作.第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作.第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围.第五分钟,和雪说,要有耐心,于是便有了时间限制.第六分钟,吃