XMPPFramework
1. 導(dǎo)入源碼
1). 將下載好的XMPPFramework解壓,解壓后的目錄如下:
2). 將Sample_XMPPFramework.h更名為XMPPFramework.h滋早,然后將XMPPFramework-3.6.4文件夾直接拖入要使用該框架的工程中,然后刪除將XMPPFramwork-3.6.4文件夾中的文件夾(除Xcode文件夾)及XMPPFramework.h文件保留驳概,其他文件刪除,刪除后結(jié)構(gòu)如圖3旷赖,編譯抡句。
3). 解決錯誤I
解決辦法:
- 在Build Settings 搜索Header Search Paths 添加頭文件搜索路徑:
/usr/include/libxml2
- 在Build Phasses->Link Binary With Libraries中添加兩個動態(tài)鏈接庫:
libxml2.tbd
、libresolv.tbd
- 在Build Settings 搜索prefix Header杠愧,在Prefix Header中添加
$SRCROOT/$(PRODUCT_NAME)/PrefixHeader.pch
- 在項(xiàng)目的根目錄下新建pch文件:Other->PCH File待榔。
4). 編譯, 報如下錯誤:
解決辦法:
- 在PrefixHeader.pch中添加頭文件
#import <UIKit/UIKit.h>
流济,添加后內(nèi)容如下:
5). 編譯锐锣,此時如果不出現(xiàn)意外,就可以成功編譯绳瘟。但我在編譯時出現(xiàn)如下錯誤:
問題原因:重復(fù)定義
解決辦法:找到對應(yīng)的位置雕憔,將34行注釋,因此是重復(fù)定義糖声,因此注釋之后對源碼沒有影響斤彼。
6). 成功編譯
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
注冊后可在管理控制臺中查看
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)閉連接將其斷開去团,然后刷新頁面,如果成功登陸穷蛹,則斷線重連功能完成土陪。
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)建分組
-
其次在控制臺中創(chuàng)建分組
- 完成發(fā)消息