XMPPFramework 使用(Mac)

XMPPFramework

1. 導(dǎo)入源碼

1). 將下載好的XMPPFramework解壓,解壓后的目錄如下:


圖1.png

2). 將Sample_XMPPFramework.h更名為XMPPFramework.h滋早,然后將XMPPFramework-3.6.4文件夾直接拖入要使用該框架的工程中,然后刪除將XMPPFramwork-3.6.4文件夾中的文件夾(除Xcode文件夾)及XMPPFramework.h文件保留驳概,其他文件刪除,刪除后結(jié)構(gòu)如圖3旷赖,編譯抡句。


圖2.png

圖3.png

3). 解決錯誤I

圖4.png

解決辦法:

  • 在Build Settings 搜索Header Search Paths 添加頭文件搜索路徑: /usr/include/libxml2
  • 在Build Phasses->Link Binary With Libraries中添加兩個動態(tài)鏈接庫: libxml2.tbdlibresolv.tbd
  • 在Build Settings 搜索prefix Header杠愧,在Prefix Header中添加$SRCROOT/$(PRODUCT_NAME)/PrefixHeader.pch
  • 在項(xiàng)目的根目錄下新建pch文件:Other->PCH File待榔。

4). 編譯, 報如下錯誤:

圖5.png

解決辦法:

  • 在PrefixHeader.pch中添加頭文件#import <UIKit/UIKit.h>流济,添加后內(nèi)容如下:
    圖6.png

5). 編譯锐锣,此時如果不出現(xiàn)意外,就可以成功編譯绳瘟。但我在編譯時出現(xiàn)如下錯誤:

圖7.png

問題原因:重復(fù)定義
解決辦法:找到對應(yīng)的位置雕憔,將34行注釋,因此是重復(fù)定義糖声,因此注釋之后對源碼沒有影響斤彼。
圖8.png

6). 成功編譯


圖9.png

2. 注冊與登陸

PrefixHeader.pch

#ifndef PrefixHeader_pch
#define PrefixHeader_pch

#import <UIKit/UIKit.h>
#import "XMPPFramework.h"
#import "MTStreamManager.h"

#endif

MTStreamManager.h

#import <Foundation/Foundation.h>

@interface MTStreamManager : NSObject

typedef NS_ENUM(NSInteger, connectToServer) {
    connectToSerLogin, // 登陸
    connectToSerRegist // 注冊
};

// 單例
+ (instancetype) sharedManager;

// 創(chuàng)建XMPPStream流
@property (nonatomic, strong) XMPPStream *xmppStream;

// 存儲密碼
@property (nonatomic, copy) NSString *password;

// 區(qū)別注冊還是登陸
@property (nonatomic) connectToServer connectStatus;

// 注冊
- (void) registWithName:(NSString *)name andPassword:(NSString *)password;

// 登陸
- (void) loginWithName:(NSString *)name andPassword:(NSString *)password;

@end

MTStreamManager.m


#import "MTStreamManager.h"
// 打印日志需要
#import "DDLog.h"
#import "DDTTYLogger.h"
#import "XMPPLogging.h"

#define DO_MAIN @"mazaiting.com"

@interface MTStreamManager() <XMPPStreamDelegate>

@end

@implementation MTStreamManager
static MTStreamManager *sInstance;
// 單例
+ (instancetype) sharedManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sInstance = [MTStreamManager new];
        // 設(shè)置日志打印
        [DDLog addLogger:[DDTTYLogger sharedInstance]];
        // 設(shè)置日志等級
        [DDLog setLogLevel:XMPP_LOG_FLAG_SEND_RECV forClass:self];
    });
    return sInstance;
}

// 懶加載XMPPStream
- (XMPPStream *)xmppStream {
    if (nil == _xmppStream) {
        // 創(chuàng)建
        _xmppStream = [[XMPPStream alloc] init];
        // 設(shè)置屬性
        // ip
        _xmppStream.hostName = @"127.0.0.1";
        // 端口
        _xmppStream.hostPort = 5222;
        // 設(shè)置代理--多播代理
        [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    return _xmppStream;
}

// 注冊
- (void) registWithName:(NSString *)name andPassword:(NSString *)password {
    // 創(chuàng)建一個JID
    XMPPJID *jid = [XMPPJID jidWithUser:name domain:DO_MAIN resource:nil];
    // 設(shè)置MyJID
    [self.xmppStream setMyJID:jid];
    // 設(shè)置密碼
    self.password = password;
    // 設(shè)置狀態(tài)為注冊
    self.connectStatus = connectToSerRegist;
    // 連接到服務(wù)器
    [self connectServer];
}

// 登陸
- (void) loginWithName:(NSString *)name andPassword:(NSString *)password {
    // 創(chuàng)建一個JID
    XMPPJID *jid = [XMPPJID jidWithUser:name domain:DO_MAIN resource:nil];
    // 設(shè)置MyJID
    [self.xmppStream setMyJID:jid];
    // 設(shè)置密碼
    self.password = password;
    // 設(shè)置狀態(tài)為注冊
    self.connectStatus = connectToSerLogin;
    // 連接到服務(wù)器
    [self connectServer];
}

// 連接到服務(wù)器
- (void)connectServer {
    // 判斷當(dāng)前是否有連接分瘦,如果有則斷開
    if ([self.xmppStream isConnected]) {
        // 退出登陸
        [self logout];
    }
    // 異常信息
    NSError *error = nil;
    // 連接服務(wù)器
    [self.xmppStream connectWithTimeout:15.0f error:&error];
    // 判斷是否連接成功
    if (error) {
        NSLog(@"連接失敗");
    }
}

// 退出登陸
- (void) logout {
    // 用戶狀態(tài)類
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    // 向服務(wù)器發(fā)送離線通知
    [self.xmppStream sendElement:presence];
    // 斷開連接
    [self.xmppStream disconnect];
}

// 激活其他模塊
- (void) activite {
    
}

#pragma mark 代理方法,連接成功之后回調(diào)
- (void)xmppStreamDidConnect:(XMPPStream *)sender {
    switch (self.connectStatus) {
        case connectToSerLogin:
        {
            // 錯誤
            NSError *error = nil;
            // 登陸
            [self.xmppStream authenticateWithPassword:self.password error:&error];
            // 匿名登陸
//            [self.xmppStream authenticateAnonymously:&error];
            // 判斷是否登陸成功
            if (error) {
                NSLog(@"登陸失敗");
            } else {
                NSLog(@"登陸成功");
                // 登陸成功之后注冊其他模塊
                [self activite];
            }
        }
            break;
        case connectToSerRegist:
        {
            // 錯誤
            NSError *error = nil;
            // 注冊
            [self.xmppStream registerWithPassword:self.password error:&error];
            // 判斷是否注冊成功
            if (error) {
                NSLog(@"注冊失敗");
            }
            // 注冊成功之后斷開連接
            [self logout];
        }
            break;
        default:
            break;
    }
}

#pragma mark 代理方法琉苇,登陸成功之后告訴服務(wù)器我要出席
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
    // 如果成功嘲玫,可以出席
    XMPPPresence *presence = [XMPPPresence presence];
    // 添加出席狀態(tài)
    [presence addChild:[DDXMLElement elementWithName:@"show" stringValue:@"dnd"]];
    [presence addChild:[DDXMLElement elementWithName:@"status" stringValue:@"請勿打擾"]];
    // 告訴服務(wù)器我要出席
    [self.xmppStream sendElement:presence];
}

@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()
// 用戶名輸入框
@property (weak, nonatomic) IBOutlet UITextField *userName;
// 密碼輸入框
@property (weak, nonatomic) IBOutlet UITextField *passWord;

@end

@implementation ViewController
// 注冊
- (IBAction)regist:(id)sender {
    NSString *username = self.userName.text;
    NSString *password = self.passWord.text;
    [[MTStreamManager sharedManager] registWithName:username andPassword:password];
}
// 登陸
- (IBAction)login:(id)sender {
    NSString *username = self.userName.text;
    NSString *password = self.passWord.text;
    [[MTStreamManager sharedManager] loginWithName:username andPassword:password];
}

@end

注冊后可在管理控制臺中查看


圖10.png

3. 斷線重連

1). 在XMPPFramework.h中添加

// 自動重連
#import "XMPPReconnect.h"

2). 在MTStreamManager.h中添加屬性

// 創(chuàng)建自動重連對象
@property (nonatomic, strong) XMPPReconnect *xmppReconnect;

3). 在MTStreamManager.m中懶加載xmppReconnect

// 懶加載斷線重連
- (XMPPReconnect *)xmppReconnect {
    if (nil == _xmppReconnect) {
        // 創(chuàng)建對象
        _xmppReconnect = [[XMPPReconnect alloc] initWithDispatchQueue:dispatch_get_main_queue()];
        // 設(shè)置參數(shù)
        _xmppReconnect.reconnectTimerInterval = 2;
    }
    return _xmppReconnect;
}

4). 在XMPPFramework.m中的activite方法中進(jìn)行激活

// 激活其他模塊
- (void) activite {
    // 激活斷線重連
    [self.xmppReconnect activate:self.xmppStream];
}

5). 測試方法
進(jìn)入管理控制臺中,選擇會話并扇,把登陸的用戶點(diǎn)擊右側(cè)的關(guān)閉連接將其斷開去团,然后刷新頁面,如果成功登陸穷蛹,則斷線重連功能完成土陪。


圖11.png

4. 心跳檢測

1). 在XMPPFramework.h中添加

// 心跳檢測
#import "XMPPAutoPing.h"

2). 在MTStreamManager.h中添加屬性

// 創(chuàng)建心跳檢測對象
@property (nonatomic, strong) XMPPAutoPing *xmppAutoPing;

3). 在MTStreamManager.m中懶加載xmppAutoPing

// 心跳檢測
- (XMPPAutoPing *)xmppAutoPing {
    if (nil == _xmppAutoPing) {
        // 創(chuàng)建心跳檢測
        _xmppAutoPing = [[XMPPAutoPing alloc] initWithDispatchQueue:dispatch_get_main_queue()];
        // 設(shè)置參數(shù)
        _xmppAutoPing.pingInterval = 3;
    }
    return _xmppAutoPing;
}

4). 在XMPPFramework.m中的activite方法中進(jìn)行激活

// 激活其他模塊
- (void) activite {
    // 激活斷線重連
    [self.xmppReconnect activate:self.xmppStream];
    // 激活心跳檢測
    [self.xmppAutoPing activate:self.xmppStream];
}

5). 測試方法
運(yùn)行程序后查看控制臺打印,如果一直在不斷的刷新肴熏,則證明心跳檢測開啟鬼雀。

5. 好友功能模塊

1). 在XMPPFramework.h中添加

// 好友角色
#import "XMPPRoster.h"
// 好友存儲管理
#import "XMPPRosterCoreDataStorage.h"
// 好友的實(shí)體
#import "XMPPUserCoreDataStorageObject.h"

2). 在MTStreamManager.h中添加屬性

// 創(chuàng)建好友列表功能模塊
@property (nonatomic, strong) XMPPRoster *xmppRoster;

3). 在MTStreamManager.m中懶加載xmppRoster

// 好友列表功能
- (XMPPRoster *)xmppRoster {
    if (nil == _xmppRoster) {
        // 創(chuàng)建對象
        _xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:[XMPPRosterCoreDataStorage sharedInstance] dispatchQueue:dispatch_get_global_queue(0, 0)];
        // 設(shè)置參數(shù)
        // 是否自動查找新的好友數(shù)據(jù)
        _xmppRoster.autoFetchRoster = YES;
        // 是否自動刪除用戶存儲的數(shù)據(jù),不需要
        _xmppRoster.autoClearAllUsersAndResources = NO;
        // 如果自動接收XMPP,會幫我們做一個加好友的操作蛙吏,代理方法也不會被調(diào)用了
        _xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = NO;
        //設(shè)置代理源哩,,注意讓MTStreamManager實(shí)現(xiàn)XMPPRosterDelegate協(xié)議
        [_xmppRoster addDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
    }
    return _xmppRoster;
}

4). 在XMPPFramework.m中的activite方法中進(jìn)行激活

// 激活其他模塊
- (void) activite {
    // 激活斷線重連
    [self.xmppReconnect activate:self.xmppStream];
    // 激活心跳檢測
    [self.xmppAutoPing activate:self.xmppStream];
    // 激活好友模塊
    [self.xmppRoster activate:self.xmppStream];
}

5). 使用

  • 使用查詢控制器來查詢數(shù)據(jù)
@interface MTContactTableViewController () <NSFetchedResultsControllerDelegate>
// 查詢控制器出刷,用來查詢好友
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
// 好友列表數(shù)組
@property (nonatomic, strong) NSArray *contactArrs;
@end

@implementation MTContactTableViewController

// 懶加載聯(lián)系人數(shù)組
- (NSArray *)contactArrs {
    if (nil == _contactArrs) {
        _contactArrs = [NSArray array];
    }
    return _contactArrs;
}

// 懶加載fetchedResultsController,執(zhí)行查詢操作
- (NSFetchedResultsController *)fetchedResultsController {
    if (nil == _fetchedResultsController) {
        // 創(chuàng)建一個查詢請求
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        // 實(shí)體
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPUserCoreDataStorageObject" inManagedObjectContext:[XMPPRosterCoreDataStorage sharedInstance].mainThreadManagedObjectContext];
        // 謂詞, 查詢只有雙方都是對方的好友的人
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"subscription = %@", @"both"];
        // 排序, 根據(jù)jidStr進(jìn)行升序排列
        NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"jidStr" ascending:YES];
        // 設(shè)置實(shí)體
        fetchRequest.entity = entity;
        // 設(shè)置謂詞
        fetchRequest.predicate = predicate;
        // 設(shè)置排序
        fetchRequest.sortDescriptors = @[sortDescriptor];
        // 創(chuàng)建fetchedResultsController對象
        _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[XMPPRosterCoreDataStorage sharedInstance].mainThreadManagedObjectContext sectionNameKeyPath:nil cacheName:@"contacts"];
        // 設(shè)置代理, 實(shí)現(xiàn)協(xié)議NSFetchedResultsControllerDelegate
        _fetchedResultsController.delegate = self;
    }
    return _fetchedResultsController;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 刪除CoreData中的緩存
    [NSFetchedResultsController deleteCacheWithName:@"contacts"];
    // 好友代理設(shè)置, 實(shí)現(xiàn)XMPPRosterDelegate
    [[MTStreamManager sharedManager].xmppRoster addDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
    // 執(zhí)行查詢操作, 查詢到之后將數(shù)據(jù)保存在了fetchedObjects變量中
    [self.fetchedResultsController performFetch:nil];
    // 獲取到數(shù)據(jù)
    self.contactArrs = self.fetchedResultsController.fetchedObjects;
    // 刷新數(shù)據(jù)
    [self.tableView reloadData];
}
}
#pragma mark - NSFetchedResultsController協(xié)議
// 當(dāng)CoreData數(shù)據(jù)發(fā)生變化會調(diào)用該代理方法
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    NSLog(@"數(shù)據(jù)發(fā)生改變");
    // 最新的列表
    self.contactArrs = self.fetchedResultsController.fetchedObjects;
    // 刷新數(shù)據(jù)
    [self.tableView reloadData];
}

#pragma mark - Table view data source
// 返回TableView中的條目總數(shù)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.contactArrs.count;
}

// 設(shè)置TableViewCell的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 80.0;
}

// 為TableViewCell賦值
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 獲取TableViewCell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Contact_Cell"];
    // 獲取對應(yīng)行的聯(lián)系人數(shù)據(jù)
    XMPPUserCoreDataStorageObject *contact = self.contactArrs[indexPath.row];
    
    // 給Cell賦值
    // 設(shè)置JID
    UILabel *nameLabel = (UILabel *)[cell viewWithTag:1002];
    nameLabel.text = contact.jidStr;

    return cell;
}
@end

6). 添加刪除好友

  • 主動申請?zhí)砑雍糜?/li>
    // 創(chuàng)建XMPPJID
    XMPPJID *jid = [XMPPJID jidWithUser:@"linghaoyu9" domain:DO_MAIN resource:nil];
    // 添加好友
//    [[MTStreamManager sharedManager].xmppRoster addUser:jid withNickname:@"加好友"];
    [[MTStreamManager sharedManager].xmppRoster subscribePresenceToUser:jid];
  • 同意對方的請求
    // 創(chuàng)建XMPPJID
    XMPPJID *jid = [XMPPJID jidWithUser:@"linghaoyu9" domain:DO_MAIN resource:nil];
    // 同意添加對方為好友
    [[MTStreamManager sharedManager].xmppRoster acceptPresenceSubscriptionRequestFrom:jid andAddToRoster:YES];
  • 刪除好友
    // 創(chuàng)建XMPPJID
    XMPPJID *jid = [XMPPJID jidWithUser:@"linghaoyu9" domain:DO_MAIN resource:nil];
// 刪除好友
        [[MTStreamManager sharedManager].xmppRoster removeUser:jid];

6. 聊天模塊

1). 在XMPPFramework.h中添加

// 聊天模塊
#import "XMPPMessageArchiving.h"
// 聊天信息的存儲管理
#import "XMPPMessageArchivingCoreDataStorage.h" 
// 消息實(shí)體
#import "XMPPMessageArchiving_Message_CoreDataObject.h"
// 最近聯(lián)系人實(shí)體
#import "XMPPMessageArchiving_Contact_CoreDataObject.h"

2). 在MTStreamManager.h中添加屬性

// 創(chuàng)建聊天功能模塊
@property (nonatomic, strong) XMPPMessageArchiving *xmppMessageArchiving;

3). 在MTStreamManager.m中懶加載xmppMessageArchiving

// 消息模塊
- (XMPPMessageArchiving *)xmppMessageArchiving {
    if (nil == _xmppMessageArchiving) {
        // 創(chuàng)建對象
        _xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:[XMPPMessageArchivingCoreDataStorage sharedInstance] dispatchQueue:dispatch_get_main_queue()];
    }
    return _xmppMessageArchiving;
}

4). 在XMPPFramework.m中的activite方法中進(jìn)行激活

