zoukankan      html  css  js  c++  java
  • iOS开发-即时通信XMPP


    1. 即时通信

     1> 概述

      即时通讯(Instant Messaging)是目前Internet上最为流行的通讯方式,各种各样的即时通讯软件也层出不穷,服务提供商也提供了越来越丰富的通讯服务功能。

      即时通讯有多种实现方式,例如:XMPP、环信、融云等。

     2> XMPP(可扩展消息处理现场协议) 

      XMPP(XML Messages Presence Protocol(可扩展消息处理现场协议))是基于可扩展标记语言(XML)的协议,可用于即时通信(IM)。

     3> XMPP的优点

    • 开放

      XMPP协议是由JSF开源社区组织开发的,不属于任何的机构和个人,从根本上保证了其开放性。

    • 标准

      互联网工程工作组将XMPP于2002年正式列为认可的实时通讯及Presence技术。

    • 分布式的网络架构

      XMPP 协议虽然是基于Client/Server 架构,但是XMPP协议本身并没有这样的限制。网络的架构和电子邮件十分相似,但没有结合任何特定的网络架构,适用范围非常广泛。

    • XMPP 协议具有良好的扩展性

      基于XML 建立起来的应用具有良好的语义完整性和扩展性。

    • XMPP 具有很好的弹性

      XMPP 除了可用在即时通信的应用程序,还能用在网络管理、内容供稿、协同工具、档案共享、游戏、远端系统监控等。

    • 安全性

      XMPP在Client-to-Server通信和Server-to-Server通信中都使用TLS (Transport Layer Security)协议作为通信通道的加密方法,保证通信的安全。

      XMPP环境的搭建的步骤详见XMPP环境的搭建

    2. 工程中添加XMPP

      将XMPP协议第三方文件拖入工程,下载地址:https://github.com/AlonerOwl/XMPPFramework

    3. 登录、注册

     1> 界面搭建

      界面采用Storyboard,效果图如下:

     2> 初始化XMPP通道

            //初始化通道
            self.xmppStream = [[XMPPStream alloc] init];
            //openfire服务器IP地址
            self.xmppStream.hostName = kHostName;
            //openfire服务器端口 默认5222
            self.xmppStream.hostPort = kHostPort;
            //添加代理
            [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()
             ];

     3> 连接服务器代码所需方法

     4> 登录代码所需方法

     5> 注册代码所需方法

     

     6> 全部代码(方法的使用详见代码注释)

    • 封装的XMPP控制器代码:

       XMPPManager.h

    #import <Foundation/Foundation.h>
    
    #import "XMPPFramework.h"
    
    @interface XMPPManager : NSObject
    
    /// 声明XMPP通道属性
    @property (nonatomic, strong) XMPPStream *xmppStream;
    
    + (XMPPManager *)shareXMPPManager;
    
    // 登录方法
    - (void)loginWithUsername:(NSString *)username
                     password:(NSString *)password;
    // 注册方法
    - (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
    
    + (XMPPManager *)shareXMPPManager
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            xmppManager = [XMPPManager new];
        });
        return xmppManager;
    }
    
    #pragma mark - 1.创建通道
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            //初始化对象
            self.xmppStream = [XMPPStream new];
            
            // 设置服务器
            [self settingUpServer];
        }
        return self;
    }
    
    // 设置服务器
    - (void)settingUpServer
    {
        // 设置opfire服务器
        self.xmppStream.hostName = kHostName;
        // 设置服务器端口号
        self.xmppStream.hostPort = kHostPort;
        // 添加代理
        [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    
    #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:域名
        // 参数3:资源
        XMPPJID *jid = [XMPPJID jidWithUser:self.username domain:kDomin resource:kResource];
        
        self.xmppStream.myJID = jid;
        
        // 如果当前聊天工具处于连接状态或已经连接,此时,你需要去切断连接【此逻辑不唯一】
        if ([self.xmppStream isConnected] || [self.xmppStream isConnecting]) {
            // 断开连接
            [self disConnectToServer];
        }
        
        // 设置连接超时
        NSError *error = nil;
        [self.xmppStream connectWithTimeout:30 error:&error];
        if (error) {
            NSLog(@"连接超时");
        }
        
    }
    
    #pragma mark - 断开连接(自己写的)
    - (void)disConnectToServer
    {
        // 当前用户不可用(下线了)
        XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
        // 告诉通道用户不可用(下线了)
        [self.xmppStream sendElement:presence];
        // 使用通道失去连接
        [self.xmppStream disconnect];
    }
    
    #pragma mark - XMPPStreamDelegate协议方法
    
    #pragma mark 连接超时
    - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender
    {
        NSLog(@"连接超时");
    }
    
    #pragma mark 连接成功
    - (void)xmppStreamDidConnect:(XMPPStream *)sender
    {
        NSLog(@"连接成功");
        
        // 认证密码
    //    [self.xmppStream authenticateWithPassword:self.password error:nil];
        
        // 区分登录和注册进行密码验证
        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)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
    {
        // 1. 自己动手断开
        // 2. 被动断开
        if (error) {
            NSLog(@"断开连接,error == %@", error);
        }
    }
    
    #pragma mark 认证失败
    - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error
    {
        NSLog(@"认证失败:error = %@", error);
    }
    
    #pragma mark 认证成功
    - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
    {
        // 当前用户可用(上线了)
        XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
        // 告诉通道用户可用(上线了)
        [self.xmppStream sendElement:presence];
        
        NSLog(@"认证成功");
    }
    
    @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];
        // Do any additional setup after loading the view.
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    - (IBAction)loginAction:(UIButton *)sender
    {
        [[XMPPManager shareXMPPManager] 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 *registerUNTextField;
    @property (weak, nonatomic) IBOutlet UITextField *registerPWTextField;
    
    @end
    
    @implementation RegisterViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        // 添加代理
        [[XMPPManager shareXMPPManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    // 按钮点击事件
    - (IBAction)registerAction:(id)sender
    {
        [[XMPPManager shareXMPPManager] registerWithUsername:self.registerUNTextField.text password:self.registerPWTextField.text];
    }
    
    #pragma mark - XMPPStreamDelegate实现协议方法
    // 注册成功后,dismiss到登录界面
    - (void)xmppStreamDidRegister:(XMPPStream *)sender
    {
        NSLog(@"注册成功");
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    
    // 注册失败
    - (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error
    {
        NSLog(@"注册失败:%@", error);
    }
    
    @end

  • 相关阅读:
    进度条
    html5 表单新增事件
    html5 表单的新增type属性
    html5 表单的新增元素
    html5 语义化标签
    jq 手风琴案例
    codeforces 702D D. Road to Post Office(数学)
    codeforces 702C C. Cellular Network(水题)
    codeforces 702B B. Powers of Two(水题)
    codeforces 702A A. Maximum Increase(水题)
  • 原文地址:https://www.cnblogs.com/melons/p/5791772.html
Copyright © 2011-2022 走看看