IOS開發之XMPP

  一.什麼是XMPP

  XMPP是一種基於XML的即時通信協議. 服務器爲openfire數組

  2、XMPP配置 

  a、導入xmpp框架 XMPPFramework;服務器

  b、添加依賴庫:libresolv.dylib、libxml2.dylib併發

  c、在Build Settings 中的 Header Search Paths中添加 /usr/include/libxml2框架

  3、開始代碼

  0、前期

  a、建立XMPPManager管理類,導入XMPP框架XMPPFramework.h,並將該類寫成單例dom

  b、聲明須要用到的對象:  ui

@interface QFXMPPManager ()
<XMPPStreamDelegate>
{
    
    XMPPStream *_xmppStream; //xmpp流
    XMPPRoster *_xmppRoster; //xmpp花名冊
    XMPPRosterCoreDataStorage *_xmppStorage; //xmpp花名冊存儲類
    XMPPReconnect *_xmppReconnect; //xmpp的重連機制類
    
    
    //保存用戶數據
    QFUserModel *userModel;
    
    //保存全部好友
    NSMutableArray *allFriends;
    
    //判斷是否在註冊(註冊/登陸)
    BOOL isRegister;
    
    //註冊結果的block
    void (^registerResultBlock)(BOOL success, NSError *error);
    
    //登錄結果的block
    void (^loginResultBlock)(BOOL success, NSError *error);
    
    //獲取好友結果的block
    void (^getFriendsResultBlock)(NSArray *friends);
    
    //發送信息結果的block
    void (^sendMessageResultBlock)(BOOL success);
    
    //接收信息結果的block
    void (^getMessageResultBlock)(QFChatModel *model);
    
}

@end

  c、建立用戶模型QFUserModel、消息模型QFMessageModelspa

  一、初始化須要用到的XMPP類

  

// 一、初始化xmpp流
        _xmppStream = [[XMPPStream alloc] init];
        
        // 設置主機
        [_xmppStream setHostName:@"1000phone.net"];
        
        // 設置端口
        [_xmppStream setHostPort:5222];
        
        // 設置代理
        [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
        
        
        // 二、初始化斷線重連機制
        _xmppReconnect = [[XMPPReconnect alloc] init];
        [_xmppReconnect activate:_xmppStream];
        
        
        // 三、初始化花名冊
        //初始化花名冊存儲對象
        _xmppStorage = [[XMPPRosterCoreDataStorage alloc] init];
        
        //初始化花名冊
        _xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:_xmppStorage];
        [_xmppRoster activate:_xmppStream];
        
        
        //初始化用戶model
        userModel = [[QFUserModel alloc] init];
        
        //初始化allFriends
        allFriends = [[NSMutableArray alloc] init];

  二、用戶註冊(經過Jid鏈接XMPP服務器)

  <用戶註冊分兩步:一、經過Jid鏈接服務器;二、經過密碼註冊>

  

// 先註冊用戶名, 而後再註冊密碼
- (void)registerWithName:(NSString *)name andPassword:(NSString *)password result:(void (^)(BOOL, NSError *))resultBlock
{
    registerResultBlock = [resultBlock copy];
    
    //正在註冊
    isRegister = YES;
    
    
    //保存用戶名和密碼
    userModel.name = name;
    userModel.password = password;
    
    
    //將name轉換成jid
    XMPPJID *jid = [XMPPJID jidWithString:name];
    [_xmppStream setMyJID:jid];
    
    //若是已經鏈接了,則先斷開鏈接
    if ([_xmppStream isConnected] || [_xmppStream isConnecting] ) {
        [_xmppStream disconnect];
    }
    
    //鏈接服務器
    NSError *error = nil;
    BOOL ret = [_xmppStream connectWithTimeout:-1 error:&error];
    if ( !ret ) {
        NSLog(@"鏈接失敗");
        
        if ( registerResultBlock ) {
            registerResultBlock (NO, error);
        }
    }
}

  三、用戶登錄(經過Jid鏈接XMPP服務器)

  <用戶登錄分兩步:一、經過Jid鏈接服務器;二、驗證密碼登錄>

  