// 激活其他模塊
- (void) activite {
    // 激活斷線重連
    [self.xmppReconnect activate:self.xmppStream];
    // 激活心跳檢測
    [self.xmppAutoPing activate:self.xmppStream];
    // 激活好友模塊
    [self.xmppRoster activate:self.xmppStream];
    // 激活聊天模塊
    [self.xmppMessageArchiving activate:self.xmppStream];
}

5). 實(shí)現(xiàn)XMPPStreamDelegate協(xié)議中的xmppStream:didReceiveMessage:方法, 用來接收消息

  • MTStreamManager.m中
// 通過代理接收數(shù)據(jù)
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
    NSLog(@"接收到的消息: %@", message.body);
    // 發(fā)送本地通知坯辩,在AppDelegate中接收通知
    UILocalNotification *noti = [[UILocalNotification alloc] init];
    [noti setAlertBody:[NSString stringWithFormat:@"來自%@ : %@ 消息", message.from, message.body]];
    // 設(shè)置appicon圖標(biāo)
    [noti setApplicationIconBadgeNumber:1];
    // 彈出本地通知
    [[UIApplication sharedApplication] presentLocalNotificationNow:noti];
}
  • AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 需要一個用戶通知設(shè)置, 用來接收通知
    UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound|UIUserNotificationTypeAlert|UIUserNotificationTypeBadge categories:nil];
    // 注冊
    [[UIApplication sharedApplication] registerUserNotificationSettings:setting];
    return YES;
}

6). 查詢消息


@interface MTChatViewController () <NSFetchedResultsControllerDelegate> {
// 消息列表查詢控制器
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
// 消息數(shù)組
@property (nonatomic, strong) NSArray *chatArrs;
}
// -----------------具體實(shí)現(xiàn)
// 懶加載數(shù)組
- (NSArray *)chatArrs {
    if (nil == _chatArrs) {
        _chatArrs = [NSArray array];
    }
    return _chatArrs;
}

// 懶加載fetchedResultsController
- (NSFetchedResultsController *)fetchedResultsController {
    if (nil == _fetchedResultsController) {
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:[XMPPMessageArchivingCoreDataStorage sharedInstance].mainThreadManagedObjectContext];
        [fetchRequest setEntity:entity];
        // Specify criteria for filtering which objects to fetch
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bareJidStr = %@", self.userJid.bare];
        [fetchRequest setPredicate:predicate];
        // Specify how the fetched objects should be sorted
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES];
        [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
        
        _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[XMPPMessageArchivingCoreDataStorage sharedInstance].mainThreadManagedObjectContext sectionNameKeyPath:nil cacheName:@"messages"];
        
        _fetchedResultsController.delegate = self;
    }
    return _fetchedResultsController;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // 清除緩存
    [NSFetchedResultsController deleteCacheWithName:@"messages"];
    // 查詢聊天記錄
    [self.fetchedResultsController performFetch:nil];
    // 數(shù)據(jù)賦值
    self.chatArrs = self.fetchedResultsController.fetchedObjects;
    // 刷新
    [self.tableView reloadData];
}

7). 發(fā)送消息

    // 發(fā)消息--私聊
    XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.userJid];
    // 發(fā)消息--群聊
//    XMPPMessage *message = [XMPPMessage messageWithType:@"group" to:self.userJid];
    // 設(shè)置消息
    [message addBody:self.message.text];
    // 發(fā)消息
    [[MTStreamManager sharedManager].xmppStream sendElement:message];

8). 獲取最近聯(lián)系人

@interface MTRecentlyTableViewController () <NSFetchedResultsControllerDelegate, XMPPvCardAvatarDelegate>
// 控制器查詢數(shù)據(jù)
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
// 最近聯(lián)系人數(shù)組
@property (nonatomic, strong) NSArray *recentlyArrs;
@end

@implementation MTRecentlyTableViewController

// 懶加載數(shù)組
- (NSArray *)recentlyArrs {
    if (nil == _recentlyArrs) {
        _recentlyArrs = [NSArray array];
    }
    return _recentlyArrs;
}

// 懶加載控制器
- (NSFetchedResultsController *)fetchedResultsController {
    if (nil == _fetchedResultsController) {
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Contact_CoreDataObject" inManagedObjectContext:[XMPPMessageArchivingCoreDataStorage sharedInstance].mainThreadManagedObjectContext];
        [fetchRequest setEntity:entity];
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"mostRecentMessageTimestamp" ascending:NO];
        [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
        // 創(chuàng)建控制器
        _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[XMPPMessageArchivingCoreDataStorage sharedInstance].mainThreadManagedObjectContext sectionNameKeyPath:nil cacheName:@"Recently"];
        // 設(shè)置代理
        _fetchedResultsController.delegate = self;
    }
    return _fetchedResultsController;
}

