上帝說:要約炮!因而有了XMPP

1、導入XMPP框架

  1. 下載 XMPPFramework 框架android

    GitHub: XMPPFrameworkgit

  2. 導入依賴框架github

    • CocoaLumberjack : 日誌框架sql

    • CocoaAsyncSocket : 底層網絡框架
      須要添加 CFNetwork & Security 框架依賴(XCode 6+ 無需導入)數據庫

    • KissXML : XML解析框架
      須要添加libxml2.dylib框架依賴
      須要指定以下編譯選項:
      Other Linker Flags = -lxml2
      Header Search Paths = /usr/include/libxml2服務器

    • libidn網絡

  3. 導入一下文件夾框架

    • Authentication
    • Categories
    • Core
    • Utilities
    • 添加依賴:libresolv.dylib
  4. 導入XMPP擴展框架dom

    • Extensions 文件夾
    • 導入 Sample_XMPPFramework.h 並改名爲:XMPPFramework.h
    • 添加PCH文件:
      • Add New File -> Other -> PCH文件
      • 添加 #import<UIKit/UIKit.h> 到PCH文件中
      • 設置編譯選項,Build Settings -> Precompile prefix Header 選擇Yes
      • 設置編譯選項,Build Settings -> Prefix Header 設置PCH文件名:「項目名/「PCH文件名」

2、登陸 & 註銷

實現用戶登陸的步驟以下:

1. 實例化XMPPStream並設置代理,同時添加代理到工做隊列      

2. 使用JID鏈接至服務器,默認端口爲5222,JID字符串中須要包含服務器的域名     

3. 在完成鏈接的代理方法中驗證用戶密碼,鏈接完成後XMPPStream的isConnect屬性爲YES     

4. 在驗證代理方法中判斷用戶是否登陸成功        

5. 上線或者下線成功後,向服務器發送Presence數據,以更新用戶在服務器的狀態

各部分的實現代碼以下:

  • 初始化 XMPPStream 並設置代理:iphone

    -(void)setupXMPPStream{
    
       _xmppStream = [[XMPPStream alloc] init];
    
       // 設置代理
       [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
    }
    

      

  • 鏈接到服務器

    -(void)connectToHost{
       NSLog(@"開始鏈接到服務器");
       if (!_xmppStream) {
           [self setupXMPPStream];
       }
    
       // 設置登陸用戶JID
       //resource 標識用戶登陸的客戶端 iphone android
    
       XMPPJID *myJID = [XMPPJID jidWithUser:@"aaa" domain:@"bourne-mbp.local" resource:@"iphone" ];
       _xmppStream.myJID = myJID;
    
       // 設置服務器域名
       _xmppStream.hostName = @"bourne-mbp.local";//不只能夠是域名,還但是IP地址
    
       // 設置端口 若是服務器端口是5222,能夠省略
       _xmppStream.hostPort = 5222;
    
       // 鏈接
       NSError *err = nil;
       if(![_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&err]){
           NSLog(@"%@",err);
       }
    
    }
    

      

  • 鏈接成功後發送密碼驗證

    -(void)sendPwdToHost{
       NSLog(@"再發送密碼受權");
       NSError *err = nil;
       [_xmppStream authenticateWithPassword:@"123456" error:&err];
       if (err) {
           NSLog(@"%@",err);
       }
    }
    

      

  • 受權成功後,發送 在線 消息

    #pragma mark  受權成功後,發送"在線" 消息
    -(void)sendOnlineToHost{
    
       NSLog(@"發送 在線 消息");
       XMPPPresence *presence = [XMPPPresence presence];
       NSLog(@"%@",presence);
    
       [_xmppStream sendElement:presence];
    }
    

      

     

須要實現的幾個代理方法

#pragma mark 與主機鏈接成功
-(void)xmppStreamDidConnect:(XMPPStream *)sender{
    NSLog(@"與主機鏈接成功");

    // 主機鏈接成功後,發送密碼進行受權
    [self sendPwdToHost];
}

  

#pragma mark 與主機斷開鏈接 
-(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error{
// 若是有錯誤,表明鏈接失敗 NSLog(@"與主機斷開鏈接 %@",error);
}
#pragma mark 受權成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
NSLog(@"受權成功"); [self sendOnlineToHost];
}
#pragma mark 受權失敗
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
NSLog(@"受權失敗 %@",error);
}

  

