IOS XMPP(即时通讯的框架)

时间:2021-03-04 09:57:33
#import "AppDelegate.h"
#import "XMPPFramework.h"
/*
* 在AppDelegate实现登录 1. 初始化XMPPStream
2. 连接到服务器[传一个JID]
3. 连接到服务成功后,再发送密码授权
4. 授权成功后,发送"在线" 消息
*/
@interface AppDelegate ()<XMPPStreamDelegate>{
XMPPStream *_xmppStream;
} // 1. 初始化XMPPStream
-(void)setupXMPPStream; // 2.连接到服务器
-(void)connectToHost; // 3.连接到服务成功后,再发送密码授权
-(void)sendPwdToHost; // 4.授权成功后,发送"在线" 消息
-(void)sendOnlineToHost;
@end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 程序一启动就连接到主机
[self connectToHost];
return YES;
} #pragma mark -私有方法
#pragma mark 初始化XMPPStream
-(void)setupXMPPStream{ _xmppStream = [[XMPPStream alloc] init]; // 设置代理
[_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, )];
} #pragma mark 连接到服务器
-(void)connectToHost{
NSLog(@"开始连接到服务器");
if (!_xmppStream) {
[self setupXMPPStream];
} // 设置登录用户JID
//resource 标识用户登录的客户端 iphone android XMPPJID *myJID = [XMPPJID jidWithUser:@"wangwu" domain:@"teacher.local" resource:@"iphone" ];
_xmppStream.myJID = myJID; // 设置服务器域名
_xmppStream.hostName = @"teacher.local";//不仅可以是域名,还可是IP地址 // 设置端口 如果服务器端口是5222,可以省略
_xmppStream.hostPort = ; // 连接
NSError *err = nil;
if(![_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&err]){
NSLog(@"%@",err);
} } #pragma mark 连接到服务成功后,再发送密码授权
-(void)sendPwdToHost{
NSLog(@"再发送密码授权");
NSError *err = nil;
[_xmppStream authenticateWithPassword:@"" error:&err];
if (err) {
NSLog(@"%@",err);
}
} #pragma mark 授权成功后,发送"在线" 消息
-(void)sendOnlineToHost{ NSLog(@"发送 在线 消息");
XMPPPresence *presence = [XMPPPresence presence];
NSLog(@"%@",presence); [_xmppStream sendElement:presence]; }
#pragma mark -XMPPStream的代理
#pragma mark 与主机连接成功
-(void)xmppStreamDidConnect:(XMPPStream *)sender{
NSLog(@"与主机连接成功"); // 主机连接成功后,发送密码进行授权
[self sendPwdToHost];
}
#pragma mark 与主机断开连接
-(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error{
// 如果有错误,代表连接失败
NSLog(@"与主机断开连接 %@",error); } #pragma mark 授权成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
NSLog(@"授权成功"); [self sendOnlineToHost];
} #pragma mark 授权失败
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
NSLog(@"授权失败 %@",error);
} #pragma mark -公共方法
-(void)logout{
// 1." 发送 "离线" 消息"
XMPPPresence *offline = [XMPPPresence presenceWithType:@"unavailable"];
[_xmppStream sendElement:offline]; // 2. 与服务器断开连接
[_xmppStream disconnect];
} @end

封装好的XMPP工具(登录,注册,注销)

WCXMPPTool.h

#import <Foundation/Foundation.h>
#import "Singleton.h"
#import "XMPPFramework.h" typedef enum {
XMPPResultTypeLoginSuccess,//登录成功
XMPPResultTypeLoginFailure,//登录失败
XMPPResultTypeNetErr,//网络不给力
XMPPResultTypeRegisterSuccess,//注册成功
XMPPResultTypeRegisterFailure//注册失败
}XMPPResultType; typedef void (^XMPPResultBlock)(XMPPResultType type);// XMPP请求结果的block @interface WCXMPPTool : NSObject singleton_interface(WCXMPPTool); @property (nonatomic, strong)XMPPvCardTempModule *vCard;//电子名片 /**
* 注册标识 YES 注册 / NO 登录
*/
@property (nonatomic, assign,getter=isRegisterOperation) BOOL registerOperation;//注册操作 /**
* 用户注销 */
-(void)xmppUserlogout;
/**
* 用户登录
*/
-(void)xmppUserLogin:(XMPPResultBlock)resultBlock; /**
* 用户注册
*/
-(void)xmppUserRegister:(XMPPResultBlock)resultBlock;
@end

WCXMPPTool.m