- (void)loginWithName:(NSString *)name
          andPassword:(NSString *)password
               result:( void(^)(BOOL success, NSError *error) )resultBlock
{
    loginResultBlock = [resultBlock copy];
    
    //正在登陸(不是正在註冊)
    isRegister = NO;
    
    //保存用戶名和密碼
    userModel.name = name;
    userModel.password = password;
    
    //把name轉換成jid
    XMPPJID *jid = [XMPPJID jidWithString:name];
    _xmppStream.myJID = jid;
    
    
    //先斷開舊鏈接
    if ( [_xmppStream isConnected] || [_xmppStream isConnecting] ) {
        [_xmppStream disconnect];
    }
    
    //開始鏈接服務器
    NSError *error = nil;
    BOOL ret = [_xmppStream connectWithTimeout:-1 error:&error];
    if ( !ret ) {
        NSLog(@"鏈接失敗");
        if ( loginResultBlock ) {
            loginResultBlock (NO, error);
        }
    }
}

  鏈接服務器成功後,經過密碼註冊/驗證密碼登錄 .net

-(void)xmppStreamDidConnect:(XMPPStream *)sender
{
    
    if ( isRegister ) {
        
        //註冊密碼
        [_xmppStream registerWithPassword:userModel.password error:nil];
    }
    
    else {
        
        //登錄,驗證密碼
        [_xmppStream authenticateWithPassword:userModel.password error:nil];
    }
} 

  註冊的回調方法(註冊成功/註冊失敗)代理

  

-(void)xmppStreamDidRegister:(XMPPStream *)sender
{
    NSLog(@"註冊成功");
    if ( registerResultBlock ) {
        registerResultBlock (YES, nil);
    }
}

#pragma mark -- 註冊失敗
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error
{
    NSLog(@"註冊失敗");
    
    NSError *myError = [NSError errorWithDomain:error.description code:-1 userInfo:nil];
    if ( registerResultBlock ) {
        registerResultBlock (NO, myError);
    }
} 

  登錄的回調方法(登錄成功/登錄失敗),登錄成功後: a、申請上線;b、請求服務器獲取好友code

  

- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
    NSLog(@" 登陸成功 ");
    
    if ( loginResultBlock ) {
        loginResultBlock(YES, nil);
    }
    
    // 申請上線
    [self online];
    
    // 請求獲取好友列表
    [self requestFriends];
    
}

#pragma  mark -- 登錄失敗
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
    NSLog(@" 登陸失敗 ");
    
    NSError *myError = [NSError errorWithDomain:error.description code:-1 userInfo:nil];
    if ( loginResultBlock ) {
        loginResultBlock (NO, myError);
    }
}

  四、申請上線(申請下線)

- (void)online
{
    // 建立一個xml對象,併發送給服務器
    XMPPPresence *presence = [XMPPPresence presence];
    //"available"
//    NSLog(@"presence: %@", presence);
    
    [_xmppStream sendElement:presence];
}

- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
    
//    NSLog(@"presence:%@", presence);
    
   
    
    NSString *from = [presence attributeStringValueForName:@"from"];
//    NSLog(@"from: %@", from);
    //nie@1000phone.net/67f1ed1a
    XMPPJID *fromJid = [XMPPJID jidWithString:from];
    
    NSString *friendStr = [NSString stringWithFormat:@"%@@%@", fromJid.user, fromJid.domain];
    XMPPJID *friendJid = [XMPPJID jidWithString:friendStr];
    
//    NSLog(@"friendStr: %@", friendStr);

    
    
    
    //好友狀態
    NSString *type = [presence type];
    NSLog(@" === type :%@", type);

    NSString *status = @"available"; //默認是在線狀態
    
    //若是有好友上線了
    if ( [type isEqualToString:@"available"] ) {
        NSLog(@"有好友上線了:%@ ", friendStr);
        status = @"available";
    }
    
    //有好友下線了
    else if ( [type isEqualToString:@"unavailable"] ){
        NSLog(@"有好友下線了:%@", friendStr);
        status = @"unavailable";
    }
    
    //有人請求添加我爲好友
    else if ( [type isEqualToString:@"subscribe"] ) {
        
        NSLog(@" 有人要加我爲好友,這我的是:%@", friendStr);
        //接受別人的加好友請求,而且請求添加對方爲好友
        [_xmppRoster acceptPresenceSubscriptionRequestFrom:friendJid andAddToRoster:YES];
        
    }
    
    //更新全部好友的某一個好友的狀態
    [self updateFriend:friendStr withNewStatus:status];
    
}

  五、請求服務器獲取好友(IQ:Information Query)

  

