xmpp整理筆記:使用者網路連接及好友的管理,xmpp網路連接
xmpp中的使用者串連模組包括使用者的上線與下線資訊展現,使用者登入,使用者的註冊; 好友模組包括好友的添加,好友的刪除,好友名單的展示。
在xmpp中 負責資料轉送的類是xmppStream,開發的過程中,針對不同的傳輸內容,會調用不同的代理方法,在使用XMPPFramework開發時,只需要在不同的代理方法中,填寫相同的代碼即可。
往期回顧:
xmpp整理筆記:xmppFramework架構的匯入和介紹 http://www.cnblogs.com/dsxniubility/p/4307057.html
xmpp整理筆記:環境的快速配置(附安裝包) http://www.cnblogs.com/dsxniubility/p/4304570.html
如果你不是在董鉑然部落格園看到本文,請點擊查看原文
一。大概的串連過程如下
1.運行後需要和伺服器建立一個長串連,系統會反饋連結是否成功
2.成功時需要告訴伺服器的使用者的密碼,伺服器判斷是否給予授權
3.成功授權後,告訴伺服器上線了。
4.將要離開時告訴伺服器,我需要取消連結了。
5.伺服器反饋你可以斷開了,然後你再告訴伺服器你下線了
二。首先,需要知道 XMPPStreamDelegate 和 XMPPRosterDelegate 的一些代理方法
如果你不是在董鉑然部落格園看到本文 請點擊查看原文
xmpp流代理方法:
串連成功時調用
- (void)xmppStreamDidConnect:(XMPPStream *)sender
中斷連線時調用
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
授權成功時調用
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
授權失敗時調用
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error
註冊成功時調用
- (void)xmppStreamDidRegister:(XMPPStream *)sender
註冊失敗時調用
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error
xmppRoster花名冊代理方法
接收到好友請求時調用
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
三。使用者的登入:
使用者需要在串連成功後的代理方法中 將自己的密碼發送給伺服器,自己的密碼應該是在點擊登入的時候就和其他資訊一起存入喜好設定了,在現在需要的時候可以輕而易舉取出來。在發送驗證請求的時候會用到這個方法authenticateWithPassword: 後面的error在實際開發中建議必須處理,我在這就偷懶了如下所示
/** 串連成功時調用 */- (void)xmppStreamDidConnect:(XMPPStream *)sender{ NSLog(@"串連成功"); NSString *password = [[NSUserDefaults standardUserDefaults] valueForKey:SXLoginPasswordKey]; // 將使用者密碼發送給伺服器,進行使用者登入 [self.xmppStream authenticateWithPassword:password error:NULL];}
然後等待結果,在授權成功後來到授權成功代理方法在這應該先告訴伺服器使用者上線,然後給發出成功通知,自己的AppDelegate在遠處接收,一旦接收到通知馬上更換應用程式的根控制器到進入後的介面,這裡要注意這些代理方法都是在非同步,所以這裡要用到線程間通訊,在主線程發送通知
// 通知伺服器使用者上線 [self goOnline]; // 在主線程利用通知發送廣播 dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:SXLoginResultNotification object:@(YES)]; });
如果授權失敗的話,應該斷開與伺服器的連結,並且把開始儲存的使用者偏好清空(因為這些是錯誤的沒用),然後再到主線程更新UI彈出一個框顯示密碼錯誤,並且發出失敗通知,讓APPDelegate切換根控制器到登入介面 (董鉑然原創)
// 斷開與伺服器的串連 [self disconnect]; // 清理使用者偏好 [self clearUserDefaults]; // 在主線程更新UI if (self.failed) { dispatch_async(dispatch_get_main_queue(), ^ {self.failed(@"使用者名稱或者密碼錯誤!");}); } // 在主線程利用通知發送廣播 dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:SXLoginResultNotification object:@(NO)]; });
四。使用者的上線和下線:
關於使用者的上線和下線,需要用到一個類XMPPPresence 類。這個類是XMPPElement的子類,主要用來管理某些資訊的展現。首先要執行個體化一個對象,這其中會用到一個presenceWithType 方法,有兩個選擇@"unavailable"代表下線,@"available"代表上線,一般情況上線的時候後面就可以直接省略。執行個體化之後用xmpp流發出去。如下所示
#pragma mark - ******************** 使用者的上線和下線- (void)goOnline { XMPPPresence *p = [XMPPPresence presence]; [self.xmppStream sendElement:p];}- (void)goOffline { XMPPPresence *p = [XMPPPresence presenceWithType:@"unavailable"]; [self.xmppStream sendElement:p];}
對使用者是否線上狀態的判斷
// 取出使用者XMPPUserCoreDataStorageObject *user = [self.fetchedResultsController objectAtIndexPath:indexPath];
使用者的 user.section 就是使用者的狀態
// section // 0 線上 // 1 離開 // 2 離線
五。使用者註冊:
自己在UI裡搭建好註冊頁面,裡面需要使用者填寫好使用者資訊。在點擊註冊按鈕時,把單例類裡自己設定的一個布爾值isRegisterUser 設定為YES。 然後重新發送串連請求。最終還是會來到,串連成功時的代理方法,剛才在這裡發送使用者密碼登入的,現在可以加一層判斷,如果isRegisterUser的值為YES 就不是發送使用者密碼登入了,而是發送使用者密碼註冊,這裡將會用到一個方法registerWithPassword:
if (self.isRegisterUser) { // 將使用者密碼發送給伺服器,進行使用者註冊 [self.xmppStream registerWithPassword:password error:NULL]; // 將註冊商標符號複位 self.isRegisterUser = NO; }
然後有兩個代理方法,註冊成功和註冊失敗,分別寫上合適的操作。
六。添加好友:
搭建一個加好友的UI只需要一個文字框和一個按鈕。
在文字框的斷行符號按鈕點擊代理方法中,做文字框是否為空白得判斷,不為空白就添加好友,(添加好友方法可以抽出來寫使得結構更加清晰)
添加好友方法如下:有兩個注意點一個是判斷使用者是否寫了網域名稱,如果只是單單寫了個帳號,也可以自動幫他拼接個網域名稱然後註冊。還有個就是判斷是否已經是自己的好友,如果是就不做任何操作。如果不是好友 那就馬上添加。最後讓導航控制器返回到登陸介面
// 添加好友- (void)addFriendWithName:(NSString *)name { // 你寫了網域名稱那更好,你沒寫系統就自動幫你補上 NSRange range = [name rangeOfString:@"@"]; // 如果沒找到 NSNotFound,不要寫0 if (range.location == NSNotFound) { name = [name stringByAppendingFormat:@"@%@", [SXXMPPTools sharedXMPPTools].xmppStream.myJID.domain]; } // 如果已經是好友就不需要再次添加 XMPPJID *jid = [XMPPJID jidWithString:name]; BOOL contains = [[SXXMPPTools sharedXMPPTools].xmppRosterCoreDataStorage userExistsWithJID:jid xmppStream:[SXXMPPTools sharedXMPPTools].xmppStream]; if (contains) { [[[UIAlertView alloc] initWithTitle:@"提示" message:@"已經是好友,無需添加" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show]; return; } [[SXXMPPTools sharedXMPPTools].xmppRoster subscribePresenceToUser:jid]; [self.navigationController popViewControllerAnimated:YES];}
這裡會用到一個通過JID加好友的方法subscribePresenceToUser: 但是這個方法是通過Roster 調用的所以要在單例類裡匯入標頭檔 聲明屬性,遵守協議,實現代理方法(董鉑然原創)
在單例類裡所有特殊類的操作都要寫在xmppStream的懶載入裡
// 執行個體化 _xmppReconnect = [[XMPPReconnect alloc]init]; _xmppRosterCoreDataStorage = [XMPPRosterCoreDataStorage sharedInstance]; _xmppRoster = [[XMPPRoster alloc]initWithRosterStorage:_xmppRosterCoreDataStorage dispatchQueue:dispatch_get_global_queue(0, 0)]; // 啟用 [_xmppRoster activate:_xmppStream]; // 添加代理 [_xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
接受到加好友請求的代理方法
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
在這個方法中,先要拼接提示的字串,就是從 presence.from(申請人的id)的人請求加你為好友。然後設定彈窗,確定和拒絕,點擊確定按鈕後
// 接受好友請求 [self.xmppRoster acceptPresenceSubscriptionRequestFrom:presence.from andAddToRoster:YES];
這個彈窗建議使用iOS8的新功能 UIAlertController。 這樣可以不用寫alertDelegate 也能設定確定按鈕點擊事件 。用 alert addAction: 添加按鈕,把點擊事件寫在block裡,最後再取到當前視窗的根控制器彈出presentViewController,相當於以前的show 。iOS8蘋果的思想漸漸是想把所有彈出控制器的各種方法都慢慢統一到present。
補充:這個功能就是QQ上所謂的加好友不需要驗證,是布爾值可以控制開關。
// 取消接收自動訂閱功能,需要確認才能夠添加好友! _xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = NO;
七。好友名單的展示。
這裡需要用到查詢結果調度器
- (NSFetchedResultsController *)fetchedResultsController{ if (_fetchedResultsController != nil) { return _fetchedResultsController; } // 指定查詢的實體 NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:@"XMPPUserCoreDataStorageObject"]; // 線上狀態排序 NSSortDescriptor *sort1 = [NSSortDescriptor sortDescriptorWithKey:@"sectionNum" ascending:YES]; // 顯示的名稱排序 NSSortDescriptor *sort2 = [NSSortDescriptor sortDescriptorWithKey:@"displayName" ascending:YES]; // 添加排序 request.sortDescriptors = @[sort1,sort2]; // 添加謂詞過濾器 request.predicate = [NSPredicate predicateWithFormat:@"!(subscription CONTAINS 'none')"]; // 添加上下文 NSManagedObjectContext *ctx = [SXXMPPTools sharedXMPPTools].xmppRosterCoreDataStorage.mainThreadManagedObjectContext; // 執行個體化結果控制器 _fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request managedObjectContext:ctx sectionNameKeyPath:nil cacheName:nil]; // 設定他的代理 _fetchedResultsController.delegate = self; return _fetchedResultsController;}
寫完了結果調度器之後要切記在viewdidload頁面首次載入中加上一句,否則不幹活
// 查詢資料 [self.fetchedResultsController performFetch:NULL];
結果調度器有一個代理方法,一旦上下文改變觸發,也就是剛加了好友,或移除朋友時會觸發
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller{ NSLog(@"上下文改變"); [self.tableView reloadData];}
整個tableview的資料來源方法如下
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.fetchedResultsController.fetchedObjects.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *ID = @"ContactCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; XMPPUserCoreDataStorageObject *user = [self.fetchedResultsController objectAtIndexPath:indexPath]; // 顯示此好友是否相互關注 NSString *str = [user.jidStr stringByAppendingFormat:@" | %@",user.subscription]; cell.textLabel.text = str ; // 這裡有個自訂方法傳入section 通過switch判斷返回漢字。section關係到是否線上 cell.detailTextLabel.text = [self userStatusWithSection:user.section]; return cell;}
其中subscription是使用者的好友互加情況
// 如果是none表示對方還沒有確認 // to 我關注對方 // from 對方關注我 // both 互粉
再提一下 user.section 就是使用者的狀態
// section // 0 線上 // 1 離開 // 2 離線
當有好友上線,上下文改變時,結果調度器會重新排序,然後線上的好友會顯示在上面。
八。移除朋友
好友的列表顯示介面可以給tableView添加滑動刪除。(開啟編輯模式)
#pragma mark - ******************** 開啟編輯模式移除朋友- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { XMPPUserCoreDataStorageObject *user = [self.fetchedResultsController objectAtIndexPath:indexPath]; XMPPJID *jid = user.jid; // 接下來是設定彈窗
在彈窗的點擊事件裡面移除朋友用到的方法是
[[SXXMPPTools sharedXMPPTools].xmppRoster removeUser:jid];
如果你不是在董鉑然部落格園看到本文,請點擊查看原文
正在整理關於資訊發送模組的各種細節,有興趣的可以關注