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  

            •  

        #import <Foundation/Foundation.h>
        #import "XMPPFramework.h"
        
        @interface XMPPManager : NSObject
        /// 声明一个通道属性
        @property (nonatomic, strong)XMPPStream *xmppStream;
        
        #pragma mark - 单例
        + (instancetype)sharedXMPPManager;
        
        #pragma mark - 登录
        - (void)loginWithUserName:(NSString *)userName
                         password:(NSString *)password;
        
        #pragma mark - 注册
        - (void)registerWithUserName:(NSString *)userName
                            password:(NSString *)password;
        @end

        XMPPManager.m

      • #import "XMPPManager.h"
        
        static XMPPManager *xmppManager = nil;
        
        // 定义枚举值,用来区分当前的状态是登录还是注册
        typedef NS_ENUM(NSUInteger, ConnectToServerPurpose) {
            ConnectToServerPurposeLogin,  // 登录
            ConnectToServerPurposeRegister,  // 注册
        };
        
        @interface XMPPManager ()<XMPPStreamDelegate>
        /// 用户名
        @property (nonatomic, copy) NSString *userName;
        /// 密码
        @property (nonatomic, copy) NSString *password;
        
        /// 记录当前的状态是登录还是注册
        @property (nonatomic) ConnectToServerPurpose connectToServer;
        @end
        
        @implementation XMPPManager
        #pragma mark - 单例
        + (instancetype)sharedXMPPManager {
            static dispatch_once_t oneToken;
            dispatch_once(&oneToken, ^{
                xmppManager = [[XMPPManager alloc] init];
            });
            return xmppManager;
        }
        
        #pragma mark - 创建通道
        - (instancetype)init {
            if (self = [super init]) {
                // 初始化通道对象
                self.xmppStream = [[XMPPStream alloc] init];
                // 设置Openfire服务器主机名
                self.xmppStream.hostName = kHostName;
                // 设置服务器端口号
                self.xmppStream.hostPort = kHostPort;
                // 设置代理
                [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
            }
            return self;
        }
        
        #pragma mark - 登录
        - (void)loginWithUserName:(NSString *)userName
                         password:(NSString *)password {
            self.userName = userName;
            self.password = password;
            // 设置当前的状态为登录
            self.connectToServer = ConnectToServerPurposeLogin;
            // 连接服务器
            [self linkServer];
            
        }
        
        #pragma mark - 注册
        - (void)registerWithUserName:(NSString *)userName
                            password:(NSString *)password {
            self.userName = userName;
            self.password = password;
            // 设置当前的状态为注册
            self.connectToServer = ConnectToServerPurposeRegister;
            // 连接服务器
            [self linkServer];
        }
        
        #pragma mark - 连接服务器
        - (void)linkServer {
            // 要连接服务器,要有用户身份认证
            // 身份认证
            // 参数1:用户名
            // 参数2:domain是域名
            // 参数3:资源
            XMPPJID *jid = [XMPPJID jidWithUser:self.userName domain:kDomin resource:kResource];
            
            // 通过通道进行身份验证
            self.xmppStream.myJID = jid;
            
            // (根据项目需求来定)如果当前聊天工具处于连接状态,或者已经连接了,此时你需要去切断连接
            if ([self.xmppStream isConnected] || [self.xmppStream isConnecting]) {
                // 调用自定义方法
                [self disconnectionToServer];
            }
            
            // 连接超时
            NSError *error = nil;
            [self.xmppStream connectWithTimeout:30 error:&error];
            if (error) {
                NSLog(@"服务器连接超时");
            }
        }
        
        #pragma mark - 手动断开连接(注销)
        - (void)disconnectionToServer {
            // 设置当前用户状态为下线
            XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
            // 告诉通道下线
            [self.xmppStream sendElement:presence];
            // 通道失去连接
            [self.xmppStream disconnect];
            NSLog(@"(自定义方法)断开连接");
        }
        
        
        #pragma mark -----------------以下XMPPStreamDelegate是协议中的方法----------------
        
        #pragma mark - 连接成功
        - (void)xmppStreamDidConnect:(XMPPStream *)sender {
            NSLog(@"服务器连接成功");
            // 校验密码
            switch (self.connectToServer) {
                case ConnectToServerPurposeLogin:
                    // 校验登录密码
                    [self.xmppStream authenticateWithPassword:self.password error:nil];
                    break;
                case ConnectToServerPurposeRegister:
                    // 注册
                    [self.xmppStream registerWithPassword:self.password error:nil];
                    break;
                default:
                    break;
            }
            
        }
        
        #pragma mark - 连接超时
        - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender {
            NSLog(@"服务器连接超时");
        }
        
        #pragma mark - 已经断开连接
        - (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error {
            // 连接被断开的情况
            // 1、自己手动断开
            // 2、被动断开
            NSLog(@"已经断开连接");
        }
        
        #pragma mark - 用户认证失败
        - (void) xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error {
            NSLog(@"登录失败 %@", error);
        }
        
        #pragma mark - 认证成功
        - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
            // 设置用户状态为上线
            XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
            // 告诉通道上线
            [self.xmppStream sendElement:presence];
            NSLog(@"用户已上线");
        
        }
        #pragma mark -----------------以上是XMPPStreamDelegate协议中的方法----------------
        // 关于注册是否成功的代理方法写在了RegisterViewController.m中
        
        
        @end

        LoginViewController.m

      • #import "LoginViewController.h"
        #import "XMPPManager.h"
        
        @interface LoginViewController ()
        /// 用户名
        @property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
        /// 密码
        @property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
        
        @end
        
        @implementation LoginViewController
        
        - (void)viewDidLoad {
            [super viewDidLoad];
        
        
        }
        #pragma mark - 登录按钮的响应方法
        - (IBAction)loginAction:(UIButton *)sender {
            // 调用登录方法
            [[XMPPManager sharedXMPPManager] loginWithUserName:self.userNameTextField.text password:self.passwordTextField.text];
        }
        
        @end

        RegisterViewController.m

        #import "RegisterViewController.h"
        #import "XMPPManager.h"
        
        @interface RegisterViewController ()<XMPPStreamDelegate>
        /// 用户名
        @property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
        /// 密码
        @property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
        
        @end
        
        @implementation RegisterViewController
        
        - (void)viewDidLoad {
            [super viewDidLoad];
        
        }
        #pragma mark - 注册按钮点击事件
        - (IBAction)registerAction:(UIButton *)sender {
            XMPPManager *manager = [XMPPManager sharedXMPPManager];
            // 设置代理
            [manager.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
            // 调用注册方法
            [manager registerWithUserName:self.userNameTextField.text password:self.passwordTextField.text];
            
            
        }
        #pragma mark -----------------以下是XMPPStreamDelegate协议中的方法----------------
        #pragma mark - 注册成功, 返回登录界面
        - (void)xmppStreamDidRegister:(XMPPStream *)sender {
            NSLog(@"注册成功");
            [self dismissViewControllerAnimated:YES completion:nil];
        }
        
        #pragma mark - 注册失败
        - (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error {
            NSLog(@"注册失败 error = %@", error);
        }
        
        #pragma mark -----------------以上是XMPPStreamDelegate协议中的方法----------------
        @end

        这个Openfire的界面可以查看数据库中的用户

posted @ 2016-05-24 17:54  董小火  阅读(519)  评论(0编辑  收藏  举报