zoukankan      html  css  js  c++  java
  • 上帝说:要约炮!于是有了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#
  • 相关阅读:
    Windows Azure 网站开发Stacks支持
    AzureDev 社区活动获奖者公布
    Android 改变窗口标题栏的布局
    cocos2d-x游戏开发系列教程-超级玛丽01-前言
    cocos2dx进阶学习之CCObject
    基于visual Studio2013解决算法导论之055拓扑排序
    查看某文件夹内文件大小
    vmstat命令
    uname 命令
    iostat命令
  • 原文地址:https://www.cnblogs.com/likun123/p/4427871.html
Copyright © 2011-2022 走看看