当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS的XMPPFramework简单介绍(实现及时通信)

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

2019年07月24日  | 移动技术网移动技术  | 我要评论

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 标签的格式一般如下:

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 协议,将数据放到标签内,例如:

- (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协议的内容。协议内容:

发送消息时附加回执请求

代码实现

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

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

代码实现

 - (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");
}

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网