-(void)requestFriends
{
    //
    NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:roster"];
    NSXMLElement *iq = [NSXMLElement elementWithName:@"iq"];
    
    [iq addAttributeWithName:@"type" stringValue:@"get"];
    [iq addChild:query];
    
//    NSLog(@" iq :%@", iq);
    
    //發送xml數據,請求獲取好友列表
    [_xmppStream sendElement:iq];
    
}

  成功獲取好友

  

-(BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
//    NSLog(@" iq :%@", iq);
    
    NSXMLElement *query = iq.childElement;
    //遍歷query的全部子節點
    for (NSXMLElement *item in query.children) {
        NSString *name = [item attributeStringValueForName:@"jid"];
        NSLog(@"friend Name: %@", name);
        
        //添加好友到allFriends中
        [self addFriendWithName:name andStatus:@"unavailable"];
    }
    
    return YES;
}

  六、添加好友 

- (void)addFriend:(NSString *)name

{

    XMPPJID *jid = [XMPPJID jidWithString:name];

    

    //請求添加好友

    [_xmppRoster subscribePresenceToUser:jid];

}

 七、更新好友狀態

   

- (void)updateFriend:(NSString *)name withNewStatus:(NSString *)newStatus
{
    for (QFUserModel *model in allFriends) {
        
        //判斷是否已經存在該好友,存在則修改其狀態
        if ( [model.name isEqualToString:name] ) {
            model.status = newStatus;
            
            //返回更新狀態後的最新的allFriends
            if ( getFriendsResultBlock ) {
                getFriendsResultBlock(allFriends);
            }
            
            return;
        }
    }
    
    //添加該好友
    [self addFriendWithName:name andStatus:newStatus];
    
} 

  添加好友到friends數組中 

- (void)addFriendWithName:(NSString *)name andStatus:(NSString *)status
{
    //遍歷本來全部的好友
    for (QFUserModel *model in allFriends) {
        
        //若是存在相同名稱的好友,不添加
        if ( [model.name isEqualToString:name] ) {
            NSLog(@" 已經存在該好友了 ,不添加了 ");
            return;
        }
    }
    
    //取得本身的名稱
    NSString *myName = [NSString stringWithFormat:@"%@@%@", _xmppStream.myJID.user, _xmppStream.myJID.domain];
    
    if ( [name isEqualToString:myName] ) {
        NSLog(@" 是我本身,不添加 ");
        return;
    }
    
    //添加這個好友
    QFUserModel *model = [[QFUserModel alloc] init];
    model.name = name;
    model.status = status;
    
    [allFriends addObject:model];
    
//    NSLog(@"allFriends.count: %d", allFriends.count);
    
    //每添加一個好友,返回最新的allFriends
    if ( getFriendsResultBlock ) {
        getFriendsResultBlock(allFriends);
    }
    
}

  八、發送和接收消息

  

#pragma  mark - 發送信息
- (void)sendMessage:(NSString *)content to:(NSString *)name result:( void(^)(BOOL success) )resultBlock
{
    sendMessageResultBlock = [resultBlock copy];
    
    NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
    [body setStringValue:content];
    
    NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
    [message addAttributeWithName:@"type" stringValue:@"chat"];
    [message addAttributeWithName:@"to" stringValue:name];
    [message addChild:body];
    
    NSLog(@"message: %@", message);
    
    //發送信息
    [_xmppStream sendElement:message];
    
}

#pragma  mark -- 發送信息成功的回調方法
- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message
{
    if ( sendMessageResultBlock ) {
        sendMessageResultBlock(YES);
    }
}

#pragma  mark -- 發送信息失敗
- (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error
{
    if ( sendMessageResultBlock ) {
        sendMessageResultBlock(NO);
    }
}

#pragma  mark - 接收信息
- (void)getMessage:( void(^)(QFChatModel *model) )resultBlock
{
    getMessageResultBlock = [resultBlock copy];
}

-(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
    if ( [message isChatMessage] ) {
        
        if ([message isChatMessageWithBody]) {
            
            NSString *body = message.body;
            NSString *from = message.from.bare;
            NSString *to = message.to.bare;
            
            QFChatModel *model = [[QFChatModel alloc] init];
            model.content = body;
            model.from = from;
            model.to = to;
            
            if ( getMessageResultBlock ) {
                getMessageResultBlock(model);
            }
        }
        
    }
    
}
相關文章
相關標籤/搜索