前言
这也是本人第一次琢磨关于即时通讯方面的内容,结合网上查看的相关资料搭建出来的仿微信小demo,如有意见请多多指教
写了这么多,尼玛终于到正题了,前面9篇讲的都是基本概念及相关环境的搭建,这里列举一下:
- Sokcet套接字的简介
- 网络七层协议,TCP/UDP的概念
- CocoaSocket的使用
- XMPP协议的简介
- XMPP通讯环境SQL的搭建
- XMPP通讯环境服务器openfire的搭建
- XMPP通讯环境客户端message,Aduim,Spark的搭建
- XMPPFramework框架的导入及简单介绍
具体项目可以在githubWeiChat下载进行查看,如若各位看官老爷觉得还可以请点star
下面开始进入正题
XMPPFramework的使用
看图
-
用户注册
-
登陆
-
切换用户登陆
-
注销
今天讲的是XMPP的登陆注册部分,废话不多说:
1.登陆注册部分常用的对象
- XMPPStream XMPP通道:负责XMPP信息的传输以及传输状态等
- XMPPReconnect 自动连接
2.准备工作
1.创建一个单例类名为XMPPManager,负责XMPP相关管理工作,比如各类登陆注册模块的激活,实现都在这里进行处理.
2.创建一个单例类名为UserManager,负责用户的账号密码的管理以及获取用户信息等方面.
3.登录注册实现部分
3.1实现原理
这里阐述下实现原理,具体实现过程请参考下部分代码以及项目内容.
1.导入XMPPStream,XMPPReonnect头文件
2.激活XMPPStream,XMPPReconnect模块并设置代理
3.登录的流程:
xmpp的登录流程是,
3.1 传递 JID , Host , Port 先连接上服务器
3.2连接成功了 再 发送密码到服务器 ,
3.3授权成功 或者 授权失败.这就代表登陆成功或失败,成功了则跳到微信主界面
4.注册的流程:
4.1xmpp的注册流程是, 传递 JID , Host , Port 先连接上服务器 :
通过JID连接成功
连接成功则会自动调用XMPPStreamDelegatexmppStreamDidConnect 代理方法
然后在通过代理方法调用 XMPPStream的发送密码的方法authenticateWithPassword
4.2连接成功了 再 发送注册密码到服务器
4.3注册成功 或者 失败,注册成功了跳到登陆界面,进行登陆
共同点:
不管你jid存不存在 都能连接到服务器。
不同点:
发送的是授权密码 还是 发送注册密码 就是决定你是登录还是注册.
5.在登陆注册页面进行调用方法并传递状态
注意:
1.连接到服务器后,对于是登陆还是注册的判断
2.登陆成功后需要发送一个在线状态消息,离线了需要发送离线状态消息
3.在UserManager中登陆用户信息和注册用户信息分清楚
4.XMPPStream代理方法执行的顺序先后
5.block对于登陆注册状态的提示
6.对于XMPP JID的理解,用户名@服务器地址.设备信息(可选)
详细请看demo
7.这个demo里登录名就是密码,不影响使用,请注意
3.2XMPPManager部分
3.2.1单例类
#pragma mark 创建XMPPManager单例类
singleton_m(manager)
3.2.2创建XMPPStream对象
// 登录注册什么的都是和服务器交互,所以我们用到的类就是XMPPStream
- (void)connect {
if (!self.stream) {
// 创建XMPPStream,只需要初始化一次,所以加判断
self.stream = [[XMPPStream alloc] init];
// 设置stream的域名和端口号
self.stream.hostName = kHostName;
self.stream.hostPort = kHostPort;
// 添加代理 连接成功后调用传密码的方法
[self.stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
// 连接服务器
- (void)connectToServer {
// 判断是否连接成功过
if (![self.stream isConnected]) {
// 连接到服务器
NSError *error;
[self.stream connectWithTimeout:XMPPStreamTimeoutNone error:&error];
if (error) {
NSLog(@"%@",error);
} else {
// 连接成功则会自动调用XMPPStreamDelegatexmppStreamDidConnect 代理方法
// 然后在通过代理方法调用 XMPPStream的发送密码的方法authenticateWithPassword
NSLog(@"连接成功");
}
}
}
3.2.3 用户登陆,使用登陆JID用户名
- (void)xmppUserLogin:(UserSatateBlock)block {
// block赋值给全局变量,在代理方法中调用block传递登陆信息
self.block = block;
// 不管登陆几次,每次登陆之前都要先把连接断开
[self.stream disconnect];
// 初始化XMPPPStream
[self connect];
/**
* 因为在调用之前,在userDefault中存储的是登陆用户的名字
所以在这里获取用户的名字
*/
UserManager *user = [UserManager sharedmanager];
[user readLoginInfo];
// 设置XMPPStream的JID : [email protected]
self.stream.myJID = [XMPPJID jidWithUser:user.loginName domain:kHostName resource:@"iPhone"];
// 通过读取UserDefault中的name连接服务器
[self connectToServer];
}
3.2.4用户注册,使用注册JID用户名
- (void)xmppUserRegist:(UserSatateBlock)block {
self.block = block;
// 不管登陆几次,每次登陆之前都要先把连接断开
[self.stream disconnect];
// 初始化XMPPPStream
[self connect];
/**
* 因为在调用之前,在userDefault中存储的是注册用户的名字
所以在这里获取用户的名字
*/
UserManager *user = [UserManager sharedmanager];
[user readRegistInfo];
// 设置XMPPStream的JID : [email protected]
self.stream.myJID = [XMPPJID jidWithUser:user.registName domain:kHostName resource:@"iPhone"];
// 通过读取UserDefault中的name连接服务器
[self connectToServer];
}
3.2.5用户注销
- (void)xmppUserLogout {
// 发送离线状态
[self sendOfflineMessage];
// 断开连接
[self.stream disconnect];
// 跳转到登陆界面
UIWindow *window = [[UIApplication sharedApplication].delegate window];
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"LoginAndRegist" bundle:nil];
window.rootViewController = [storyBoard instantiateInitialViewController];
}
3.2.6XMPPStreamDelegate连接服务器状态
#pragma mark -- XMPPStreamDelegate
/**
* 登录的流程:
xmpp的登录流程是, 传递 JID , Host , Port 先连接上服务器 ,连接成功了 再 发送密码到服务器 ,授权成功 或者 授权失败
注册的流程:
xmpp的注册流程是, 传递 JID , Host , Port 先连接上服务器 ,连接成功了 再 发送注册密码到服务器 ,注册成功 或者 失败
共同点:
不管你jid存不存在 都能连接到服务器。
不同点:
发送的是授权密码 还是 发送注册密码 就是决定你是登录还是注册
*/
/**
通过JID连接成功
* 连接成功则会自动调用XMPPStreamDelegatexmppStreamDidConnect 代理方法
然后在通过代理方法调用 XMPPStream的发送密码的方法authenticateWithPassword
*/
#pragma mark -- 连接成功
- (void)xmppStreamDidConnect:(XMPPStream *)sender {
NSLog(@"通过JID建立连接成功");
/**
* 发送密码进行授权登陆
分登陆密码
和注册密码
需要判断
*/
UserManager *user = [UserManager sharedmanager];
//[user readUserInfo];
NSError *error = nil;
NSLog(@"%@",user.loginName);
NSLog(@"---%@",user.registName);
if (user.loginName) {
// 发送登陆密码
[self.stream authenticateWithPassword:user.loginPsw error:&error];
} else {
// 发送注册密码
[self.stream registerWithPassword:user.registPsw error:&error];
}
}
#pragma mark -- 连接失败,与服务器断开连接(例如网络原因)
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error {
NSLog(@"通过JID建立连接失败,与服务器断开连接");
if (self.block) {
self.block(XMPPUserStateTypeOther);
}
// 发送通知:状态2表示连接服务器失败
[[NSNotificationCenter defaultCenter] postNotificationName:kLoginStateNotification object:nil userInfo:@{@"state":@"3"}];
}
3.2.7XMPPStreamDelegate登陆
/**
* 属于登陆方面
*/
#pragma mark -- 授权登陆成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
NSLog(@"授权登陆成功");
if (self.block) {
self.block(XMPPUserStateTypeSuccess);
}
// 授权登陆成功后,跳转到主界面
UIWindow *window = [[UIApplication sharedApplication].delegate window];
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
window.rootViewController = [storyBoard instantiateInitialViewController];
// 同时要发送一个在线的信息
[self sendOnlineMessage];
}
#pragma mark -- 授权登陆失败
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
NSLog(@"授权登陆失败");
if (self.block) {
self.block(XMPPUserStateTypeFaild);
}
}
3.2.8XMPPStreamDelegate注册
/**
* 属于注册方面
*/
#pragma mark -- 注册成功
- (void)xmppStreamDidRegister:(XMPPStream *)sender{
NSLog(@"注册成功");
if (self.block) {
self.block(XMPPUserStateTypeSuccess);
}
}
#pragma mark -- 注册失败
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error{
NSLog(@"注册失败");
if (self.block) {
self.block(XMPPUserStateTypeFaild);
}
}
3.2.7登陆状态发送
#pragma mark ******************************
#pragma mark - 登陆成功后,给服务器发送一个在线消息:上线了
/**
presence表示用户状态
presence 的状态:
available 上线
away 离开
do not disturb 忙碌
unavailable 下线
*/
- (void)sendOnlineMessage {
/**
* 关于用户的上线和下线,需要用到一个类XMPPPresence 类。这个类是XMPPElement的子类,主要用来管理某些信息的展现。首先要实例化一个对象,这其中会用到一个presenceWithType 方法,有两个选择@"unavailable"代表下线,@"available"代表上线,一般情况上线的时候后面就可以直接省略。
*/
XMPPPresence *pre = [XMPPPresence presenceWithType:@"available"];
// XMPPPresence *pre = [XMPPPresence presence];
[self.stream sendElement:pre];
}
#pragma mark - 离线时,给服务器发送一个在线消息:下线了
- (void)sendOfflineMessage {
XMPPPresence *pre = [XMPPPresence presenceWithType:@"unavailable"];
[self.stream sendElement:pre];
}
3.3登陆注册页面
这个部分就不详细介绍了,可以进demo查阅
未完待续...