XMPP客户端登录开发详解

jopen 3年前

由上篇文章将了如何在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客户端登录开发详解

然后点击 左侧 导航栏中的新建用户 填写好用户信息就可以了。

XMPP客户端登录开发详解

到这边基本上用户注册环节 已经结束了。

开发 登录功能,基本上包括 登录界面的开发、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/