iOS中 XMPP即時通信實現的主要步驟

這裏只是列出實現的只要步驟,不是所有代碼。服務器

首先導入XMPPFramework,及相關配置,完成後開始。網絡

建立一個XMPPHelper  類來管理要進行的操做。dom

XMPPHelper.h文件以下ide

 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文件以下post

#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  而後調用相關方法,並在相關的代理方法中實現必要的操做就能夠了。atom

相關文章
相關標籤/搜索