• 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

  • 相关阅读:
    根据一个class,对改class 建一个内表
    将一个内表中的数据,读取到structure中。不用loop循环.
    sap gui中打断点,进入不了断点
    使用python 写一个 股票涨跌提醒功能
    windows使用方法
    mathType插入公式编号,及对公式编号的字体进行修改。调整公式上下间距。
    notefirst使用
    word自动导入目录
    杀死正在运行的进程: linux
    win10系统电脑调节屏幕亮度选项无法显示
  • 原文地址:https://www.cnblogs.com/melons/p/5791772.html
Copyright © 2020-2023  润新知