XMPP客户端登录开发详解
由上篇文章将了如何在MAC本地搭建一个Openfire服务器,今天我们就要着手使用 XMPPFramework来开发 基于XMPP 协议的即时通讯IOS 客户端系统。今天主要看登录功能开发,可能有人会质疑,我们都没有开发注册功能,怎么开发登录功能。注册账号我们有捷径,服务器都在本地,当然很好做了。另外就是通过MAC 自带的客户端 Messages 进行注册。
首先,我们需要搭建起来IOS 的工程,并且将XMPPFramework 引入到我们的工程中来,当然我们可以使用源码 直接导入,也可以使用cocoapods来进行依赖。本文直接使用源码来进行开发。由于在Github上的源码有一些问题,所以大家可以来 https://github.com/TerryLMay/TMXMPPClient/tree/master/TMXMPPClient/ThirdTools/XMPPFrameworkio 下载相关的XMPPFramework相关的代码。
下载关于XMPPFramework的代码之后,我们需要做的是 创建一个工程,然后将源代码导入到我们的工程中去。当然直接导入并且编译会出现libxml找不到的问题。我们需要在工程中导入libxml2.tbd(ios 9之后的名称) 以及 libresolv.9.tbd(ios 9之后的后缀)。然后在Build Setting的Head search 中加上 头文件的链接地址
${SDKROOT}/usr/include/libxml2
这之后,重新编译工程即可编译成功。后面,我们需要做的就是开发登录功能了,在开始之前,我们还是先看一下怎么注册一个账号吧;登录Openfire后台,创建一个用户。
通过在浏览器中输入 (前提 是 openfire服务器以及mysql服务器都已经启动了)
127.0.0.1:9090
进入如下界面
点击左上角用户/组 进入用户管理界面
然后点击 左侧 导航栏中的新建用户 填写好用户信息就可以了。
到这边基本上用户注册环节 已经结束了。
开发 登录功能,基本上包括 登录界面的开发、XMPP登录逻辑的开发。登录界面我们可以 随便搭建一个登录界面就可以了。我今天主要是说一下 XMPP登录部分。
首先,创建关于XMPPLoginManager类,实现XMPPStreamDelegate,我定义了自己的一个宏,表示使用的Openfire服务器的地址 以及 端口号
#define LocalOpenfire 1 #if LocalOpenfire #define HOST_NAME @"127.0.0.1" #define HOST_PORT 5222 #define CONNECT_IDENTIFIER @"@" #endif #define TIME_OUT 20
然后 定义XMPPStream、XMPPReconnect实例,并且初始化
- (void)initXMPPStream { self.loginXmppStream = [[XMPPStream alloc] init]; [self.loginXmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; } - (void)initXMPPReconnect { self.loginReconnectManager = [[XMPPReconnect alloc] init]; [self.loginReconnectManager activate:self.loginXmppStream]; // You can also optionally add delegates to the module. [self.loginReconnectManager addDelegate:self delegateQueue:dispatch_get_main_queue()]; }
定义 Login按钮点击之后的点击事件调用 XMPPLoginManager中的如下方法进行连接:
#pragma mark -- connect xmpp method for login viewController - (void)connectXMPPServer:(NSString *)userName password:(NSString *)password { self.userName = userName; self.password = password; NSString *myJid = [NSString stringWithFormat:@"%@%@%@", userName, CONNECT_IDENTIFIER, HOST_NAME]; self.loginXmppStream.myJID = [XMPPJID jidWithString:myJid]; self.loginXmppStream.hostName = HOST_NAME; self.loginXmppStream.hostPort = HOST_PORT; NSError *connectError = nil; [self.loginXmppStream connectWithTimeout:TIME_OUT error:&connectError]; if (connectError) { NSLog(@"%@", connectError); [self.loginDelegate loginXMPPConnectError:connectError]; } }
后面就是处理XMPPStream的各种回调就可以了
#pragma mark -- xmppstream delegate //连接xmpp成功之后,使用密码认证 - (void)xmppStreamDidConnect:(XMPPStream *)sender { NSError *authError = nil; [self.loginXmppStream authenticateWithPassword:self.password error:&authError]; if (authError) { NSLog(@"%@", authError); [self.loginDelegate loginXMPPDidNotAuthenticate]; } } //认证通过之后的处理 - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender { NSLog(@"%@", @"认证通过"); [self.loginDelegate loginXMPPDidAuthenticate]; } //连接服务器的超时处理 - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender { NSLog(@"连接超时"); [self.loginDelegate loginXMPPConnectDidTimeout]; } //认证没有通过处理 - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error { NSLog(@"认证失败"); [self.loginDelegate loginXMPPDidNotAuthenticate]; }
基本上这样就可以登录了,登录成功之后,可以跳转到相应的界面。提一下我们 能看到的XMPP交互流程 包括:
1、XMPP 使用用户名去连接服务器;
2、XMPP 连接成功之后,通过密码去服务器认证
3、认证成功之后,处理自己想处理的一下事情。
但其实XMPP 报文交互包括好几步,我就从别人那边摘录一点交互细节过来,就不自己一个个的抓包看了。
C1: 客户端初始化流给服务器 <stream:stream to="127.0.0.1" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0"> S1: 服务器向客户端发送流标签作为应答: <?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="192.168.1.185" id="fb0cfcad" xml:lang="en" version="1.0"> S2: 发送 STARTTLS范围 <stream:features> <starttls xmlns="urn:ietf:params:xml:ns: xmpp-tls"></starttls> <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"> <mechanism>PLAIN</mechanism> <mechanism>CRAM-MD5</mechanism> <mechanism>ANONYMOUS</mechanism> <mechanism>DIGEST-MD5</mechanism> <mechanism>JIVE-SHAREDSECRET</mechanism> </mechanisms> <compression xmlns="http://jabber.org/features/compress"> <method>zlib</method> </compression> <auth xmlns="http://jabber.org/features/iq-auth"/> <register xmlns="http://jabber.org/features/iq-register"/> </stream:features> C2:客户端发送 STARTTLS 命令给服务器: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> S3:服务器通知客户端可以继续进行: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> C3:TLS 握手成功, 客户端初始化一个新的流给服务器 <stream:stream to="192.168.1.185" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0"> S4:服务器通知客户端可用的验证机制: <?xml version='1.0' encoding='UTF-8'?> <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="192.168.1.185" id="ad6f53e8" xml:lang="en" version="1.0"> <stream:features> <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"> <mechanism>DIGEST-MD5</mechanism> <mechanism>PLAIN</mechanism> <mechanism>ANONYMOUS</mechanism> <mechanism>CRAM-MD5</mechanism> </mechanisms> <compression xmlns="http://jabber.org/features/compress"> <method>zlib</method> </compression> <auth xmlns="http://jabber.org/features/iq-auth"/> <register xmlns="http://jabber.org/features/iq-register"/> </stream:features> C4: 客户端选择一个验证机制: <auth mechanism="DIGEST-MD5" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"></auth> S5:服务器发送一个 [BASE64] 编码的挑战给客户端: <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cmVhbG09IjE5Mi4xNjguMS4xODUiLG5vbmNlPSJlcEJaZlBxU1p0WGlLYzBqdGpwT0I1a01HMHdiY0hsUmNhOE52ZE9SIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz</challenge> C5:客户端发送一个[BASE64]编码的回应这个挑战: <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iYWRtaW4iLHJlYWxtPSIxOTIuMTY4LjEuMTg1Iixub25jZT0iZXBCWmZQcVNadFhpS2MwanRqcE9CNWtNRzB3YmNIbFJjYThOdmRPUiIsbmM9MDAwMDAwMDEsY25vbmNlPSJMNDJ1SE1XK2piemh6N1hzdWRndHN1V1VIT2hNZmFLVUJpcU5iR1p2IixkaWdlc3QtdXJpPSJ4bXBwLzE5Mi4xNjguMS4xODUiLG1heGJ1Zj02NTUzNixyZXNwb25zZT1hN2JhMWZlOThiMDc2ZjUzZWUzNTczM2Q5NDMwODJlYSxxb3A9YXV0aCxhdXRoemlkPSJhZG1pbiI=</response> S6:服务器通知客户端验证成功 <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cnNwYXV0aD0yNDZlZDcyOTQ3ZjVhYzFiNWQ2ZDc4ZTkxM2QzMmFjMQ==</success> C6客户端初始化一个新流给服务器: <stream:stream to="192.168.1.185" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0">
基本上XMPP的登录细节就已经清楚了。后面我们看一下 注册相关的模块 以及 联系人请求模块的开发。如果想获取源码的话,请转到 https://github.com/TerryLMay/TMXMPPClient/tree/master/TMXMPPClient
本文作者:Terry 专注于技术开发;打滚于IOS 技术领域,偶尔也会迈出脚步探索其他领域 地址:http://www.terrylmay.com/terrylmay.github.io/2016/01/31/XMPP%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%99%BB%E5%BD%95%E5%BC%80%E5%8F%91%E8%AF%A6%E8%A7%A3/
来自: http://www.superqq.com/blog/2016/01/31/xmpp-client-login-dev/