iOS进阶学习-即时通讯(1)

一、即时通讯

  1、简介

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

  2、实现方式

  即时通讯有多种实现方式,例如:XMPP、环信、融云等。
下面我们对XMPP的使用进行介绍。

  3、什么是XMPP

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

  4、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环境:具体操作请参考我的另一篇博客XMPP环境搭建。

四、工程中添加XMPP

  1、创建新工程
  2、导入XMPP框架,XMPPFramework:github下载地址
  3、引入XMPP需要的依赖库 libxml   libresolv
  4、设置路径 /usr/include/libxml2

  

五、登录、注册

  首先用storyboard搭建框架:

  具体代码实现:

  LoginViewController.m

@interface LoginViewController ()
/// 用户名
@property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
/// 密码
@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;

@end

@implementation LoginViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];

}
#pragma mark - 登录按钮的响应方法
- (IBAction)loginAction:(id)sender {
    [[XMPPManager sharedXMPPManager] loginWithUserName:self.userNameTextField.text password:self.passwordTextField.text];
}

@end

  RegisterViewController.m

@interface RegistViewController ()<XMPPStreamDelegate>

/// 注册用户名
@property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
/// 注册密码
@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;

@end

@implementation RegistViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [[XMPPManager sharedXMPPManager].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 sharedXMPPManager] registerWithUserName:self.userNameTextField.text password:self.passwordTextField.text];
}

#pragma mark - 实现XMPPStreamDelegate协议方法
// 实现协议是为了满足需求:注册成功之后跳转(dismiss)回页面
- (void)xmppStreamDidRegister:(XMPPStream *)sender
{
    NSLog(@"注册成功");
    [self dismissViewControllerAnimated:YES completion:nil];
}
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error
{
    NSLog(@"注册失败:error = %@", error);
}

@end

  XMPPManager.h

@interface XMPPManager : NSObject

/// 声明一个通道的属性
@property (nonatomic, strong) XMPPStream *xmppStream;

+ (XMPPManager *)sharedXMPPManager;

// 登录的方法
- (void)loginWithUserName:(NSString *)userName
                 password:(NSString *)password;

// 注册的方法
- (void)registerWithUserName:(NSString *)userName
                    password:(NSString *)password;

@end

  XMPPManager.m

#import "XMPPManager.h"

static XMPPManager *manager = nil;

// 记录状态
typedef NS_ENUM(NSUInteger, ConnectToServerPurpose) {
    ConnectToServerPurposeLogin,
    ConnectToServerPurposeRegister,
};

@interface XMPPManager ()<XMPPStreamDelegate>
/// 记录当前状态(登录/注册)
@property (nonatomic) ConnectToServerPurpose connectToServer;
/// 用户名
@property (nonatomic, strong) NSString *userName;
/// 密码
@property (nonatomic, strong) NSString *password;
/// 注册的用户名
@property (nonatomic, strong) NSString *registerUserName;
/// 注册的密码
@property (nonatomic, strong) NSString *registerPassword;

@end

@implementation XMPPManager

+ (XMPPManager *)sharedXMPPManager
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[XMPPManager alloc] init];

    });
    return manager;
}

#pragma mark - 1.创建通道
- (instancetype)init
{
    self = [super init];
    if (self) {
        // 初始化通道
        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()];

    }
    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.registerUserName = userName;
    self.registerPassword = password;
    // 记录注册状态
    self.connectToServer = ConnectToServerPurposeRegister;
    // 连接服务器
    [self linkServer];

}
#pragma mark - 连接服务器
- (void)linkServer
{
    NSString *string = [[NSString alloc] init];
    switch (self.connectToServer) {
        case ConnectToServerPurposeLogin:
            string = [NSString stringWithFormat:@"%@", self.userName];
            break;
        case ConnectToServerPurposeRegister:
            string = [NSString stringWithFormat:@"%@", self.registerUserName];
            break;
        default:
            break;
    }
    // 要连接服务器,要有用户身份认证
    // 身份证
    // 第一个参数:用户名
    // 第二个参数:域名
    // 第三个参数:资源
    XMPPJID *jid = [XMPPJID jidWithUser:string domain:kDomin resource:kResource];
    // 通过通道进行身份验证
    self.xmppStream.myJID = jid;

    // 如果当前聊天工具处于连接状态或者已经连接,此时,需要切断连接(此逻辑不唯一,根据需求而定)
    if ([self.xmppStream isConnected] || [self.xmppStream isConnecting]) {
        // 切断连接
        [self disConnectedToServer];
    }
    // 设置连接超时
    NSError *error = nil;
    [self.xmppStream connectWithTimeout:30 error:&error];
    if (error) {
        NSLog(@"服务器连接超时");
    }
}
#pragma mark - 断开连接
- (void)disConnectedToServer
{
    // 当前用户下线了
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    // 告诉通道下线了
    [self.xmppStream sendElement:presence];
    // 使通道失去连接
    [self.xmppStream disconnect];

}

#pragma mark - XMPPStreamDelegate协议方法
// 连接超时
- (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender
{
    NSLog(@"连接超时");
}

// 连接成功
- (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.registerPassword error:nil];
            break;
        default:
            break;
    }

}
// 断开连接
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
    // 自己手动断开
    // 被动断开
    if (error) {
        NSLog(@"断开连接,erroe = @%@", error);
    }
}
// 认证失败
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error
{
    NSLog(@"认证失败:error = %@", error);
}
// 认证成功
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
    // 上线
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
    [self.xmppStream sendElement:presence];
    NSLog(@"认证成功");

}

  未完待续...

