UI進階 即時通信之XMPP登陸、註冊

1、即時通信

    • 什麼是即時通信、
      • 即時通信(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)協議做爲通訊通道的加密方法,保證通訊的安全
      • 2、XMPP實現即時通信

        • 原理
          實現即時通信至少須要一個服務器端、兩個客戶端。
            • 下面咱們準備須要的環境:
              一、XMPP服務器     二、XMPP客戶端(輔助調試)

              一、XMPP環境搭建

              http://www.cnblogs.com/fearlessyyp/p/5506644.htmlhtml

              第一次打開可能會有點兒慢,圖片不少,步驟很詳細,祝搭建成功。數據庫

              二、工程中添加XMPP

              一、建立新工程
              二、導入XMPP框架
              三、引入XMPP須要的依賴庫 libxml   libresolv
              四、設置路徑:在工程的"Build Settings"頁中找到"Header Search Path"項,添加"/usr/include/libxml2"。在"Other Linker Flags"項,添加"-lxml2"  XML解析適配
              安全

              3、XMPP實現登陸、註冊

                一、Main.storyboard搭建界面服務器

            • 二、初始化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 ];
              複製代碼

                三、主要實現框架

                XMPPStream關鍵方法less

                登陸用到的方法dom

                註冊用到的方法分佈式

              封裝了一個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 {
            // 鏈接被斷開的狀況
            // 一、本身手動斷開
            // 二、被動斷開
            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的界面能夠查看數據庫中的用戶

相關文章
相關標籤/搜索