#import "WCXMPPTool.h"

/*
* 在AppDelegate实现登录 1. 初始化XMPPStream
2. 连接到服务器[传一个JID]
3. 连接到服务成功后,再发送密码授权
4. 授权成功后,发送"在线" 消息
*/
@interface WCXMPPTool ()<XMPPStreamDelegate>{
XMPPStream *_xmppStream;
XMPPResultBlock _resultBlock; XMPPvCardCoreDataStorage *_vCardStorage;//电子名片的数据存储 XMPPvCardAvatarModule *_avatar;//头像模块
} // 1. 初始化XMPPStream
-(void)setupXMPPStream; // 2.连接到服务器
-(void)connectToHost; // 3.连接到服务成功后,再发送密码授权
-(void)sendPwdToHost; // 4.授权成功后,发送"在线" 消息
-(void)sendOnlineToHost;
@end @implementation WCXMPPTool singleton_implementation(WCXMPPTool) #pragma mark -私有方法
#pragma mark 初始化XMPPStream
-(void)setupXMPPStream{ _xmppStream = [[XMPPStream alloc] init]; #warning 每一个模块添加后都要激活
//添加电子名片模块
_vCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
_vCard = [[XMPPvCardTempModule alloc] initWithvCardStorage:_vCardStorage]; //激活
[_vCard activate:_xmppStream]; //添加头像模块
_avatar = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_vCard];
[_avatar activate:_xmppStream]; // 设置代理
[_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, )];
} #pragma mark 连接到服务器
-(void)connectToHost{
WCLog(@"开始连接到服务器");
if (!_xmppStream) {
[self setupXMPPStream];
} // 设置登录用户JID
//resource 标识用户登录的客户端 iphone android // 从单例获取用户名
NSString *user = nil;
if (self.isRegisterOperation) {
user = [WCUserInfo sharedWCUserInfo].registerUser;
}else{
user = [WCUserInfo sharedWCUserInfo].user;
} XMPPJID *myJID = [XMPPJID jidWithUser:user domain:@"teacher.local" resource:@"iphone" ];
_xmppStream.myJID = myJID; // 设置服务器域名
_xmppStream.hostName = @"127.0.0.1";//不仅可以是域名,还可是IP地址 // 设置端口 如果服务器端口是5222,可以省略
_xmppStream.hostPort = ; // 连接
NSError *err = nil;
if(![_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&err]){
WCLog(@"%@",err);
} } #pragma mark 连接到服务成功后,再发送密码授权
-(void)sendPwdToHost{
WCLog(@"再发送密码授权");
NSError *err = nil; // 从单例里获取密码
NSString *pwd = [WCUserInfo sharedWCUserInfo].pwd; [_xmppStream authenticateWithPassword:pwd error:&err]; if (err) {
WCLog(@"%@",err);
}
} #pragma mark 授权成功后,发送"在线" 消息
-(void)sendOnlineToHost{ WCLog(@"发送 在线 消息");
XMPPPresence *presence = [XMPPPresence presence];
WCLog(@"%@",presence); [_xmppStream sendElement:presence]; }
#pragma mark -XMPPStream的代理
#pragma mark 与主机连接成功
-(void)xmppStreamDidConnect:(XMPPStream *)sender{
WCLog(@"与主机连接成功"); if (self.isRegisterOperation) {//注册操作,发送注册的密码
NSString *pwd = [WCUserInfo sharedWCUserInfo].registerPwd;
[_xmppStream registerWithPassword:pwd error:nil];
}else{//登录操作
// 主机连接成功后,发送密码进行授权
[self sendPwdToHost];
} }
#pragma mark 与主机断开连接
-(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error{
// 如果有错误,代表连接失败 // 如果没有错误,表示正常的断开连接(人为断开连接) if(error && _resultBlock){
_resultBlock(XMPPResultTypeNetErr);
}
WCLog(@"与主机断开连接 %@",error); } #pragma mark 授权成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
WCLog(@"授权成功"); [self sendOnlineToHost]; // 回调控制器登录成功
if(_resultBlock){
_resultBlock(XMPPResultTypeLoginSuccess);
} } #pragma mark 授权失败
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
WCLog(@"授权失败 %@",error); // 判断block有无值,再回调给登录控制器
if (_resultBlock) {
_resultBlock(XMPPResultTypeLoginFailure);
}
} #pragma mark 注册成功
-(void)xmppStreamDidRegister:(XMPPStream *)sender{
WCLog(@"注册成功");
if(_resultBlock){
_resultBlock(XMPPResultTypeRegisterSuccess);
} } #pragma mark 注册失败
-(void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error{ WCLog(@"注册失败 %@",error);
if(_resultBlock){
_resultBlock(XMPPResultTypeRegisterFailure);
} } #pragma mark -公共方法
-(void)xmppUserlogout{
// 1." 发送 "离线" 消息"
XMPPPresence *offline = [XMPPPresence presenceWithType:@"unavailable"];
[_xmppStream sendElement:offline]; // 2. 与服务器断开连接
[_xmppStream disconnect]; // 3. 回到登录界面
// UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Login" bundle:nil];
//
// self.window.rootViewController = storyboard.instantiateInitialViewController;
[UIStoryboard showInitialVCWithName:@"Login"]; //4.更新用户的登录状态
[WCUserInfo sharedWCUserInfo].loginStatus = NO;
[[WCUserInfo sharedWCUserInfo] saveUserInfoToSanbox]; } -(void)xmppUserLogin:(XMPPResultBlock)resultBlock{ // 先把block存起来
_resultBlock = resultBlock; // Domain=XMPPStreamErrorDomain Code=1 "Attempting to connect while already connected or connecting." UserInfo=0x7fd86bf06700 {NSLocalizedDescription=Attempting to connect while already connected or connecting.}
// 如果以前连接过服务,要断开
[_xmppStream disconnect]; // 连接主机 成功后发送登录密码
[self connectToHost];
} -(void)xmppUserRegister:(XMPPResultBlock)resultBlock{
// 先把block存起来
_resultBlock = resultBlock; // 如果以前连接过服务,要断开
[_xmppStream disconnect]; // 连接主机 成功后发送注册密码
[self connectToHost];
} @end

自动登录

AppDelegate.m

#import "AppDelegate.h"
#import "XMPPFramework.h"
#import "WCNavigationController.h"
#import "DDLog.h"
#import "DDTTYLogger.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //从沙盒的路径
NSString *path=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; //打开XMPP的日志
[DDLog addLogger:[DDTTYLogger sharedInstance]]; //设置导航栏背景
// [WCNavigationController setupNavTheme]; //从沙盒里加载用户的数据单例
[[WCUserInfo sharedWCUserInfo] loadUserInfoFromSanbox]; //判断用户的登录状态,YES直接来到主界面
if([WCUserInfo sharedWCUserInfo].loginStatus){
UIStoryboard *storayobard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
self.window.rootViewController=storayobard.instantiateInitialViewController; //自动登录服务
[[WCXMPPTool sharedWCXMPPTool]xmppUserLogin:nil];
} return YES;
}
@end