// NSFetchedResultsController代理, 當(dāng)查詢的內(nèi)容發(fā)生改變的時候會調(diào)用此方法
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // 數(shù)據(jù)獲取
    self.recentlyArrs = self.fetchedResultsController.fetchedObjects;
    // 數(shù)據(jù)刷新
    [self.tableView reloadData];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // 清楚緩存數(shù)據(jù)
    [NSFetchedResultsController deleteCacheWithName:@"Recently"];
    // 數(shù)據(jù)查詢
    [self.fetchedResultsController performFetch:nil];
    // 數(shù)組賦值
    self.recentlyArrs = self.fetchedResultsController.fetchedObjects;
    // 刷新列表
    [self.tableView reloadData];
}

7. 資料模塊

1). 在XMPPFramework.h中添加

// 自己個人資料模塊
#import "XMPPvCardTempModule.h"
// 個人資料內(nèi)存存儲
#import "XMPPvCardTemp.h"
// 個人資料的存儲器,自己和別人
#import "XMPPvCardCoreDataStorage.h"
// 個人資料的實(shí)體對象
#import "XMPPvCardCoreDataStorageObject.h"
// 好友的個人資料
#import "XMPPvCardAvatarModule.h"
// 好友個人資料實(shí)體對象
#import "XMPPvCardAvatarCoreDataStorageObject.h"

2). 在MTStreamManager.h中添加屬性

// 自己個人資料的功能類
@property (nonatomic, strong) XMPPvCardTempModule *xmppvCardTempModule;

// 好友個人資料
@property (nonatomic, strong) XMPPvCardAvatarModule *xmppvCardAvatarModule;

3). 在MTStreamManager.m中懶加載xmppvCardTempModule,xmppvCardAvatarModule

// 自己的個人資料
- (XMPPvCardTempModule *)xmppvCardTempModule {
    if (nil == _xmppvCardTempModule) {
        // 創(chuàng)建對象
        _xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:[XMPPvCardCoreDataStorage sharedInstance] dispatchQueue:dispatch_get_main_queue()];
    }
    return _xmppvCardTempModule;
}

// 指定的用戶的個人資料
- (XMPPvCardAvatarModule *)xmppvCardAvatarModule {
    if (nil == _xmppvCardAvatarModule) {
        // 創(chuàng)建
        _xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_xmppvCardTempModule dispatchQueue:dispatch_get_main_queue()];
    }
    return _xmppvCardAvatarModule;
}

4). 在XMPPFramework.m中的activite方法中進(jìn)行激活

// 激活其他模塊
- (void) activite {
    // 激活斷線重連
    [self.xmppReconnect activate:self.xmppStream];
    // 激活心跳檢測
    [self.xmppAutoPing activate:self.xmppStream];
    // 激活好友模塊
    [self.xmppRoster activate:self.xmppStream];
    // 激活聊天模塊
    [self.xmppMessageArchiving activate:self.xmppStream];
    // 激活個人資料
    [self.xmppvCardTempModule activate:self.xmppStream];
    // 好友的個人資料
    [self.xmppvCardAvatarModule activate:self.xmppStream];
}

5). 查詢用戶資料

@interface MTMeTableViewController () <XMPPvCardTempModuleDelegate>
// 頭像
@property (weak, nonatomic) IBOutlet UIImageView *icon;
// JID
@property (weak, nonatomic) IBOutlet UILabel *name;
// 昵稱
@property (weak, nonatomic) IBOutlet UILabel *nickName;
// 個性簽名
@property (weak, nonatomic) IBOutlet UILabel *desc;

// 內(nèi)存存儲個人信息
@property (nonatomic, strong) XMPPvCardTemp *myvCardTemp;
@end

@implementation MTMeTableViewController

// 懶加載獲取存儲數(shù)據(jù)
- (XMPPvCardTemp *)myvCardTemp {
    if (nil == _myvCardTemp) {
        _myvCardTemp = [MTStreamManager sharedManager].xmppvCardTempModule.myvCardTemp;
    }
    return _myvCardTemp;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // 設(shè)置代理,需要更新用戶資料的界面都要實(shí)現(xiàn)這個代理
    [[MTStreamManager sharedManager].xmppvCardTempModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
    // 設(shè)置參數(shù)
    [self update];
}

// 更新
- (void)update {
    // 頭像
    self.icon.image = [UIImage imageWithData:self.myvCardTemp.photo];
    // 名字
    self.name.text = [MTStreamManager sharedManager].xmppStream.myJID.bare;
    // 昵稱
    self.nickName.text = self.myvCardTemp.nickname;
    // 個性簽名
    self.desc.text = self.myvCardTemp.description;
}

// 更新馁龟,需要更新用戶資料的界面都要實(shí)現(xiàn)這個代理
- (void)xmppvCardTempModuleDidUpdateMyvCard:(XMPPvCardTempModule *)vCardTempModule {
    // 清除之前的內(nèi)存
    self.myvCardTemp = nil;
    // 重新賦值最新的數(shù)據(jù)
    [self update];
}

@end

6). 更新頭像