註銷登陸

  • 發送 離線 信息
  • 斷開鏈接
-(void)logout{
    // 1." 發送 `離線` 消息"
    XMPPPresence *offline = [XMPPPresence presenceWithType:@"unavailable"];
    [_xmppStream sendElement:offline];

    // 2. 與服務器斷開鏈接
    [_xmppStream disconnect];
}

  

3、註冊

  • 與登陸同樣,首先發送賬號創建鏈接

  • 鏈接成功後,發送註冊的密碼

  • 註冊成功後,框架會通知代理

實現如下代理方法

- (void)xmppStreamDidRegister:(XMPPStream *)sender {
    NSLog(@"註冊成功");

    if (_resultBlock) {
        _resultBlock(BWXMPPLoginResultSuccessed);
    }
}

- (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error {
    if (_resultBlock) {
        _resultBlock(BWXMPPLoginResultFailure);
    }
}

  

4、用戶信息

XMPP是面向模塊的,每個大的動能都屬於某一個模塊,須要使用時,就在頭文件中將其暴露出來(本來是被註釋了的)。

  1. 工做原理:

    添加用戶信息模塊以後,XMPPFramework框架會自動從服務器獲取用戶信息,並使用CoreData保存到本地的數據庫中,使用XMPPvCardTempModule能夠訪問數據

  2. XMPPFramework.h中將如下的頭文件前面的註釋去掉:

    // 電子名片模塊
    #import "XMPPvCardTempModule.h"
    #import "XMPPvCardCoreDataStorage.h"
    
    // 頭像模塊
    #import "XMPPvCardAvatarModule.h"
  3. 初始化模塊

    //添加電子名片模塊
    _vCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
    _vCard = [[XMPPvCardTempModule alloc] initWithvCardStorage:_vCardStorage];
    
    //激活
    [_vCard activate:_xmppStream];
    
    //添加頭像模塊
    _avatar = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_vCard];
    [_avatar activate:_xmppStream];
    

      

  4. 應用

    //xmpp提供了一個方法,直接獲取我的信息
    XMPPvCardTemp *myVCard =[WCXMPPTool sharedWCXMPPTool].vCard.myvCardTemp;
    
    // 設置頭像
    if(myVCard.photo){
     self.haedView.image = [UIImage imageWithData:myVCard.photo];
    }
    
    // 設置暱稱
    self.nicknameLabel.text = myVCard.nickname;
    

      

5、好友

與用戶信息模塊類似,添加相應的好友花名冊模塊便可。

  1. 頭文件

    // 花名冊模塊
    #import "XMPPRoster.h"
    #import "XMPPRosterCoreDataStorage.h"
  2. 初始化

    // 添加花名冊模塊【獲取好友列表】
    _rosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
    _roster = [[XMPPRoster alloc] initWithRosterStorage:_rosterStorage];
    [_roster activate:_xmppStream];
    

      

  3. 應用

    //使用CoreData獲取數據
    // 1.上下文【關聯到數據庫XMPPRoster.sqlite】
    NSManagedObjectContext *context = [WCXMPPTool sharedWCXMPPTool].rosterStorage.mainThreadManagedObjectContext;
    
    // 2.FetchRequest【查哪張表】
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"XMPPUserCoreDataStorageObject"];
    
    // 3.設置過濾和排序
    // 過濾當前登陸用戶的好友
    NSString *jid = [WCUserInfo sharedWCUserInfo].jid;
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"streamBareJidStr = %@",jid];
    request.predicate = pre;
    
    //排序
    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"displayName" ascending:YES];
    request.sortDescriptors = @[sort];
    
    // 4.執行請求獲取數據
    _resultsContrl = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
    
    _resultsContrl.delegate = self;
    
    NSError *err = nil;
    [_resultsContrl performFetch:&err];
    if (err) {
     WCLog(@"%@",err);
    }
    

      

    • 注意:使用NSFetchedResultsController並設置代理,若是數據庫的內容發生了變化,這個類會自動通知代理,就能夠設置界面的數據,作到實時更新。

