【原】iOS學習43即時通訊之XMPP(2)

本篇是 即時通訊之XMPP(2) 接上次 即時通訊之XMPP(1)html

1. 好友列表

 1> 初始化好友花名冊

    // 獲取管理好友的單例對象
    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()];

 2> XMPPRoster代理方法

  代碼:
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];
}

 3> 添加好友所需方法

  代碼: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];
}

4> 刪除好友

   代碼:數組

#pragma mark - 刪除好友
- (void)removeFriendWithName:(NSString *)name
{
    // 使用JID記錄
    XMPPJID *friendJID = [XMPPJID jidWithUser:name domain:kDomin resource:kResource];
    
    // 中止監聽好友
    [self.xmppRoster unsubscribePresenceFromUser:friendJID];
    
    // 刪除好友
    [self.xmppRoster removeUser:friendJID];
}

2. 聊天

 1> 聊天的規則:

  • 從服務器獲取聊天記錄,根據數據屬性判斷消息類型服務器

  • 發送消息dom

  • 接收消息優化

 2> 初始化消息歸檔

    // 獲取管理消息的存儲對象
    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];

 3> 獲取聊天記錄

  獲取聊天記錄使用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];
    }
}

 4> 發送消息

#pragma mark - 發送點擊方法
- (void)sendMessageAction
{
    // 設置message的body
    XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatToJID];
    
    // 發送的內容,通常是從輸入框獲取,這裏咱們就寫成固定的值
    [message addBody:@"能夠"];
    
    // 經過通道進行消息發送
    [[XMPPManager shareXMPPManager].xmppStream sendElement:message];
}

 5> 接收/發送消息的回調

  代碼:

#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(@"發送消息失敗");
}

 6> 消息氣泡

   代碼:

//重寫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,若是有需求,請本身進行優化。

代碼效果圖:

 

相關文章
相關標籤/搜索