时间: 2024-10-11 07:32:46

iOS进阶学习-即时通讯(1)的相关文章

iOS进阶学习-即时通讯(2)

本篇是续接即时通讯(1). 一.好友列表 管理好友列表是通过XMPP中的花名册(XMPPRoster).代码示例: #pragma mark - 管理好友 // 获取管理好友的单例对象 XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance]; // 给roster属性进行初始化 self.xmppRoster = [[XMPPRoster alloc] initWithRoster

iOS进阶学习-地图

一.地图的简介 在移动互联网时代,移动app能解决用户的很多生活琐事,比如: 导航:去任意陌生的地方. 周边:找餐馆.找酒店.找银行.找电影院. 手机软件:微信摇一摇.QQ附近的人.微博.支付宝等. 在上述应用中,都用到了地图和定位功能,在iOS开发中,要想加入这两大功能,必须基于两个框架进行开发: Map Kit :用于地图展示. Core Location :用于地理定位. 二.地图定位(CoreLocation框架,地理编码与反地理编码) 1.CoreLocation框架的使用 导入头文件

iOS进阶学习-多线程

一.多线程概述 1.程序,进程,线程 程序:由源代码生成的可执行应用.(例如:QQ.app) 进程:一个正在运行的程序可以看做一个进程.(例如:正在运行的QQ就是一个进程),进程拥有独立运行所需的全部资源. 线程:程序中独立运行的代码段.(例如:接收QQ消息的代码) 一个进程是由一或多个线程组成.进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行. 2.单线程 每个正在运行的程序(即进程),至少包含一个线程,这个线程叫主线程. 主线程在程序启动时被创建,用于执行main函数.

iOS进阶学习笔记

熟练掌握C/C++/Objective-C/Swift语言: 熟悉Cocoa Touch(Foundation,UIKit).Objective-C中block,gcd,NSOperation等: 熟悉Object消息传递等机制,Objective-C Runtime,阅读源码: 熟练使用大部分iOS平台常用库,开源库(AFNetworking,SDWebImage,fmdb),开源控件(EGOTableViewPullRefresh,MRProgress); 关注github上iOS平台开源项

iOS进阶学习-CocoaPods的安装与使用

一.CocoaPods的安装 1.简介: CocoaPods是一个用来帮助我们管理第三方依赖库的工具. 在开发iOS应用时,会经常使用第三方类库,比如SDWebImage.AFNetworking等等,手动的下载与添加类库非常麻烦,通过CocoaPods可以便捷的下载与管理第三方类库. 使用CocoaPods的目的是让我们能自动化的.集中的.直观的管理第三方开源库. 官方链接:https://cocoapods.org 2.安装步骤 第一步:打开终端,查看自己电脑的ruby环境:gem sour

iOS进阶学习-网络之数据请求

注:文中出现的网站只做用例子,所以有些已经失效的网站,具体URL大家可以自己上网搜索相关资源. 一.HTTP和HTTPS协议 1.URL: URL全称是Uniform Resource Locator(统一资源定位符)通过1个URL,能找到互联网上唯一的1个资源 URL就是资源的地址.位置,互联网上的每个资源都有一个唯一的URL URL的基本格式=协议://主机地址/路径 http://www.cnblogs.com/soley 协议:不同的协议,代表着不同的资源查找方式,资源传输方式 主机地址

iOS进阶学习-数据处理之文件读写

一.沙盒机制 1.什么是沙盒? 每一个iOS应用程序都会为自己创建一个文件系统目录(文件夹),这个独立.封闭.安全的空间,叫做沙盒. 2.沙盒机制(SandBox) 沙盒是一种安全体系. 它规定了应用程序只能在为该应用程序创建的文件夹(沙盒)内访问文件,不可以访问其它沙盒内的内容(iOS8之后已经部分开放访问). 所有的非代码文件都保存在这个地方,比如图片.声音.属性列表(plist).sqlite数据库和文本文件等. 3.沙盒机制的特点: 每个应用程序的活动范围都限定在自己的沙盒里. 不能随意

iOS进阶学习-数据库

一.数据库管理系统 1.SQL语言概述:SQL是Structured Query Language(结构化查询语言)的缩写.SQL是专为数据库而建立的操作命令集,是一种功能齐全的数据库语言. 2.常见的数据库: MySQL:MySQL是一个精巧的SQL数据库管理系统,而且是开源的数据管理系统.MySQL主要目标是快速.健壮和易用.它拥有强大的功能.灵活性.丰富的应用编程接口(API)以及精巧的系统结构. Oracle:Oracle Database,又名Oracle RDBMS,或简称Oracl

iOS进阶学习-初识AFNetworking

一.AFNetworking简介 AFNetworking是一个 在iOS开发中 使用非常多网络开源库 适用于iOS以及Mac OS X.它构建于在(Apple iOS开发文档) NSURLConnection ,  NSOperation , 以及其他熟悉的Foundation技术之上. 它拥有良好的架构,丰富的api,以及模块化构建方式,使得使用起来非常轻松. 官方链接http://cocoadocs.org/docsets/AFNetworking/1.3.0/. AFNetworking