本篇是 即時通訊之XMPP(2) 接上次 即時通訊之XMPP(1)html
// 獲取管理好友的單例對象 XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance]; // 給roster屬性進行初始化 self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)]; // 將好友列表在通道中激活 [self.xmppRoster activate:self.xmppStream]; // 設置花名冊代理 [self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
代碼:
git
#pragma mark - XMPPRosterDelegate代理方法 /// 開始獲取好友 - (void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender { NSLog(@"開始獲取好友"); } /// 結束獲取好友 - (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender { // 當前頁面適用於顯示好友列表的,因此在結束好友獲取的代理方法中要進行刷新頁面,而後將數據顯示 // 刷新頁面 [self.tableView reloadData]; } // 接收好友的信息 // 這個代理方法會被執行屢次,每添加無缺友,相對應的好友信息都要有反饋 - (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item { /* both 互爲好友 none 互不爲好友 to 我已經添加對方爲好友,可是對方尚未接受 from 對方已經添加我爲好友,可是我尚未接受 remove 曾經刪除的好友 */ // 描述本身和對方之間的關係 NSString *description = [[item attributeForName:@"subscription"] stringValue]; NSLog(@"description = %@", description); if ([description isEqualToString:@"to"] || [description isEqualToString:@"none"] || [description isEqualToString:@"both"] || [description isEqualToString:@"from"]) { // 添加好友 // 獲取添加好友的JID NSString *friendJID = [[item attributeForName:@"jid"] stringValue]; XMPPJID *jid = [XMPPJID jidWithString:friendJID]; // 若是數組中有這個用戶,就不用再進行操做 if ([self.allRosterArray containsObject:jid]) { return; } // 添加好友到數組 [self.allRosterArray addObject:jid]; // 在tableView中添加這條數據 NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.allRosterArray.count - 1 inSection:0]; [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight]; } } // 收到好友的監聽請求(加好友請求),是否贊成 - (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence { self.fromJID = presence.from; // 須要相關的提醒框去肯定是否接受 UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"好友請求" message:@"是否接受好友請求" preferredStyle:UIAlertControllerStyleAlert]; __weak typeof(self)weakSelf = self; UIAlertAction *acceptAction = [UIAlertAction actionWithTitle:@"接受" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // 在花名冊中去接受相關的好友 [[XMPPManager shareXMPPManager].xmppRoster acceptPresenceSubscriptionRequestFrom:weakSelf.fromJID andAddToRoster:YES]; }]; UIAlertAction *rejectAction = [UIAlertAction actionWithTitle:@"拒絕" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [[XMPPManager shareXMPPManager].xmppRoster rejectPresenceSubscriptionRequestFrom:weakSelf.fromJID]; }]; [alertController addAction:acceptAction]; [alertController addAction:rejectAction]; [self presentViewController:alertController animated:YES completion:nil]; }
代碼:github
- (void)addFriend { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"添加好友" message:@"請輸入添加好友的名字" preferredStyle:UIAlertControllerStyleAlert]; __weak typeof(self)mySlef = self; [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { mySlef.textField = textField; }]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { NSLog(@"取消刪除好友!"); }]; UIAlertAction *ensureAction = [UIAlertAction actionWithTitle:@"肯定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { // 使用JID記錄 XMPPJID *friendJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@%@", mySlef.textField.text, kDomin]]; // 監聽好友的動做 [mySlef.xmppRoster subscribePresenceToUser:friendJID]; // 添加好友 [mySlef.xmppRoster addUser:friendJID withNickname:mySlef.textField.text]; }]; [alertController addAction:ensureAction]; [alertController addAction:cancelAction]; [[self getCurrentVC] presentViewController:alertController animated:YES completion:nil]; }
代碼:數組
#pragma mark - 刪除好友 - (void)removeFriendWithName:(NSString *)name { // 使用JID記錄 XMPPJID *friendJID = [XMPPJID jidWithUser:name domain:kDomin resource:kResource]; // 中止監聽好友 [self.xmppRoster unsubscribePresenceFromUser:friendJID]; // 刪除好友 [self.xmppRoster removeUser:friendJID]; }
從服務器獲取聊天記錄,根據數據屬性判斷消息類型服務器
發送消息dom
接收消息優化
// 獲取管理消息的存儲對象 XMPPMessageArchivingCoreDataStorage *storage = [XMPPMessageArchivingCoreDataStorage sharedInstance]; // 消息管理器的初始化 self.messageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:storage dispatchQueue:dispatch_get_main_queue()]; // 激活通道 [self.messageArchiving activate:self.xmppStream]; // 設置代理 [self.messageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()]; // 設置消息管理上下文 self.context = [storage mainThreadManagedObjectContext];
獲取聊天記錄使用CoreData的方式spa
建立請求代理
建立實體描述,實體名: XMPPMessageArchiving_Message_CoreDataObjectcode
建立謂詞查詢條件,條件:streamBareJidStr == 本人Jid AND bareJidStr == 好友Jid
建立排序對象,排序條件:timestamp
執行請求
代碼:
#pragma mark - 顯示消息 - (void)showMessage { // 獲取管理上下文 NSManagedObjectContext *contxt = [XMPPManager shareXMPPManager].context; // 初始化請求對象 NSFetchRequest *request = [NSFetchRequest new]; // 獲取實體 NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:contxt]; // 設置查詢請求的實體 [request setEntity:entity]; // 設置謂詞查詢 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"streamBareJidStr == %@ AND bareJidStr == %@", [XMPPManager shareXMPPManager].xmppStream.myJID.bare, self.chatToJID.bare]; [request setPredicate:predicate]; // 按照時間順序排序 NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES]; [request setSortDescriptors:@[sort]]; // 執行相關的操做 NSArray *resultArray = [contxt executeFetchRequest:request error:nil]; // 先清空消息數組 [self.allMessageArray removeAllObjects]; // 添加context執行結果數組 [self.allMessageArray addObjectsFromArray:resultArray]; // 刷新UI [self.tableView reloadData]; // 當前聊天記錄跳到最後一行 if (self.allMessageArray.count > 0) { NSIndexPath * indexPath = [NSIndexPath indexPathForRow:self.allMessageArray.count-1 inSection:0]; // 跳到最後一行 [self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom]; } }
#pragma mark - 發送點擊方法 - (void)sendMessageAction { // 設置message的body XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatToJID]; // 發送的內容,通常是從輸入框獲取,這裏咱們就寫成固定的值 [message addBody:@"能夠"]; // 經過通道進行消息發送 [[XMPPManager shareXMPPManager].xmppStream sendElement:message]; }
代碼:
#pragma mark 發送消息成功 - (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message { // 從新顯示相關消息 [self showMessage]; } #pragma mark 接受消息成功 - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message { [self showMessage]; } #pragma mark 發送消息失敗 - (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error { NSLog(@"發送消息失敗"); }
代碼:
//重寫message方法,在cell上顯示聊天記錄 - (void)setMessage:(NSString *)message { if (_message != message) { _message = message; self.contentLabel.text = _message; // self.contentLabel.numberOfLines = 0; [self.contentLabel sizeToFit]; CGRect rect = self.frame; if (self.isOut) {//發出去的 self.backgroundImageView.image = [[UIImage imageNamed:@"chat_to"] stretchableImageWithLeftCapWidth:45 topCapHeight:40]; self.backgroundImageView.frame = CGRectMake(rect.size.width - self.contentLabel.frame.size.width - 50-20, 10, self.contentLabel.frame.size.width+20, rect.size.height-20); }else{//接收的 self.backgroundImageView.image = [[UIImage imageNamed:@"chat_from"] stretchableImageWithLeftCapWidth:45 topCapHeight:40]; self.backgroundImageView.frame = CGRectMake(50, 10,self.contentLabel.frame.size.width+40, rect.size.height-20); } //由於contentLabel已經自適應文字大小,故不用設置寬高,但須要設置位置 self.contentLabel.center = CGPointMake(self.backgroundImageView.frame.size.width/2.0, self.backgroundImageView.frame.size.height/2.0); } }
以上代碼均爲練習代碼的部分代碼!完整練習代碼github下載地址: https://github.com/AlonerOwl/UISenior11_-_1
因爲只是練習代碼,對於界面和部分功能沒有優化,看起來比較low,若是有需求,請本身進行優化。
代碼效果圖: