天天看点

XMPPFramework 使用(Mac)

XMPPFramework

1. 导入源码

1). 将下载好的XMPPFramework解压,解压后的目录如下:

XMPPFramework 使用(Mac)

图1.png

2). 将Sample_XMPPFramework.h更名为XMPPFramework.h,然后将XMPPFramework-3.6.4文件夹直接拖入要使用该框架的工程中,然后删除将XMPPFramwork-3.6.4文件夹中的文件夹(除Xcode文件夹)及XMPPFramework.h文件保留,其他文件删除,删除后结构如图3,编译。

XMPPFramework 使用(Mac)

图2.png

XMPPFramework 使用(Mac)

图3.png

3). 解决错误I

XMPPFramework 使用(Mac)

图4.png

解决办法:

  • 在Build Settings 搜索Header Search Paths 添加头文件搜索路径:

    /usr/include/libxml2

  • 在Build Phasses->Link Binary With Libraries中添加两个动态链接库:

    libxml2.tbd

    libresolv.tbd

  • 在Build Settings 搜索prefix Header,在Prefix Header中添加

    $SRCROOT/$(PRODUCT_NAME)/PrefixHeader.pch

  • 在项目的根目录下新建pch文件:Other->PCH File。

4). 编译, 报如下错误:

XMPPFramework 使用(Mac)

图5.png

解决办法:

  • 在PrefixHeader.pch中添加头文件

    #import <UIKit/UIKit.h>

    ,添加后内容如下:
    XMPPFramework 使用(Mac)
    图6.png

5). 编译,此时如果不出现意外,就可以成功编译。但我在编译时出现如下错误:

XMPPFramework 使用(Mac)

图7.png

问题原因:重复定义

解决办法:找到对应的位置,将34行注释,因此是重复定义,因此注释之后对源码没有影响。

XMPPFramework 使用(Mac)

图8.png

6). 成功编译

XMPPFramework 使用(Mac)

图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;

// 创建XMPPStream流
@property (nonatomic, strong) XMPPStream *xmppStream;

// 存储密码
@property (nonatomic, copy) NSString *password;

// 区别注册还是登陆
@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];
        // 设置日志打印
        [DDLog addLogger:[DDTTYLogger sharedInstance]];
        // 设置日志等级
        [DDLog setLogLevel:XMPP_LOG_FLAG_SEND_RECV forClass:self];
    });
    return sInstance;
}

// 懒加载XMPPStream
- (XMPPStream *)xmppStream {
    if (nil == _xmppStream) {
        // 创建
        _xmppStream = [[XMPPStream alloc] init];
        // 设置属性
        // ip
        _xmppStream.hostName = @"127.0.0.1";
        // 端口
        _xmppStream.hostPort = 5222;
        // 设置代理--多播代理
        [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    return _xmppStream;
}

// 注册
- (void) registWithName:(NSString *)name andPassword:(NSString *)password {
    // 创建一个JID
    XMPPJID *jid = [XMPPJID jidWithUser:name domain:DO_MAIN resource:nil];
    // 设置MyJID
    [self.xmppStream setMyJID:jid];
    // 设置密码
    self.password = password;
    // 设置状态为注册
    self.connectStatus = connectToSerRegist;
    // 连接到服务器
    [self connectServer];
}

// 登陆
- (void) loginWithName:(NSString *)name andPassword:(NSString *)password {
    // 创建一个JID
    XMPPJID *jid = [XMPPJID jidWithUser:name domain:DO_MAIN resource:nil];
    // 设置MyJID
    [self.xmppStream setMyJID:jid];
    // 设置密码
    self.password = password;
    // 设置状态为注册
    self.connectStatus = connectToSerLogin;
    // 连接到服务器
    [self connectServer];
}

// 连接到服务器
- (void)connectServer {
    // 判断当前是否有连接,如果有则断开
    if ([self.xmppStream isConnected]) {
        // 退出登陆
        [self logout];
    }
    // 异常信息
    NSError *error = nil;
    // 连接服务器
    [self.xmppStream connectWithTimeout:15.0f error:&error];
    // 判断是否连接成功
    if (error) {
        NSLog(@"连接失败");
    }
}

// 退出登陆
- (void) logout {
    // 用户状态类
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    // 向服务器发送离线通知
    [self.xmppStream sendElement:presence];
    // 断开连接
    [self.xmppStream disconnect];
}

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

#pragma mark 代理方法,连接成功之后回调
- (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 代理方法,登陆成功之后告诉服务器我要出席
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
    // 如果成功,可以出席
    XMPPPresence *presence = [XMPPPresence presence];
    // 添加出席状态
    [presence addChild:[DDXMLElement elementWithName:@"show" stringValue:@"dnd"]];
    [presence addChild:[DDXMLElement elementWithName:@"status" stringValue:@"请勿打扰"]];
    // 告诉服务器我要出席
    [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
           

注册后可在管理控制台中查看

XMPPFramework 使用(Mac)

图10.png

3. 断线重连

1). 在XMPPFramework.h中添加

// 自动重连
#import "XMPPReconnect.h"
           

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

// 创建自动重连对象
@property (nonatomic, strong) XMPPReconnect *xmppReconnect;
           

3). 在MTStreamManager.m中懒加载xmppReconnect

// 懒加载断线重连
- (XMPPReconnect *)xmppReconnect {
    if (nil == _xmppReconnect) {
        // 创建对象
        _xmppReconnect = [[XMPPReconnect alloc] initWithDispatchQueue:dispatch_get_main_queue()];
        // 设置参数
        _xmppReconnect.reconnectTimerInterval = 2;
    }
    return _xmppReconnect;
}
           

4). 在XMPPFramework.m中的activite方法中进行激活

// 激活其他模块
- (void) activite {
    // 激活断线重连
    [self.xmppReconnect activate:self.xmppStream];
}
           

5). 测试方法

进入管理控制台中,选择会话,把登陆的用户点击右侧的关闭连接将其断开,然后刷新页面,如果成功登陆,则断线重连功能完成。

XMPPFramework 使用(Mac)

图11.png

4. 心跳检测

// 心跳检测
#import "XMPPAutoPing.h"
           
// 创建心跳检测对象
@property (nonatomic, strong) XMPPAutoPing *xmppAutoPing;
           

3). 在MTStreamManager.m中懒加载xmppAutoPing

// 心跳检测
- (XMPPAutoPing *)xmppAutoPing {
    if (nil == _xmppAutoPing) {
        // 创建心跳检测
        _xmppAutoPing = [[XMPPAutoPing alloc] initWithDispatchQueue:dispatch_get_main_queue()];
        // 设置参数
        _xmppAutoPing.pingInterval = 3;
    }
    return _xmppAutoPing;
}
           
// 激活其他模块
- (void) activite {
    // 激活断线重连
    [self.xmppReconnect activate:self.xmppStream];
    // 激活心跳检测
    [self.xmppAutoPing activate:self.xmppStream];
}
           

运行程序后查看控制台打印,如果一直在不断的刷新,则证明心跳检测开启。

5. 好友功能模块

// 好友角色
#import "XMPPRoster.h"
// 好友存储管理
#import "XMPPRosterCoreDataStorage.h"
// 好友的实体
#import "XMPPUserCoreDataStorageObject.h"
           
// 创建好友列表功能模块
@property (nonatomic, strong) XMPPRoster *xmppRoster;
           

3). 在MTStreamManager.m中懒加载xmppRoster

// 好友列表功能
- (XMPPRoster *)xmppRoster {
    if (nil == _xmppRoster) {
        // 创建对象
        _xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:[XMPPRosterCoreDataStorage sharedInstance] dispatchQueue:dispatch_get_global_queue(0, 0)];
        // 设置参数
        // 是否自动查找新的好友数据
        _xmppRoster.autoFetchRoster = YES;
        // 是否自动删除用户存储的数据,不需要
        _xmppRoster.autoClearAllUsersAndResources = NO;
        // 如果自动接收XMPP,会帮我们做一个加好友的操作,代理方法也不会被调用了
        _xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = NO;
        //设置代理,,注意让MTStreamManager实现XMPPRosterDelegate协议
        [_xmppRoster addDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
    }
    return _xmppRoster;
}
           
// 激活其他模块
- (void) activite {
    // 激活断线重连
    [self.xmppReconnect activate:self.xmppStream];
    // 激活心跳检测
    [self.xmppAutoPing activate:self.xmppStream];
    // 激活好友模块
    [self.xmppRoster activate:self.xmppStream];
}
           

5). 使用

  • 使用查询控制器来查询数据
@interface MTContactTableViewController () <NSFetchedResultsControllerDelegate>
// 查询控制器,用来查询好友
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
// 好友列表数组
@property (nonatomic, strong) NSArray *contactArrs;
@end

@implementation MTContactTableViewController

// 懒加载联系人数组
- (NSArray *)contactArrs {
    if (nil == _contactArrs) {
        _contactArrs = [NSArray array];
    }
    return _contactArrs;
}

// 懒加载fetchedResultsController,执行查询操作
- (NSFetchedResultsController *)fetchedResultsController {
    if (nil == _fetchedResultsController) {
        // 创建一个查询请求
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        // 实体
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPUserCoreDataStorageObject" inManagedObjectContext:[XMPPRosterCoreDataStorage sharedInstance].mainThreadManagedObjectContext];
        // 谓词, 查询只有双方都是对方的好友的人
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"subscription = %@", @"both"];
        // 排序, 根据jidStr进行升序排列
        NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"jidStr" ascending:YES];
        // 设置实体
        fetchRequest.entity = entity;
        // 设置谓词
        fetchRequest.predicate = predicate;
        // 设置排序
        fetchRequest.sortDescriptors = @[sortDescriptor];
        // 创建fetchedResultsController对象
        _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[XMPPRosterCoreDataStorage sharedInstance].mainThreadManagedObjectContext sectionNameKeyPath:nil cacheName:@"contacts"];
        // 设置代理, 实现协议NSFetchedResultsControllerDelegate
        _fetchedResultsController.delegate = self;
    }
    return _fetchedResultsController;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 删除CoreData中的缓存
    [NSFetchedResultsController deleteCacheWithName:@"contacts"];
    // 好友代理设置, 实现XMPPRosterDelegate
    [[MTStreamManager sharedManager].xmppRoster addDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
    // 执行查询操作, 查询到之后将数据保存在了fetchedObjects变量中
    [self.fetchedResultsController performFetch:nil];
    // 获取到数据
    self.contactArrs = self.fetchedResultsController.fetchedObjects;
    // 刷新数据
    [self.tableView reloadData];
}
}
#pragma mark - NSFetchedResultsController协议
// 当CoreData数据发生变化会调用该代理方法
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    NSLog(@"数据发生改变");
    // 最新的列表
    self.contactArrs = self.fetchedResultsController.fetchedObjects;
    // 刷新数据
    [self.tableView reloadData];
}

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

// 设置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"];
    // 获取对应行的联系人数据
    XMPPUserCoreDataStorageObject *contact = self.contactArrs[indexPath.row];
    
    // 给Cell赋值
    // 设置JID
    UILabel *nameLabel = (UILabel *)[cell viewWithTag:1002];
    nameLabel.text = contact.jidStr;

    return cell;
}
@end
           

6). 添加删除好友

  • 主动申请添加好友
// 创建XMPPJID
    XMPPJID *jid = [XMPPJID jidWithUser:@"linghaoyu9" domain:DO_MAIN resource:nil];
    // 添加好友
//    [[MTStreamManager sharedManager].xmppRoster addUser:jid withNickname:@"加好友"];
    [[MTStreamManager sharedManager].xmppRoster subscribePresenceToUser:jid];
           
  • 同意对方的请求
// 创建XMPPJID
    XMPPJID *jid = [XMPPJID jidWithUser:@"linghaoyu9" domain:DO_MAIN resource:nil];
    // 同意添加对方为好友
    [[MTStreamManager sharedManager].xmppRoster acceptPresenceSubscriptionRequestFrom:jid andAddToRoster:YES];
           
  • 删除好友
// 创建XMPPJID
    XMPPJID *jid = [XMPPJID jidWithUser:@"linghaoyu9" domain:DO_MAIN resource:nil];
// 删除好友
        [[MTStreamManager sharedManager].xmppRoster removeUser:jid];
           

6. 聊天模块

// 聊天模块
#import "XMPPMessageArchiving.h"
// 聊天信息的存储管理
#import "XMPPMessageArchivingCoreDataStorage.h" 
// 消息实体
#import "XMPPMessageArchiving_Message_CoreDataObject.h"
// 最近联系人实体
#import "XMPPMessageArchiving_Contact_CoreDataObject.h"
           
// 创建聊天功能模块
@property (nonatomic, strong) XMPPMessageArchiving *xmppMessageArchiving;
           

3). 在MTStreamManager.m中懒加载xmppMessageArchiving

// 消息模块
- (XMPPMessageArchiving *)xmppMessageArchiving {
    if (nil == _xmppMessageArchiving) {
        // 创建对象
        _xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:[XMPPMessageArchivingCoreDataStorage sharedInstance] dispatchQueue:dispatch_get_main_queue()];
    }
    return _xmppMessageArchiving;
}
           
// 激活其他模块
- (void) activite {
    // 激活断线重连
    [self.xmppReconnect activate:self.xmppStream];
    // 激活心跳检测
    [self.xmppAutoPing activate:self.xmppStream];
    // 激活好友模块
    [self.xmppRoster activate:self.xmppStream];
    // 激活聊天模块
    [self.xmppMessageArchiving activate:self.xmppStream];
}
           

5). 实现XMPPStreamDelegate协议中的xmppStream:didReceiveMessage:方法, 用来接收消息

  • MTStreamManager.m中
// 通过代理接收数据
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
    NSLog(@"接收到的消息: %@", message.body);
    // 发送本地通知,在AppDelegate中接收通知
    UILocalNotification *noti = [[UILocalNotification alloc] init];
    [noti setAlertBody:[NSString stringWithFormat:@"来自%@ : %@ 消息", message.from, message.body]];
    // 设置appicon图标
    [noti setApplicationIconBadgeNumber:1];
    // 弹出本地通知
    [[UIApplication sharedApplication] presentLocalNotificationNow:noti];
}
           
  • AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 需要一个用户通知设置, 用来接收通知
    UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound|UIUserNotificationTypeAlert|UIUserNotificationTypeBadge categories:nil];
    // 注册
    [[UIApplication sharedApplication] registerUserNotificationSettings:setting];
    return YES;
}
           

6). 查询消息

@interface MTChatViewController () <NSFetchedResultsControllerDelegate> {
// 消息列表查询控制器
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
// 消息数组
@property (nonatomic, strong) NSArray *chatArrs;
}
// -----------------具体实现
// 懒加载数组
- (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];
    // 数据赋值
    self.chatArrs = self.fetchedResultsController.fetchedObjects;
    // 刷新
    [self.tableView reloadData];
}
           

7). 发送消息

// 发消息--私聊
    XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.userJid];
    // 发消息--群聊
//    XMPPMessage *message = [XMPPMessage messageWithType:@"group" to:self.userJid];
    // 设置消息
    [message addBody:self.message.text];
    // 发消息
    [[MTStreamManager sharedManager].xmppStream sendElement:message];
           

8). 获取最近联系人

@interface MTRecentlyTableViewController () <NSFetchedResultsControllerDelegate, XMPPvCardAvatarDelegate>
// 控制器查询数据
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
// 最近联系人数组
@property (nonatomic, strong) NSArray *recentlyArrs;
@end

@implementation MTRecentlyTableViewController

// 懒加载数组
- (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]];
        // 创建控制器
        _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[XMPPMessageArchivingCoreDataStorage sharedInstance].mainThreadManagedObjectContext sectionNameKeyPath:nil cacheName:@"Recently"];
        // 设置代理
        _fetchedResultsController.delegate = self;
    }
    return _fetchedResultsController;
}

// NSFetchedResultsController代理, 当查询的内容发生改变的时候会调用此方法
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // 数据获取
    self.recentlyArrs = self.fetchedResultsController.fetchedObjects;
    // 数据刷新
    [self.tableView reloadData];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // 清楚缓存数据
    [NSFetchedResultsController deleteCacheWithName:@"Recently"];
    // 数据查询
    [self.fetchedResultsController performFetch:nil];
    // 数组赋值
    self.recentlyArrs = self.fetchedResultsController.fetchedObjects;
    // 刷新列表
    [self.tableView reloadData];
}
           

7. 资料模块

// 自己个人资料模块
#import "XMPPvCardTempModule.h"
// 个人资料内存存储
#import "XMPPvCardTemp.h"
// 个人资料的存储器,自己和别人
#import "XMPPvCardCoreDataStorage.h"
// 个人资料的实体对象
#import "XMPPvCardCoreDataStorageObject.h"
// 好友的个人资料
#import "XMPPvCardAvatarModule.h"
// 好友个人资料实体对象
#import "XMPPvCardAvatarCoreDataStorageObject.h"
           
// 自己个人资料的功能类
@property (nonatomic, strong) XMPPvCardTempModule *xmppvCardTempModule;

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

3). 在MTStreamManager.m中懒加载xmppvCardTempModule,xmppvCardAvatarModule

// 自己的个人资料
- (XMPPvCardTempModule *)xmppvCardTempModule {
    if (nil == _xmppvCardTempModule) {
        // 创建对象
        _xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:[XMPPvCardCoreDataStorage sharedInstance] dispatchQueue:dispatch_get_main_queue()];
    }
    return _xmppvCardTempModule;
}

// 指定的用户的个人资料
- (XMPPvCardAvatarModule *)xmppvCardAvatarModule {
    if (nil == _xmppvCardAvatarModule) {
        // 创建
        _xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_xmppvCardTempModule dispatchQueue:dispatch_get_main_queue()];
    }
    return _xmppvCardAvatarModule;
}

           
// 激活其他模块
- (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;

// 内存存储个人信息
@property (nonatomic, strong) XMPPvCardTemp *myvCardTemp;
@end

@implementation MTMeTableViewController

// 懒加载获取存储数据
- (XMPPvCardTemp *)myvCardTemp {
    if (nil == _myvCardTemp) {
        _myvCardTemp = [MTStreamManager sharedManager].xmppvCardTempModule.myvCardTemp;
    }
    return _myvCardTemp;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // 设置代理,需要更新用户资料的界面都要实现这个代理
    [[MTStreamManager sharedManager].xmppvCardTempModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
    // 设置参数
    [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;
}

// 更新,需要更新用户资料的界面都要实现这个代理
- (void)xmppvCardTempModuleDidUpdateMyvCard:(XMPPvCardTempModule *)vCardTempModule {
    // 清除之前的内存
    self.myvCardTemp = nil;
    // 重新赋值最新的数据
    [self update];
}

@end
           

6). 更新头像

// 点击头像时执行的方法
// 选择照片--换头像    
- (IBAction)pickerImage:(id)sender {
    // 相册
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    // 参数设置
    picker.allowsEditing = YES;
    // 设置代理
    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];
    // 装换为二进制数据
    NSData *imageData = UIImageJPEGRepresentation(image, 0.2);
    // 内存存储
    self.xmppvCardTemp.photo = imageData;
    // 数据更新
    [[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;
// 内存存储
@property (nonatomic, strong) XMPPvCardTemp *myvCardTemp;
@end

@implementation MTUpdateTableViewController

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

// 取消按钮
- (IBAction)cancel:(id)sender {
    // 关闭当前控制器
    [self.navigationController popViewControllerAnimated:YES];
}

// 更新数据
- (IBAction)update:(id)sender {
    // 数据更新
    if ([self.title isEqualToString:@"昵称"]) {
        // 对昵称做更新
        self.myvCardTemp.nickname = self.textMessage.text;
    } else {
        // 对个性签名做更新
        self.myvCardTemp.description = self.textMessage.text;
    }
    // 更新数据
    [[MTStreamManager sharedManager].xmppvCardTempModule updateMyvCardTemp:self.myvCardTemp];
    // 关闭当前控制器
    [self.navigationController popViewControllerAnimated:YES];
}
           

8. 群聊

// 群聊功能类
#import "XMPPMUC.h"
// 聊天室功能类
#import "XMPPRoom.h"
// 数据存储管理
#import "XMPPRoomCoreDataStorage.h"
           

2). 新建群聊管理类

MTMucRoomManager.h 头文件

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

// 单例
+ (instancetype)sharedMucRoom;

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

MTMucRoomManager.m 实现

@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) {
        // 创建字典
        _roomDict = [NSMutableDictionary dictionary];
    }
    return _roomDict;
}

// 多用户聊天功能类
- (XMPPMUC *)xmppMuc {
    if (nil == _xmppMuc) {
        // 创建
        _xmppMuc = [[XMPPMUC alloc] initWithDispatchQueue:dispatch_get_main_queue()];
        // 设置代理
        [_xmppMuc addDelegate:self delegateQueue:dispatch_get_main_queue()];
        // 激活
        [_xmppMuc activate:[MTStreamManager sharedManager].xmppStream];
    }
    return _xmppMuc;
}

// 聊天室功能类
- (XMPPRoom *)xmppRoom {
    if (nil == _xmppRoom) {
        // 创建对象
        _xmppRoom = [[XMPPRoom alloc] initWithDispatchQueue:dispatch_get_main_queue()];
    }
    return _xmppRoom;
}

// 加入或者创建聊天室
- (void)joinOrCreateWithRoomJid:(XMPPJID *)roomJid andNickName:(NSString *)nickName {
    // 创建房间
    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];
    // 设置代理
    [room addDelegate:self delegateQueue:dispatch_get_main_queue()];
}

#pragma mark 回调
// 加入
- (void)xmppRoomDidJoin:(XMPPRoom *)sender {
    // 对房间进行配置
    [sender configureRoomUsingOptions:nil];
    // 测试方法--需先要在控制台中创建分组与房间
    XMPPJID *jid = [XMPPJID jidWithUser:@"linghaoyu9" domain:DO_MAIN resource:nil];
    // 邀请加入
    [sender inviteUser:jid withMessage:@"来聊天"];
}

// 创建
- (void)xmppRoomDidCreate:(XMPPRoom *)sender {
    
}

@end
           

3). 加入聊天室

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

4). 测试

  • 需要先在控制台中创建分组
    XMPPFramework 使用(Mac)
    图12.jpg
  • 其次在控制台中创建分组
    XMPPFramework 使用(Mac)
    图13.jpg
  • 完成发消息

示例地址