登录方法

#import "WCBaseLoginViewController.h"
#import "AppDelegate.h" @implementation WCBaseLoginViewController - (void)login{
// 登录 /*
* 官方的登录实现 * 1.把用户名和密码放在WCUserInfo的单例 * 2.调用 AppDelegate的一个login 连接服务并登录
*/ //隐藏键盘
[self.view endEditing:YES]; // 登录之前给个提示 [MBProgressHUD showMessage:@"正在登录中..." toView:self.view]; [WCXMPPTool sharedWCXMPPTool].registerOperation = NO;
__weak typeof(self) selfVc = self; [[WCXMPPTool sharedWCXMPPTool] xmppUserLogin:^(XMPPResultType type) {
[selfVc handleResultType:type];
}];
} -(void)handleResultType:(XMPPResultType)type{
// 主线程刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view
];
switch (type) {
case XMPPResultTypeLoginSuccess:
NSLog(@"登录成功");
[self enterMainPage];
break;
case XMPPResultTypeLoginFailure:
NSLog(@"登录失败");
[MBProgressHUD showError:@"用户名或者密码不正确" toView:self.view];
break;
case XMPPResultTypeNetErr:
[MBProgressHUD showError:@"网络不给力" toView:self.view];
default:
break;
}
}); } -(void)enterMainPage{ // 更改用户的登录状态为YES
[WCUserInfo sharedWCUserInfo].loginStatus = YES; // 把用户登录成功的数据,保存到沙盒
[[WCUserInfo sharedWCUserInfo] saveUserInfoToSanbox]; // 隐藏模态窗口
[self dismissViewControllerAnimated:NO completion:nil]; // 登录成功来到主界面
// 此方法是在子线程补调用,所以在主线程刷新UI
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
self.view.window.rootViewController = storyboard.instantiateInitialViewController;
}