XMPPFramework 框架

    xiaoxiao2021-04-17  37

    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://ju.6miu.com/read-673714.html

    最新回复(0)