// 點(diǎn)擊頭像時執(zhí)行的方法
// 選擇照片--換頭像    
- (IBAction)pickerImage:(id)sender {
    // 相冊
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    // 參數(shù)設(shè)置
    picker.allowsEditing = YES;
    // 設(shè)置代理
    picker.delegate = self;
    // 彈出控制器
    [self.navigationController presentViewController:picker animated:YES completion:nil];
}

// 選中照片
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
    NSLog(@"info = %@", info);
    // 獲取圖片
    UIImage *image = info[UIImagePickerControllerEditedImage];
    // 裝換為二進(jìn)制數(shù)據(jù)
    NSData *imageData = UIImageJPEGRepresentation(image, 0.2);
    // 內(nèi)存存儲
    self.xmppvCardTemp.photo = imageData;
    // 數(shù)據(jù)更新
    [[MTStreamManager sharedManager].xmppvCardTempModule updateMyvCardTemp:self.xmppvCardTemp];
    // 銷毀控制器
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
}

// 取消選中
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    // 銷毀控制器
    [self.navigationController dismissViewControllerAnimated:YES completion:nil];
}

7). 更新昵稱或者個性簽名


@interface MTUpdateTableViewController ()
// 信息輸入框
@property (weak, nonatomic) IBOutlet UITextField *textMessage;
// 內(nèi)存存儲
@property (nonatomic, strong) XMPPvCardTemp *myvCardTemp;
@end

@implementation MTUpdateTableViewController

// 懶加載
- (XMPPvCardTemp *)myvCardTemp {
    if (nil == _myvCardTemp) {
        _myvCardTemp = [MTStreamManager sharedManager].xmppvCardTempModule.myvCardTemp;
    }
    return _myvCardTemp;
}

// 取消按鈕
- (IBAction)cancel:(id)sender {
    // 關(guān)閉當(dāng)前控制器
    [self.navigationController popViewControllerAnimated:YES];
}

// 更新數(shù)據(jù)
- (IBAction)update:(id)sender {
    // 數(shù)據(jù)更新
    if ([self.title isEqualToString:@"昵稱"]) {
        // 對昵稱做更新
        self.myvCardTemp.nickname = self.textMessage.text;
    } else {
        // 對個性簽名做更新
        self.myvCardTemp.description = self.textMessage.text;
    }
    // 更新數(shù)據(jù)
    [[MTStreamManager sharedManager].xmppvCardTempModule updateMyvCardTemp:self.myvCardTemp];
    // 關(guān)閉當(dāng)前控制器
    [self.navigationController popViewControllerAnimated:YES];
}

8. 群聊

1). 在XMPPFramework.h中添加

// 群聊功能類
#import "XMPPMUC.h"
// 聊天室功能類
#import "XMPPRoom.h"
// 數(shù)據(jù)存儲管理
#import "XMPPRoomCoreDataStorage.h"

2). 新建群聊管理類
MTMucRoomManager.h 頭文件

@interface MTMucRoomManager : NSObject
// 多用戶聊天功能類
@property (nonatomic, strong) XMPPMUC *xmppMuc;
// 聊天室功能類
@property (nonatomic, strong) XMPPRoom *xmppRoom;

// 單例
+ (instancetype)sharedMucRoom;

// 加入或者創(chuàng)建聊天室
- (void)joinOrCreateWithRoomJid:(XMPPJID *)roomJid andNickName:(NSString *)nickName;
@end

MTMucRoomManager.m 實(shí)現(xiàn)

@interface MTMucRoomManager () <XMPPMUCDelegate, XMPPRoomDelegate>

// 用來存儲聊天室的字典
@property (nonatomic, strong) NSMutableDictionary *roomDict;

@end

@implementation MTMucRoomManager

static MTMucRoomManager *sInstance;
// 單例
+ (instancetype)sharedMucRoom {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sInstance = [MTMucRoomManager new];
    });
    return sInstance;
}

// 懶加載字典
- (NSMutableDictionary *)roomDict {
    if (nil == _roomDict) {
        // 創(chuàng)建字典
        _roomDict = [NSMutableDictionary dictionary];
    }
    return _roomDict;
}

