UI进阶 即时通讯之XMPP登录、注册

一、即时通讯

  • 什么是即时通讯、
    • 即时通讯(Instant Messaging)是目前Internet上最为流行的通讯方式,各种各样的即时通讯软件也层出不穷,服务提供商也提供了越来越丰富的通讯服务功能。
  • 即时通讯的实现方式
    • 即时通讯有多种实现方式,例如:XMPP、环信、融云等。
  • 什么是XMPP
    • 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的界面可以查看数据库中的用户

posted @ 2016-05-19 22:06  fearlessyyp  阅读(567)  评论(0编辑  收藏  举报