欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS的XMPPFramework简单介绍(实现及时通信)

程序员文章站 2024-02-12 22:15:40
xmppframework是一个os x/ios平台的开源项目,使用objective-c实现了xmpp协议(rfc-3920),同时还提供了用于读写xml的工具,大大简化...

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服务器

- (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的方法,首先调用

- (void)xmppstream:(xmppstream *)sender socketdidconnect:(gcdasyncsocket *)socket

然后

- (void)xmppstreamdidconnect:(xmppstream *)sender

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

- (void)xmppstreamdidauthenticate:(xmppstream *)sender

1.3上线

实现 - (void)xmppstreamdidauthenticate:(xmppstream *)sender 委托方法

- (void)xmppstreamdidauthenticate:(xmppstream *)sender {
  xmpppresence *presence = [xmpppresence presencewithtype:@"available"];
  [self.xmppstream sendelement:presence];
}

1.4退出并断开连接

- (void)disconnect {
  xmpppresence *presence = [xmpppresence presencewithtype:@"unavailable"];
  [self.xmppstream sendelement:presence];
   
  [self.xmppstream disconnect];
}

1.5好友状态

获取好友状态,通过实现

- (void)xmppstream:(xmppstream *)sender didreceivepresence:(xmpppresence *)presence
 
...

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

一个 presence 标签的格式一般如下:
iOS的XMPPFramework简单介绍(实现及时通信)

presence 的状态:

  • available 上线
  • away 离开
  • do not disturb 忙碌
  • unavailable 下线
- (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接收消息

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

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

- (void)xmppstream:(xmppstream *)sender didreceivemessage:(xmppmessage *)message {
  nsstring *messagebody = [[message elementforname:@"body"] stringvalue];
}

2.2发送消息
发送消息,我们需要根据 xmpp 协议,将数据放到标签内,例如:iOS的XMPPFramework简单介绍(实现及时通信)

- (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好友列表和好友名片

[_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添加好友

 //name为用户账号
  - (void)xmppaddfriendsubscribe:(nsstring *)name
  {
    //xmpphost 就是服务器名, 主机名
    xmppjid *jid = [xmppjid jidwithstring:[nsstring stringwithformat:@"%@@%@",name,xmpphost]];
    //[presence addattributewithname:@"subscription" stringvalue:@"好友"];
    [xmpproster subscribepresencetouser:jid];
     
  }

3.3收到添加好友的请求

 - (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删除好友

//删除好友,name为好友账号
- (void)removebuddy:(nsstring *)name 
{ 
  xmppjid *jid = [xmppjid jidwithstring:[nsstring stringwithformat:@"%@@%@",name,xmpphost]]; 
    
  [self xmpproster] removeuser:jid]; 
}

4. 聊天室

初始化聊天室

xmppjid *roomjid = [xmppjid jidwithstring:room_jid];
   
  xmpproom = [[xmpproom alloc] initwithroomstorage:self jid:roomjid];
   
  [xmpproom activate:xmppstream];
  [xmpproom adddelegate:self delegatequeue:dispatch_get_main_queue()];

创建聊天室成功

- (void)xmpproomdidcreate:(xmpproom *)sender
  {
    ddloginfo(@"%@: %@", this_file, this_method);
  }

加入聊天室,使用昵称

 [xmpproom joinroomusingnickname:@"quack" history:nil];

获取聊天室信息

  - (void)xmpproomdidjoin:(xmpproom *)sender
  {
    [xmpproom fetchconfigurationform];
    [xmpproom fetchbanlist];
    [xmpproom fetchmemberslist];
    [xmpproom fetchmoderatorslist];
  }

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

 // 收到禁止名单列表
  - (void)xmpproom:(xmpproom *)sender didfetchbanlist:(nsarray *)items;
  // 收到好友名单列表
  - (void)xmpproom:(xmpproom *)sender didfetchmemberslist:(nsarray *)items;
  // 收到主持人名单列表
  - (void)xmpproom:(xmpproom *)sender didfetchmoderatorslist:(nsarray *)items;

房间不存在,调用委托

 - (void)xmpproom:(xmpproom *)sender didnotfetchbanlist:(xmppiq *)iqerror;
  - (void)xmpproom:(xmpproom *)sender didnotfetchmemberslist:(xmppiq *)iqerror;
  - (void)xmpproom:(xmpproom *)sender didnotfetchmoderatorslist:(xmppiq *)iqerror;

离开房间

[xmpproom deactivate:xmppstream];

xmpproomdelegate的其他代理方法:

离开聊天室

 - (void)xmpproomdidleave:(xmpproom *)sender
  {
    ddlogverbose(@"%@: %@", this_file, this_method);
  }

新人加入群聊

 - (void)xmpproom:(xmpproom *)sender occupantdidjoin:(xmppjid *)occupantjid
  {
    ddlogverbose(@"%@: %@", this_file, this_method);
  }

有人退出群聊

 - (void)xmpproom:(xmpproom *)sender occupantdidleave:(xmppjid *)occupantjid
  {
    ddlogverbose(@"%@: %@", this_file, this_method);
  }

有人在群里发言

 - (void)xmpproom:(xmpproom *)sender didreceivemessage:(xmppmessage *)message fromoccupant:(xmppjid *)occupantjid
  {
    ddlogverbose(@"%@: %@", this_file, this_method);
  }

5. 消息回执

这个是xep-0184协议的内容。协议内容:

发送消息时附加回执请求
iOS的XMPPFramework简单介绍(实现及时通信)

代码实现

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];

收到回执请求的消息,发送回执
iOS的XMPPFramework简单介绍(实现及时通信)

代码实现

 - (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使用起来更方便。

//初始化并启动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");
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。