// 多用戶聊天功能類
- (XMPPMUC *)xmppMuc {
    if (nil == _xmppMuc) {
        // 創(chuàng)建
        _xmppMuc = [[XMPPMUC alloc] initWithDispatchQueue:dispatch_get_main_queue()];
        // 設(shè)置代理
        [_xmppMuc addDelegate:self delegateQueue:dispatch_get_main_queue()];
        // 激活
        [_xmppMuc activate:[MTStreamManager sharedManager].xmppStream];
    }
    return _xmppMuc;
}

// 聊天室功能類
- (XMPPRoom *)xmppRoom {
    if (nil == _xmppRoom) {
        // 創(chuàng)建對象
        _xmppRoom = [[XMPPRoom alloc] initWithDispatchQueue:dispatch_get_main_queue()];
    }
    return _xmppRoom;
}

// 加入或者創(chuàng)建聊天室
- (void)joinOrCreateWithRoomJid:(XMPPJID *)roomJid andNickName:(NSString *)nickName {
    // 創(chuàng)建房間
    XMPPRoom *room = [[XMPPRoom alloc] initWithRoomStorage:[XMPPRoomCoreDataStorage sharedInstance] jid:roomJid dispatchQueue:dispatch_get_main_queue()];
    // 激活
    [room activate:[MTStreamManager sharedManager].xmppStream];
    // 存放在字典中
    self.roomDict[roomJid] = room;
    // 加入房間
    [room joinRoomUsingNickname:nickName history:nil];
    // 設(shè)置代理
    [room addDelegate:self delegateQueue:dispatch_get_main_queue()];
}

#pragma mark 回調(diào)
// 加入
- (void)xmppRoomDidJoin:(XMPPRoom *)sender {
    // 對房間進(jìn)行配置
    [sender configureRoomUsingOptions:nil];
    // 測試方法--需先要在控制臺中創(chuàng)建分組與房間
    XMPPJID *jid = [XMPPJID jidWithUser:@"linghaoyu9" domain:DO_MAIN resource:nil];
    // 邀請加入
    [sender inviteUser:jid withMessage:@"來聊天"];
}

// 創(chuàng)建
- (void)xmppRoomDidCreate:(XMPPRoom *)sender {
    
}

@end

3). 加入聊天室

    XMPPJID *jid = [XMPPJID jidWithUser:@"love" domain:@"tochat.mazaiting.com" resource:nil];
    // 加入到房間
    [[MTMucRoomManager sharedMucRoom] joinOrCreateWithRoomJid:jid andNickName:@"小魚"];

4). 測試

  • 需要先在控制臺中創(chuàng)建分組


    圖12.jpg
  • 其次在控制臺中創(chuàng)建分組


    圖13.jpg
  • 完成發(fā)消息

示例地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市漆魔,隨后出現(xiàn)的幾起案子坷檩,更是在濱河造成了極大的恐慌,老刑警劉巖改抡,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矢炼,死亡現(xiàn)場離奇詭異,居然都是意外死亡阿纤,警方通過查閱死者的電腦和手機(jī)句灌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來欠拾,“玉大人胰锌,你說我怎么就攤上這事∶暾” “怎么了资昧?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長荆忍。 經(jīng)常有香客問我格带,道長撤缴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任叽唱,我火速辦了婚禮屈呕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘尔觉。我一直安慰自己凉袱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布侦铜。 她就那樣靜靜地躺著专甩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钉稍。 梳的紋絲不亂的頭發(fā)上涤躲,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機(jī)與錄音贡未,去河邊找鬼种樱。 笑死,一個胖子當(dāng)著我的面吹牛俊卤,可吹牛的內(nèi)容都是我干的嫩挤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼消恍,長吁一口氣:“原來是場噩夢啊……” “哼岂昭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起狠怨,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤约啊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后佣赖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恰矩,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年憎蛤,在試婚紗的時候發(fā)現(xiàn)自己被綠了外傅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡俩檬,死狀恐怖栏豺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情豆胸,我是刑警寧澤奥洼,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站晚胡,受9級特大地震影響灵奖,放射性物質(zhì)發(fā)生泄漏嚼沿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一瓷患、第九天 我趴在偏房一處隱蔽的房頂上張望骡尽。 院中可真熱鬧,春花似錦擅编、人聲如沸攀细。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谭贪。三九已至,卻和暖如春锦担,著一層夾襖步出監(jiān)牢的瞬間俭识,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工洞渔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留套媚,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓磁椒,卻偏偏與公主長得像堤瘤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浆熔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容