6、消息

  1. 頭文件

    • 注意:這幾個頭文件沒在XMPPFramework.h文件中,須要本身添加
    // 消息模塊
    #import "XMPPMessageArchiving.h"
    #import "XMPPMessageArchivingCoreDataStorage.h"
  2. 初始化

    // 添加聊天模塊
    _msgStorage = [[XMPPMessageArchivingCoreDataStorage alloc] init];
    _msgArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:_msgStorage];
    [_msgArchiving activate:_xmppStream];
    

      

  3. 應用

    // 上下文
    NSManagedObjectContext *context = [WCXMPPTool sharedWCXMPPTool].msgStorage.mainThreadManagedObjectContext;
    // 請求對象
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"XMPPMessageArchiving_Message_CoreDataObject"];
    
    // 過濾、排序
    // 1.當前登陸用戶的JID的消息
    // 2.好友的Jid的消息
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"streamBareJidStr = %@ AND bareJidStr = %@",[WCUserInfo sharedWCUserInfo].jid,self.friendJid.bare];
    NSLog(@"%@",pre);
    request.predicate = pre;
    
    // 時間升序
    NSSortDescriptor *timeSort = [NSSortDescriptor sortDescriptorWithKey:@"timestamp" ascending:YES];
    request.sortDescriptors = @[timeSort];
    
    // 查詢
    _resultsContr = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
    
    NSError *err = nil;
    // 代理
    _resultsContr.delegate = self;
    
    [_resultsContr performFetch:&err];
    
    NSLog(@"%@",_resultsContr.fetchedObjects);
    if (err) {
      WCLog(@"%@",err);
    }
    

      

7、文件傳送(圖片,音頻)

  1. 原理分析

    • 使用base64將文件轉化爲字符串,而後再經過XMPPFramework傳輸。
    • 先將文件上傳到服務器,再將文件網址經過XMPPFramework轉輸給好友,好友收到後再自行下載文件。
  1. 難點解析

    • 須要給XMPPFramework的``數據體添加一個信息類型字段。
    XMPPMessage *msg = [XMPPMessage messageWithType:@"chat" to:self.friendJid];
    
    //text 純文本
    //image 圖片
    [msg addAttributeWithName:@"bodyType" stringValue:bodyType];
    
    // 設置內容
    [msg addBody:text];
    NSLog(@"%@",msg);
    [[WCXMPPTool sharedWCXMPPTool].xmppStream sendElement:msg];
    

      

    • 根據消息類型解析消息

    ```objc

    XMPPMessageArchiving_Message_CoreDataObject *msg = _resultsContr.fetchedObjects[indexPath.row];
    
    // 判斷是圖片仍是純文本
    NSString *chatType = [msg.message attributeStringValueForName:@"bodyType"];
    if ([chatType isEqualToString:@"image"]) {
        //下圖片顯示
        [cell.imageView sd_setImageWithURL:[NSURL URLWithString:msg.body] placeholderImage:[UIImage imageNamed:@"DefaultProfileHead_qq"]];
        cell.textLabel.text = nil;
    } else if ([chatType isEqualToString:@"text"]){
    
        //顯示消息
        if ([msg.outgoing boolValue]) {//本身發
            cell.textLabel.text = msg.body;
        }else{//別人發的
            cell.textLabel.text = msg.body;
        }
    
        cell.imageView.image = nil;
    }
    

      

```

聲明:

以上內容轉自:

http://www.jianshu.com/p/c7bbbad90639#
相關文章
相關標籤/搜索