zoukankan      html  css  js  c++  java
  • iOS中 XMPP即时通讯实现的主要步骤

    这里只是列出实现的只要步骤,不是全部代码。

    首先导入XMPPFramework,及相关配置,完成后开始。

    创建一个XMPPHelper  类来管理要进行的操作。

    XMPPHelper.h文件如下

     1 typedef void(^loginSuccessBlock)(void);
     2 typedef void(^loginFailBlock)(NSString *info);
     3 typedef void(^fenchFridendList)(id result);
     4 typedef void(^logoutSuccessBlock)(void);
     5 typedef void(^registerSuccessBlock)(void);
     6 typedef enum {
     7     kTypeLogin,
     8     kTypeRegister
     9 }ConnectType;
    10 #import <Foundation/Foundation.h>
    11 #define kXMPPHosetName @"lala"
    12 #define kXMPPHostAddress @"192.168.13.17"
    13 #define kHostPort 5222
    14 
    15 @interface XMPPHelper : NSObject
    16 {
    17 
    18     ConnectType _connectType;
    19 
    20 }
    21 @property(nonatomic,strong)XMPPStream *stream;
    22 @property(nonatomic,strong)XMPPRoster *roster;
    23 @property(nonatomic,copy)NSString *username;
    24 @property(nonatomic,copy)NSString *password;
    25 
    26 @property(nonatomic,copy)loginSuccessBlock loginSuccessBlock;
    27 @property(nonatomic,copy)loginFailBlock loginFailBlock;
    28 @property(nonatomic,copy)fenchFridendList fenchFriendList;
    29 @property(nonatomic,copy)logoutSuccessBlock logoutSuccessBlock;
    30 @property(nonatomic,copy)registerSuccessBlock registerSuccessblock;
    31 
    32 +(instancetype)shareInstance;
    33 //登陆
    34 -(void)login:(NSString *)username password:(NSString *)password loginSuccessBlock:(loginSuccessBlock)block loginFailBlock:(loginFailBlock)failBlcok;
    35 //获取好友列表
    36 -(void)loadFriendList:(fenchFridendList)fenchfriendList;
    37 //发送消息
    38 -(void)sendMessage:(NSString *)message toUser:(NSString *)jid;
    39 //注销
    40 -(void)logoutAction:(logoutSuccessBlock)block;
    41 //注册
    42 -(void)registerAction:(NSString *)username password:(NSString *)password registerSuccessBlock:(registerSuccessBlock)registerBlock;
    43 
    44 @end

    XMPPHelper.m文件如下

    #define kHostAddress @"192.168.13.12"
    #define kHostName @"zy"
    #define KHostPort 5222
    #import "XMPPHelper.h"
    #import "User.h"
    
    
    static XMPPHelper *helper = nil;
    @interface XMPPHelper() <XMPPStreamDelegate>{
        ConnectTyep _connectType;
    }
    @end
    @implementation XMPPHelper
    
    //单例
    + (instancetype) shareInstance {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            helper = [[XMPPHelper alloc] init];
            [helper _stepXMPPHelper];
        });
        return helper;
    }
    
    //初始化的操作
    - (void) _stepXMPPHelper {
        //初始化流对象.
        self.stream = [[XMPPStream alloc] init];
        //创建自动连接的对象,当意外断开的时候,可以进行自动连接.
        XMPPReconnect *reConnect = [[XMPPReconnect alloc] init];
        
        //初始化花名册对象(好友列表)
        //存储方式.
        XMPPRosterCoreDataStorage *storage = [[XMPPRosterCoreDataStorage alloc] init];
        self.roster = [[XMPPRoster alloc] initWithRosterStorage:storage];
        
        //建立对象之间的联系
        //激活.
        [reConnect activate:self.stream];
        //激活,使用花名册对象.
        [self.roster activate:self.stream];
        
        //设置代理;
        [self.stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
        [self.roster addDelegate:self delegateQueue:dispatch_get_main_queue()];
        
        //设置服务器的基本信息.
        //服务器的地址
        [self.stream setHostName:kHostAddress];
        [self.stream setHostPort:KHostPort];
        //端口号
    }
    
    #pragma mark XMPP 对外公开方法
    - (void) login:(NSString *)userName password:(NSString *)password loginSuccessBlock:(LoginSuccessBlock)block loginFailBlock:(LoginFailBlock)failBlock {
        
        _connectType = kTypeLogin;
        
        self.userName = userName;
        self.password = password;
        self.loginFailBlock = failBlock;
        self.loginSuccessBlock = block;
        //登录的流程.
        if (![self connect]) {
            //连接失败的时候 调用失败的block
            if (self.loginFailBlock) {
                self.loginFailBlock(@"网络错误");
            }
        }
    }
    //发起连接
    - (BOOL) connect {
        //设置用户的jid
        NSString *jidString = [NSString stringWithFormat:@"%@@%@",self.userName,kHostName];
        //创建了一个jid对象
        XMPPJID *jid = [XMPPJID jidWithString:jidString];
        [self.stream setMyJID:jid];
        NSError *ERROR = nil;
      return [self.stream connectWithTimeout:10 error:&ERROR];
    }
    //上线的方法
    - (void) online {
        //默认情况下 上线的状态
        XMPPPresence *presence = [XMPPPresence presence];
        [self.stream sendElement:presence];
    }
    
    //下线的方法
    - (void) outLine {
        
        XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];//unavailable 离线的意思
        //发送离线状态
        [self.stream sendElement:presence];
        
    }
    
    //查询好友列表
    
    /**
     <iq from='guojing@wxhl' type='get' id='roster_1' to='域名'>
        <query xmlns='jabber:iq:roster'/> <!-- iq 信息有多种,根据命名空间来区分-->
     </iq>
    
     */
    - (void) loadFriendList :(FentchFriendList) fentchFriendList {
        
        self.fentchFriendList  = fentchFriendList;
        //创建xml片段
        //创建<iq></iq>
        NSXMLElement *iqElement = [NSXMLElement elementWithName:@"iq"];
        XMPPJID *jid = self.stream.myJID;
        [iqElement addAttributeWithName:@"from" stringValue:[jid description]];
        //jid.domain  ---> 服务器的域名
        [iqElement addAttributeWithName:@"to" stringValue:jid.domain];
        [iqElement addAttributeWithName:@"type" stringValue:@"get"];
        [iqElement addAttributeWithName:@"id" stringValue:@"123456"];
        
        //创建子节点
        NSXMLElement *queryElement = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:roster"];
        //给iq节点增加子节点.
        [iqElement addChild:queryElement];
        //发送请求(好友列表)
        [self.stream sendElement:iqElement];
    }
    //发送消息
    //发送消息的格式
    /**
     <message
        to='huangrong@wxhl'
        from='guojing@wxhl'
        type='chat'
            xml:lang='en'>
        <body>有个bug帮我看下</body>
     </message>
     */
    - (void) sendMessage:(NSString *)message toUser:(NSString *) jid {
        
        //NIL
        if (!message || [message isEqualToString:@""]) {
            return;
        }
        
        NSXMLElement *messageElement = [NSXMLElement elementWithName:@"message"];
        
        [messageElement addAttributeWithName:@"to" stringValue:jid];
        XMPPJID *myJid = self.stream.myJID;
        [messageElement addAttributeWithName:@"from" stringValue:myJid.description];
        
        [messageElement addAttributeWithName:@"type" stringValue:@"chat"];
        
        [messageElement addAttributeWithName:@"xml:lang" stringValue:@"en"];
        //<message></message>创建完毕
        //创建子节点<body></body>
        NSXMLElement *bodyElement = [NSXMLElement elementWithName:@"body" stringValue:message];
        [messageElement addChild:bodyElement];
        
        //发送消息
        [self.stream sendElement:messageElement];
    }
    
    //注销方法
    - (void) logOutAction : (LogoutSuccessBlock) block {
        //发送离线的消息
        [self outLine];
        
        //断开连接,主动断开链接
        [self.stream disconnect];
        
        if (block) {
            block();
        }
    }
    //注册的方法
    - (void) registerUser:(NSString *)userName password:(NSString *)password registerSuccessBlock:(RegisterSuccessBlock) block {
        _connectType = kTypeRegister;
        //连接
        self.userName = userName;
        self.password = password;
        self.registerBlock = block;
        
        [self connect];
    }
    
    #pragma mark - XMPP DELEGAET
    - (void)xmppStreamDidConnect:(XMPPStream *)sender {
        NSLog(@"连接成功");
        //注册流程和登录流程都要使用该方法.在这里就要进行逻辑上判断
        if (_connectType == kTypeRegister) {
            [self.stream registerWithPassword:self.password error:nil];
        }else if(_connectType == kTypeLogin){
            //如果连接成功,则继续验证密码.
            [self.stream authenticateWithPassword:self.password error:nil];
        }
    }
    //验证成功的方法
    - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
        NSLog(@"验证成功");
        //要调用成功的block
        //发送上线的状态.
        [self online];
        if (self.loginSuccessBlock) {
            self.loginSuccessBlock();
        }
    }
    //验证失败的方法
    - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error {
        NSLog(@"验证失败");
        //如果认证失败的话,要主动断开连接
        [self.stream disconnect];
        if (self.loginFailBlock) {
            self.loginFailBlock(@"密码错误");
        }
    }
    //获取查询信息
    - (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq {
        /**
         //根节点
         <iq xmlns="jabber:client" type="result" id="123456" to="1234@zy/f54fcd02">
            <query xmlns="jabber:iq:roster">
                <item jid="gxb@localhost" name="" ask="subscribe" subscription="none">
                    <group>联系人列表</group>
                </item>
                <item jid="laoyan@zy" name="laoyan" subscription="both">
                    <group>12</group>
                </item>
                <item jid="deskmate@zy" name="deskmate" subscription="both">
                    <group>12</group>
                    <group>12</group>
                </item>
                <item jid="test123@zy" name="test123" subscription="both">
                    <group>联系人列表</group>
                </item>
                <item jid="zhengqingqing@192.168.13.12" name="" ask="subscribe" subscription="none">
                    <group>联系人列表</group>
                </item>
                <item jid="liuweiwei@zy" name="" subscription="both">
                    <group>让你变绿</group>
                    <group>让你变绿</group>
                </item>
                <item jid="zhengqingqing@zy" name="zhengqingqing" subscription="both">
                    <group>让你变绿</group>
                </item>
                <item jid="gxb1@zy" name="" subscription="both">
                    <group>联系人列表</group>
                    <group>联系人列表</group>
                    <group>变绿了</group>
                </item>
                <item jid="123456@localhost" name="" ask="subscribe" subscription="none">
                    <group>联系人列表</group>
                </item>
            </query>
         </iq>
         */
        //需要要类型是 字典
        /**
         dic = {
            "联系人列表":[user1,user3],
            "12":[user2]
         }
         */
        NSMutableDictionary *results = [NSMutableDictionary dictionary];
        NSXMLElement *queryElement = iq.childElement;
        //遍历Query节点
        User *user = nil;
        for (NSXMLElement *itemElement in queryElement.children) {
            
            user = [[User alloc] init];
            
            NSString *jidString = [itemElement attributeStringValueForName:@"jid"];
            
            user.jid = jidString;
            
            NSString *userName = [itemElement attributeStringValueForName:@"name"];
            
            user.username = userName;
            
            for (NSXMLElement *groupElement in itemElement.children) {
                //组名 12
                NSString *groupString = groupElement.stringValue;
                
                NSMutableArray *users = results[groupString];
                
                if (users == nil) {
                    users = [NSMutableArray array];
                    results[groupString] = users;
                }
                [users addObject:user];
            }
        }
        
        if (self.fentchFriendList) {
            self.fentchFriendList(results);
        }
        
        
        NSLog(@"获取好友列表 %@",results);
        return YES;
    }
    //监听外部传过来的数据,就是如果有好友发来信息,则,回调此方法.
    /**
     //传过来很多message标签,我们只需要带body的message标签
     <message xmlns="jabber:client" type="chat" id="purplea775e98a" to="1234@zy" from="gxb1@zy/MacdeMacBook-Pro-3"><composing xmlns="http://jabber.org/protocol/chatstates"/></message>
     2015-11-18 09:35:20.264 WeChat[3162:161262] message is <message xmlns="jabber:client" type="chat" id="purplea775e98b" to="1234@zy" from="gxb1@zy/MacdeMacBook-Pro-3"><active xmlns="http://jabber.org/protocol/chatstates"/><body>sad</body></message>
     2015-11-18 09:35:30.491 WeChat[3162:161262] message is <message xmlns="jabber:client" type="chat" id="purplea775e98c" to="1234@zy" from="gxb1@zy/MacdeMacBook-Pro-3"><active xmlns="http://jabber.org/protocol/chatstates"/></message>
     */
    - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
        //判断当前的message标签是否带body子标签
        if ([message isChatMessageWithBody]) {
            NSString *body = message.body;
            //获取发信息的人的jid
            XMPPJID *jidFrom = message.from;
            
            
            NSDictionary *messageDic = @{
                                         @"fromUser":jidFrom.description,
                                         @"text":body
                                         };
            
            //通知,发出接收消息的通知
            [[NSNotificationCenter defaultCenter] postNotificationName:kRecevieMessageNotification object:nil userInfo:messageDic];
            
        }
        
        
    }
    //注册成功调用的方法
    - (void)xmppStreamDidRegister:(XMPPStream *)sender {
        _connectType = kTypeLogin;
        self.loginSuccessBlock = self.registerBlock;
        self.registerBlock = nil;
        [self xmppStreamDidConnect:sender];
    }
    
    @end

    把宏定义改成自己的参数,在相关的UI操作代码中创建  单例XMPPHelper  然后调用相关方法,并在相关的代理方法中实现必要的操作就可以了。

  • 相关阅读:
    php-Zip打包文件
    PHP命令行类库 climate
    vim 添加块注释
    冒泡排序|插入排序
    PHP-SeasLog安装和使用
    链表
    多线程上下文切换
    竞态与线程安全
    线程的生命周期
    线程创建的两种方法
  • 原文地址:https://www.cnblogs.com/allencelee/p/4977596.html
Copyright © 2011-2022 走看看