前言
這也是本人第一次琢磨關于即時通訊方面的內容,結合網上查看的相關資料搭建出來的仿微信小demo,如有意見請多多指教
寫了這么多,尼瑪終于到正題了,前面9篇講的都是基本概念及相關環(huán)境的搭建,這里列舉一下:
- Sokcet套接字的簡介
- 網絡七層協(xié)議,TCP/UDP的概念
- CocoaSocket的使用
- XMPP協(xié)議的簡介
- XMPP通訊環(huán)境SQL的搭建
- XMPP通訊環(huán)境服務器openfire的搭建
- XMPP通訊環(huán)境客戶端message,Aduim,Spark的搭建
- XMPPFramework框架的導入及簡單介紹
具體項目可以在githubWeiChat下載進行查看,如若各位看官老爺覺得還可以請點star
下面開始進入正題
XMPPFramework的使用
看圖
-
用戶注冊
注冊.gif -
登陸
登陸 -
切換用戶登陸
切換用戶登陸.gif -
注銷
注銷
今天講的是XMPP的登陸注冊部分,廢話不多說:
1.登陸注冊部分常用的對象
- XMPPStream XMPP通道:負責XMPP信息的傳輸以及傳輸狀態(tài)等
- XMPPReconnect 自動連接
2.準備工作
1.創(chuàng)建一個單例類名為XMPPManager,負責XMPP相關管理工作,比如各類登陸注冊模塊的激活,實現(xiàn)都在這里進行處理.
2.創(chuàng)建一個單例類名為UserManager,負責用戶的賬號密碼的管理以及獲取用戶信息等方面.
3.登錄注冊實現(xiàn)部分
3.1實現(xiàn)原理
這里闡述下實現(xiàn)原理,具體實現(xiàn)過程請參考下部分代碼以及項目內容.
1.導入XMPPStream,XMPPReonnect頭文件
2.激活XMPPStream,XMPPReconnect模塊并設置代理
3.登錄的流程:
xmpp的登錄流程是权旷,
3.1 傳遞 JID , Host , Port 先連接上服務器
3.2連接成功了 再 發(fā)送密碼到服務器 倒源,
3.3授權成功 或者 授權失敗.這就代表登陸成功或失敗,成功了則跳到微信主界面
4.注冊的流程:
4.1xmpp的注冊流程是, 傳遞 JID , Host , Port 先連接上服務器 :
通過JID連接成功
連接成功則會自動調用XMPPStreamDelegatexmppStreamDidConnect 代理方法
然后在通過代理方法調用 XMPPStream的發(fā)送密碼的方法authenticateWithPassword
4.2連接成功了 再 發(fā)送注冊密碼到服務器
4.3注冊成功 或者 失敗,注冊成功了跳到登陸界面,進行登陸
共同點:
不管你jid存不存在 都能連接到服務器嗡善。
不同點:
發(fā)送的是授權密碼 還是 發(fā)送注冊密碼 就是決定你是登錄還是注冊.
5.在登陸注冊頁面進行調用方法并傳遞狀態(tài)
注意:
1.連接到服務器后,對于是登陸還是注冊的判斷
2.登陸成功后需要發(fā)送一個在線狀態(tài)消息,離線了需要發(fā)送離線狀態(tài)消息
3.在UserManager中登陸用戶信息和注冊用戶信息分清楚
4.XMPPStream代理方法執(zhí)行的順序先后
5.block對于登陸注冊狀態(tài)的提示
6.對于XMPP JID的理解,用戶名@服務器地址.設備信息(可選)
詳細請看demo
7.這個demo里登錄名就是密碼,不影響使用,請注意
3.2XMPPManager部分
3.2.1單例類
#pragma mark 創(chuàng)建XMPPManager單例類
singleton_m(manager)
3.2.2創(chuàng)建XMPPStream對象
// 登錄注冊什么的都是和服務器交互,所以我們用到的類就是XMPPStream
- (void)connect {
if (!self.stream) {
// 創(chuàng)建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的發(fā)送密碼的方法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 : yoyu@127.0.0.1.iPhone
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 : yoyu@127.0.0.1.iPhone
self.stream.myJID = [XMPPJID jidWithUser:user.registName domain:kHostName resource:@"iPhone"];
// 通過讀取UserDefault中的name連接服務器
[self connectToServer];
}
3.2.5用戶注銷
- (void)xmppUserLogout {
// 發(fā)送離線狀態(tài)
[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連接服務器狀態(tài)
#pragma mark -- XMPPStreamDelegate
/**
* 登錄的流程:
xmpp的登錄流程是渡蜻, 傳遞 JID , Host , Port 先連接上服務器 术吝,連接成功了 再 發(fā)送密碼到服務器 ,授權成功 或者 授權失敗
注冊的流程:
xmpp的注冊流程是茸苇, 傳遞 JID , Host , Port 先連接上服務器 排苍,連接成功了 再 發(fā)送注冊密碼到服務器 ,注冊成功 或者 失敗
共同點:
不管你jid存不存在 都能連接到服務器学密。
不同點:
發(fā)送的是授權密碼 還是 發(fā)送注冊密碼 就是決定你是登錄還是注冊
*/
/**
通過JID連接成功
* 連接成功則會自動調用XMPPStreamDelegatexmppStreamDidConnect 代理方法
然后在通過代理方法調用 XMPPStream的發(fā)送密碼的方法authenticateWithPassword
*/
#pragma mark -- 連接成功
- (void)xmppStreamDidConnect:(XMPPStream *)sender {
NSLog(@"通過JID建立連接成功");
/**
* 發(fā)送密碼進行授權登陸
分登陸密碼
和注冊密碼
需要判斷
*/
UserManager *user = [UserManager sharedmanager];
//[user readUserInfo];
NSError *error = nil;
NSLog(@"%@",user.loginName);
NSLog(@"---%@",user.registName);
if (user.loginName) {
// 發(fā)送登陸密碼
[self.stream authenticateWithPassword:user.loginPsw error:&error];
} else {
// 發(fā)送注冊密碼
[self.stream registerWithPassword:user.registPsw error:&error];
}
}
#pragma mark -- 連接失敗,與服務器斷開連接(例如網絡原因)
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error {
NSLog(@"通過JID建立連接失敗,與服務器斷開連接");
if (self.block) {
self.block(XMPPUserStateTypeOther);
}
// 發(fā)送通知:狀態(tài)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];
// 同時要發(fā)送一個在線的信息
[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登陸狀態(tài)發(fā)送
#pragma mark ******************************
#pragma mark - 登陸成功后,給服務器發(fā)送一個在線消息:上線了
/**
presence表示用戶狀態(tài)
presence 的狀態(tài):
available 上線
away 離開
do not disturb 忙碌
unavailable 下線
*/
- (void)sendOnlineMessage {
/**
* 關于用戶的上線和下線淘衙,需要用到一個類XMPPPresence 類。這個類是XMPPElement的子類腻暮,主要用來管理某些信息的展現(xiàn)彤守。首先要實例化一個對象,這其中會用到一個presenceWithType 方法哭靖,有兩個選擇@"unavailable"代表下線具垫,@"available"代表上線,一般情況上線的時候后面就可以直接省略试幽。
*/
XMPPPresence *pre = [XMPPPresence presenceWithType:@"available"];
// XMPPPresence *pre = [XMPPPresence presence];
[self.stream sendElement:pre];
}
#pragma mark - 離線時,給服務器發(fā)送一個在線消息:下線了
- (void)sendOfflineMessage {
XMPPPresence *pre = [XMPPPresence presenceWithType:@"unavailable"];
[self.stream sendElement:pre];
}
3.3登陸注冊頁面
這個部分就不詳細介紹了,可以進demo查閱
未完待續(xù)...