UI进阶 即时通讯之XMPP登录、注册
一、即时通讯
- 什么是即时通讯、
- 即时通讯(Instant Messaging)是目前Internet上最为流行的通讯方式,各种各样的即时通讯软件也层出不穷,服务提供商也提供了越来越丰富的通讯服务功能。
- 即时通讯的实现方式
- 即时通讯有多种实现方式,例如:XMPP、环信、融云等。
- 什么是XMPP
- XMPP(XML,Messages,Presence,Protocol)是基于可扩展标记语言(XML)的协议,可用于即时通信(IM)。
——可扩展消息处理现场协议
- XMPP(XML,Messages,Presence,Protocol)是基于可扩展标记语言(XML)的协议,可用于即时通信(IM)。
- XMPP优点
- 开放
XMPP协议是由JSF开源社区组织开发的,不属于任何的机构和个人,从根本上保证了其开放性。 - 2. 标准
互联网工程工作组将XMPP于2002年正式列为认可的实时通讯及Presence技术。 - 3.分布式的网络架构
XMPP 协议虽然是基于Client/Server 架构,但是XMPP协议本身并没有这样的限制。网络的架构和电子邮件十分相似,但没有结合任何特定的网络架构,适用范围非常广泛。 - XMPP 协议具有良好的扩展性
基于XML 建立起来的应用具有良好的语义完整性和扩展性。 - XMPP 具有很好的弹性
XMPP 除了可用在即时通信的应用程序,还能用在网络管理、内容供稿、协同工具、档案共享、游戏、远端系统监控等。 - 安全性
XMPP在Client-to-Server通信和Server-to-Server通信中都使用TLS (Transport Layer Security)协议作为通信通道的加密方法,保证通信的安全。
- 开放
二、XMPP实现即时通讯
- 原理
实现即时通讯至少需要一个服务器端、两个客户端。
- 下面我们准备需要的环境:
1、XMPP服务器 2、XMPP客户端(辅助调试)
1、XMPP环境搭建
http://www.cnblogs.com/fearlessyyp/p/5506644.html
第一次打开可能会有点儿慢,图片很多,步骤很详细,祝搭建成功。
2、工程中添加XMPP
1、创建新工程
2、导入XMPP框架
3、引入XMPP需要的依赖库 libxml libresolv
4、设置路径:在工程的"Build Settings"页中找到"Header Search Path"项,添加"/usr/include/libxml2"。在"Other Linker Flags"项,添加"-lxml2" XML解析适配
三、XMPP实现登录、注册
1、Main.storyboard搭建界面
2、初始化XMPP通道
XMPPFramework框架中有一个XMPPConfig.h文件,里面宏定义了连接服务器用到的参数,可对照着自己的服务器参数修改宏
1 // 2 // XMPPConfig.h 3 // XMPPSample 4 // 5 // Created by lewis on 14-3-27. 6 // Copyright (c) 2014年 com.lanou3g. All rights reserved. 7 // 8 9 #ifndef XMPPSample_XMPPConfig_h 10 #define XMPPSample_XMPPConfig_h 11 12 //openfire服务器IP地址 13 #define kHostName @"127.0.0.1" 14 //openfire服务器端口 默认5222 15 #define kHostPort 5222 16 //openfire域名 17 #define kDomin @"127.0.0.1" 18 //resource 19 #define kResource @"iOS" 20 #endif
初始化通道里用到的kHostName、kHostPort都是在XMPPConfig.h文件中定义的
1 //初始化通道 2 self.xmppStream = [[XMPPStream alloc] init]; 3 //openfire服务器IP地址 4 self.xmppStream.hostName = kHostName; 5 //openfire服务器端口 默认5222 6 self.xmppStream.hostPort = kHostPort; 7 //添加代理 8 [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue() 9 ];
3、主要实现
XMPPStream关键方法
登录用到的方法
注册用到的方法
封装了一个XMPPManager类
XMPPManager.h
1 #import <Foundation/Foundation.h> 2 #import "XMPPFramework.h" 3 4 @interface XMPPManager : NSObject 5 /// 声明一个通道属性 6 @property (nonatomic, strong)XMPPStream *xmppStream; 7 8 #pragma mark - 单例 9 + (instancetype)sharedXMPPManager; 10 11 #pragma mark - 登录 12 - (void)loginWithUserName:(NSString *)userName 13 password:(NSString *)password; 14 15 #pragma mark - 注册 16 - (void)registerWithUserName:(NSString *)userName 17 password:(NSString *)password; 18 @end
XMPPManager.m
1 #import "XMPPManager.h" 2 3 static XMPPManager *xmppManager = nil; 4 5 // 定义枚举值,用来区分当前的状态是登录还是注册 6 typedef NS_ENUM(NSUInteger, ConnectToServerPurpose) { 7 ConnectToServerPurposeLogin, // 登录 8 ConnectToServerPurposeRegister, // 注册 9 }; 10 11 @interface XMPPManager ()<XMPPStreamDelegate> 12 /// 用户名 13 @property (nonatomic, copy) NSString *userName; 14 /// 密码 15 @property (nonatomic, copy) NSString *password; 16 17 /// 记录当前的状态是登录还是注册 18 @property (nonatomic) ConnectToServerPurpose connectToServer; 19 @end 20 21 @implementation XMPPManager 22 #pragma mark - 单例 23 + (instancetype)sharedXMPPManager { 24 static dispatch_once_t oneToken; 25 dispatch_once(&oneToken, ^{ 26 xmppManager = [[XMPPManager alloc] init]; 27 }); 28 return xmppManager; 29 } 30 31 #pragma mark - 创建通道 32 - (instancetype)init { 33 if (self = [super init]) { 34 // 初始化通道对象 35 self.xmppStream = [[XMPPStream alloc] init]; 36 // 设置Openfire服务器主机名 37 self.xmppStream.hostName = kHostName; 38 // 设置服务器端口号 39 self.xmppStream.hostPort = kHostPort; 40 // 设置代理 41 [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; 42 } 43 return self; 44 } 45 46 #pragma mark - 登录 47 - (void)loginWithUserName:(NSString *)userName 48 password:(NSString *)password { 49 self.userName = userName; 50 self.password = password; 51 // 设置当前的状态为登录 52 self.connectToServer = ConnectToServerPurposeLogin; 53 // 连接服务器 54 [self linkServer]; 55 56 } 57 58 #pragma mark - 注册 59 - (void)registerWithUserName:(NSString *)userName 60 password:(NSString *)password { 61 self.userName = userName; 62 self.password = password; 63 // 设置当前的状态为注册 64 self.connectToServer = ConnectToServerPurposeRegister; 65 // 连接服务器 66 [self linkServer]; 67 } 68 69 #pragma mark - 连接服务器 70 - (void)linkServer { 71 // 要连接服务器,要有用户身份认证 72 // 身份认证 73 // 参数1:用户名 74 // 参数2:domain是域名 75 // 参数3:资源 76 XMPPJID *jid = [XMPPJID jidWithUser:self.userName domain:kDomin resource:kResource]; 77 78 // 通过通道进行身份验证 79 self.xmppStream.myJID = jid; 80 81 // (根据项目需求来定)如果当前聊天工具处于连接状态,或者已经连接了,此时你需要去切断连接 82 if ([self.xmppStream isConnected] || [self.xmppStream isConnecting]) { 83 // 调用自定义方法 84 [self disconnectionToServer]; 85 } 86 87 // 连接超时 88 NSError *error = nil; 89 [self.xmppStream connectWithTimeout:30 error:&error]; 90 if (error) { 91 NSLog(@"服务器连接超时"); 92 } 93 } 94 95 #pragma mark - 手动断开连接(注销) 96 - (void)disconnectionToServer { 97 // 设置当前用户状态为下线 98 XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"]; 99 // 告诉通道下线 100 [self.xmppStream sendElement:presence]; 101 // 通道失去连接 102 [self.xmppStream disconnect]; 103 NSLog(@"(自定义方法)断开连接"); 104 } 105 106 107 #pragma mark -----------------以下XMPPStreamDelegate是协议中的方法---------------- 108 109 #pragma mark - 连接成功 110 - (void)xmppStreamDidConnect:(XMPPStream *)sender { 111 NSLog(@"服务器连接成功"); 112 // 校验密码 113 switch (self.connectToServer) { 114 case ConnectToServerPurposeLogin: 115 // 校验登录密码 116 [self.xmppStream authenticateWithPassword:self.password error:nil]; 117 break; 118 case ConnectToServerPurposeRegister: 119 // 注册 120 [self.xmppStream registerWithPassword:self.password error:nil]; 121 break; 122 default: 123 break; 124 } 125 126 } 127 128 #pragma mark - 连接超时 129 - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender { 130 NSLog(@"服务器连接超时"); 131 } 132 133 #pragma mark - 已经断开连接 134 - (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error { 135 // 连接被断开的情况 136 // 1、自己手动断开 137 // 2、被动断开 138 NSLog(@"已经断开连接"); 139 } 140 141 #pragma mark - 用户认证失败 142 - (void) xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error { 143 NSLog(@"登录失败 %@", error); 144 } 145 146 #pragma mark - 认证成功 147 - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender { 148 // 设置用户状态为上线 149 XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"]; 150 // 告诉通道上线 151 [self.xmppStream sendElement:presence]; 152 NSLog(@"用户已上线"); 153 154 } 155 #pragma mark -----------------以上是XMPPStreamDelegate协议中的方法---------------- 156 // 关于注册是否成功的代理方法写在了RegisterViewController.m中 157 158 159 @end
LoginViewController.m
1 #import "LoginViewController.h" 2 #import "XMPPManager.h" 3 4 @interface LoginViewController () 5 /// 用户名 6 @property (weak, nonatomic) IBOutlet UITextField *userNameTextField; 7 /// 密码 8 @property (weak, nonatomic) IBOutlet UITextField *passwordTextField; 9 10 @end 11 12 @implementation LoginViewController 13 14 - (void)viewDidLoad { 15 [super viewDidLoad]; 16 17 18 } 19 #pragma mark - 登录按钮的响应方法 20 - (IBAction)loginAction:(UIButton *)sender { 21 // 调用登录方法 22 [[XMPPManager sharedXMPPManager] loginWithUserName:self.userNameTextField.text password:self.passwordTextField.text]; 23 } 24 25 @end
RegisterViewController.m
1 #import "RegisterViewController.h" 2 #import "XMPPManager.h" 3 4 @interface RegisterViewController ()<XMPPStreamDelegate> 5 /// 用户名 6 @property (weak, nonatomic) IBOutlet UITextField *userNameTextField; 7 /// 密码 8 @property (weak, nonatomic) IBOutlet UITextField *passwordTextField; 9 10 @end 11 12 @implementation RegisterViewController 13 14 - (void)viewDidLoad { 15 [super viewDidLoad]; 16 17 } 18 #pragma mark - 注册按钮点击事件 19 - (IBAction)registerAction:(UIButton *)sender { 20 XMPPManager *manager = [XMPPManager sharedXMPPManager]; 21 // 设置代理 22 [manager.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; 23 // 调用注册方法 24 [manager registerWithUserName:self.userNameTextField.text password:self.passwordTextField.text]; 25 26 27 } 28 #pragma mark -----------------以下是XMPPStreamDelegate协议中的方法---------------- 29 #pragma mark - 注册成功, 返回登录界面 30 - (void)xmppStreamDidRegister:(XMPPStream *)sender { 31 NSLog(@"注册成功"); 32 [self dismissViewControllerAnimated:YES completion:nil]; 33 } 34 35 #pragma mark - 注册失败 36 - (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error { 37 NSLog(@"注册失败 error = %@", error); 38 } 39 40 #pragma mark -----------------以上是XMPPStreamDelegate协议中的方法---------------- 41 @end
这个Openfire的界面可以查看数据库中的用户