XMPP

一.什么是XMPP

XMPP是一种基于XML的即时通讯协议,前身是jabber.

二.为什么要写XMPP单例

由于XMPPStream是基于myJID建立的长连接,因此在应用程序中应该仅被实例化一次(也就是建立单例)

+ (id)shareInstance

{

static id _s;

if (_s== nil) {

_s = [[[self class]alloc]init];

}

return _s;

}

三.XMPP初始化

//初始化用户

_currentUser = [[UserModel alloc]init];

_allFriendList = [[NSMutableArray alloc]init];

_xmppStream = [[XMPPStream alloc]init];

//设置主机名

[_xmppStream setHostName:@"1000phone.net"];

//设置端口

[_xmppStream setHostPort:5222];

//在这里并没有连接

//设置代理,有数据回来急用delegate接收

//        xxx.delegate = self; 是一样的

//这里使用了一个多代理,多对多的方式

[_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];

四.用户模型

@property (nonatomic,copy)NSString *jid;

@property (nonatomic,copy)NSString *password;

@property (nonatomic,copy)NSString *status;

五.XMPP注册

//保存注册回调

void (^saveRegCb)(BOOL ret,NSError *error);

- (void)registerUser:(NSString *)jid withPassword:(NSString *)passWord withCompletion:(void (^)(BOOL, NSError *))cb

{

saveRegCb = [cb copy];

isInRegisting = YES;

//真正的注册

if ([_xmppStream isConnected]) {

[_xmppStream disconnect];

}

_currentUser.jid = jid;

_currentUser.password = passWord;

/*

1.给服务器账号

2.服务器返回我收到了账号

3.再给服务器密码

*/

//把jid字符串转化为XMPPJID对象

XMPPJID *myjid = [XMPPJID jidWithString:jid];

//连接服务器

//给xmppStream流设置一个账号

[_xmppStream setMyJID:myjid];

NSError *error = nil;

//异步方式,只是去连,但还没有成功

//connectWithTimeout,这个函数绝对不能调用两次

BOOL ret = [_xmppStream connectWithTimeout:-1 error:&error];

//异步注册,需要代理

if (ret == NO) {

if (saveRegCb) {

saveRegCb(NO,error);

}

}

}

//已经连接

- (void)xmppStreamDidConnect:(XMPPStream *)sender

{

NSLog(@"连接上了 %@",NSStringFromSelector(_cmd));

//输入密码

NSError *error= nil;

//因为不论注册还是登录都会走这个方法,所以用一个变量来区分

if (isInRegisting) {

//一旦注册就会回到xmppStreamDidRegister

[_xmppStream registerWithPassword:_currentUser.password error:&error];

}else

{

//对于已有的用户,这里是授权密码

[_xmppStream authenticateWithPassword:_currentUser.password error:&error];

//一旦授权完成,就会进入密码授权正确

}

//成功和失败

}

//注册成功

- (void)xmppStreamDidRegister:(XMPPStream *)sender

{

NSLog(@"function %@",NSStringFromSelector(_cmd));

if (saveRegCb) {

saveRegCb(YES,nil);

}

}

//注册失败

- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error

{

NSLog(@"function %@",NSStringFromSelector(_cmd));

NSLog(@"error is %@",[error description]);

if (saveRegCb) {

//因为error 是NSXMLElement类型,所以要转化

NSError *myerror = [NSError errorWithDomain:error.description code:-1 userInfo:nil];

saveRegCb(NO,myerror);

}

}

六.XMPP登录

//保存登录回调

void (^saveLoginCb)(BOOL ret,NSError *error);

- (void)loginUser:(NSString *)jid withPassword:(NSString *)passWord withCompletion:(void (^)(BOOL, NSError *))cb

{

saveLoginCb = [cb copy];

isInRegisting = NO;

//登录分为两步

//1.给服务器输入账号,2给服务器输入密码

_currentUser.jid = jid;

_currentUser.password =passWord;

XMPPJID *myjid = [XMPPJID jidWithString:jid];

//有可能是注册完了就登录,所以要断开

if ([_xmppStream isConnected]) {

[_xmppStream disconnect];

}

[_xmppStream setMyJID:myjid];

NSError *error= nil;

BOOL ret= [_xmppStream connectWithTimeout:-1 error:&error];

if (ret == NO) {

saveLoginCb(NO,error);

}

}

//授权成功

- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender

{

NSLog(@"function %@",NSStringFromSelector(_cmd));

//可以上线了

if (saveLoginCb) {

saveLoginCb(YES,nil);

}

//上线,获取所有好友

[self goOnLine];

//取得所有好友信息

//取得当前上线是谁

[self getAllFriends];

}

//授权失败

- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error

{

NSLog(@"function %@",NSStringFromSelector(_cmd));

if (saveLoginCb) {

saveLoginCb(NO,[NSError errorWithDomain:error.description code:-1 userInfo:nil]);

}

}

七.XMPP上线

- (void)goOnLine

{

//presence   曝光

//这个类的作用就是产生一个xml的结构

XMPPPresence *p = [XMPPPresence presence];

//通过给服务器发送XML文件的形式,上线

[_xmppStream sendElement:p];

}

八.XMPP获取好友

void (^saveFriendCb)(NSArray *);

NSMutableArray *_allFriendList;

- (void)getAllFriends

{

//产生一个节点<query xxx>

NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:roster"];

NSXMLElement *iq = [NSXMLElement elementWithName:@"iq"];

[iq addAttributeWithName:@"type" stringValue:@"get"];

[iq addChild:query];

NSLog(@"all friends %@",iq);

//传给服务器,服务器返回的也是xml

[_xmppStream sendElement:iq];

}

#pragma mark - 获取好友(默认是离线状态)

- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq

{

//    NSLog(@"iq is %@",iq);

// XML解析好友列表

NSXMLElement * query = iq.childElement;

for (NSXMLElement * oneChild in query.children) {

NSString * jid = [oneChild attributeStringValueForName:@"jid"];

// 相同JID好友防止重复添加 默认情况下都是离线好友

[self addFriendFromReceiveIQ:jid withStatus:@"unavailable"];

}

return YES;

}

#pragma mark - 更新好友列表 好友状态

- (void)addFriendFromReceiveIQ:(NSString *)name withStatus:(NSString *)status

{

for (UserModel * m in _friendArr) {

if ([m.name isEqualToString:name]) {

return;

}

}

UserModel * m = [[UserModel alloc] init];

m.name = name;

m.status = status;

[_friendArr addObject:m];

if (saveFriendCb) {

saveFriendCb(_friendArr);

}

}

//获取状态更新,这个方法会比获取好友更先走

#pragma mark - 订阅事件  上线 离线 发送好友请求 拒绝好友请求...

/*

available -- (默认)用户空闲状态

unavailable -- 用户没空看消息

subscribe -- 请求订阅别人,即请求加对方为好友

subscribed -- 统一被别人订阅,也就是确认被对方加为好友

unsubscribe -- 他取消订阅别人,请求删除某好友

unsubscribed -- 拒绝被别人订阅,即拒绝对放的添加请求

error -- 当前状态packet有错误

*/

- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence

{

//    [email protected]/747f21ab 变成 [email protected]

// 从presence中提取出谁发送了 上线 下线请求

//    [presence attributeStringValueForName:@"from"]

XMPPJID * fromJid = [XMPPJID jidWithString:[presence attributeStringValueForName:@"from"]];

NSString * jidStr = [NSString stringWithFormat:@"%@@%@",fromJid.user,fromJid.domain];

//XMPPJID * jid = [XMPPJID jidWithString:jidStr];

NSString * status = @"available";

NSString * type = [presence type];

if ([type isEqualToString:@"unavailable"]){

// 离线

status = @"unavailable";

}

else if ([type isEqualToString:@"available"]){

// 上线

status = @"available";

}

[self updateOrAddFriendFromReceivePresence:jidStr withStatus:status];

NSLog(@">>%@ %@",jidStr,status);

}

- (void)updateOrAddFriendFromReceivePresence:(NSString *)name withStatus:(NSString *)status

{

BOOL exist = NO;

// 如果有相同JID的好友 不应该添加至数组

for (UserModel * m in _friendArr) {

if ([m.name isEqualToString:name]) {

exist = YES;

m.status = status;

break;

}

}

// 可以被添加至数组

if (!exist) {

UserModel * m = [[UserModel alloc] init];

m.name = name;

m.status = status;

[_friendArr addObject:m];

}

// 回调好友列表

if (saveFriendCb) {

saveFriendCb(_friendArr);

}

}

- (void)getAllFriends:(void (^)(NSArray *))cb

{

saveFriendCb = [cb copy];

//好友会不断上线下线

if (saveFriendCb) {

saveFriendCb(_allFriendList);

}

}

九.登录页面

- (IBAction)login:(id)sender {

//登录

[[QFXMPPmanager shareInstance]

loginUser:self.nameField.text

withPassword:self.passField.text

withCompletion:^(BOOL ret,NSError *error)

{

if (ret == YES) {

NSLog(@"登录成功");

FriendListViewController *flc = [[FriendListViewController alloc]init];

UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:flc];

[self presentViewController:nav animated:YES completion:nil];

}else

{

NSLog(@"登录失败");

}

}];

}

- (IBAction)regist:(id)sender {

//注册

[[QFXMPPmanager shareInstance]

registerUser:self.nameField.text

withPassword:self.passField.text

withCompletion:^(BOOL ret,NSError *error)

{

if (ret == YES) {

NSLog(@"注册成功");

}else

{

NSLog(@"注册失败");

}

}];

}

十.获取好友页面

- (void)viewDidLoad

{

[super viewDidLoad];

self.title = @"朋友";

[[QFXMPPmanager shareInstance]getAllFriends:^(NSArray *list)

{

[_allFriendList removeAllObjects];

[_allFriendList addObjectsFromArray:list];

[self.tableView reloadData];

}];

}

十一.接收消息页面

[[XMPPmanager shareInstace]refreshMessage:^(ChatModel *model) {

//来一条消息,刷新一条消息

[_chatList addObject:model];

[self.tableView reloadData];

}];

十二.聊天模型

@property (nonatomic,copy)NSString *body;

@property (nonatomic,copy)NSString *from;

@property (nonatomic,copy)NSString *to;

十三.收到的消息

- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message

{

//判断是否是聊天消息

if ([message isChatMessage])

{

//判断消息是否带消息体(body)

if ([message isChatMessageWithBody])

{

NSString *body = [message body];

NSString *from = [[message from]bare];

NSString *to = [[message to]bare];

NSLog(@"body==%@,from=%@,to=%@",body,from,to);

ChatModel *model = [[ChatModel alloc]init];

model.body = body;

model.from = from;

model.to = to;

//刷表

if (saveRefreshMessageBlock) {

saveRefreshMessageBlock(model);

}

}

}

}

十四.发送消息

在聊天的viewController中:

[xmppmanager shareinstace](void)sendMessage:(nssrting *)msg  toUser:(userModel *)toUser  withCompletion:(void (^) (bool ret))cb

- (void)sendMessage:(nssrting *)msg  toUser:(userModel *)toUser  withCompletion:(void (^) (bool ret))cb;

{

saveSendMessageBlocks  = [cb copy];

xmppjid *toJid = [xmppJid jidwithstring:toUser.name];

xmppMessage *oneMessage = [[xmppmessage alloc]initWithtype:@“chat”to:toJid];

[oneMessage addBody:msg];

[_xmppStream sendElement: oneMessage];

}

- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message;

{

if(saveSendMessageBlocks)

{

saveSendMessageBlocks(YES);

}

}

- (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error;

{

if(saveSendMessageBlocks)

{

saveSendMessageBlocks(NO);

}

}

时间: 2024-10-05 03:50:16

XMPP的相关文章

Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送

Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送,写这个系列真的很要命,你要去把他们的API文档大致的翻阅一遍,而且各种功能都实现一遍,解决各种bug各种坑,不得不说,极光推送真坑,大家使用还是要慎重,我们看一下极光推送的官网 https://www.jpush.cn/common/ 推送比较使用,很多软件有需要,所以在这个点拿出来多讲讲,我们本节

XMPP即时通讯

XMPP:XMPP是基于XML的点对点通讯协议,The Extensible Messaging and Presence Protocol(可扩展通讯和表示协议). XMPP可用于服务类实时通讯,表示和需求响应服务中的XML数据元流失传输.XMPP以Jabber协议为基础,而Jabber是即时通讯中常用的开放式协议. 基本结构. XML是一个典型的C/S架构,而不是像大多数即时通讯软件一样,使用P2P客户端到客户端的架构,也就是说在大多数情况下,当两个客户端进行通讯时,他们的消息都是通过服务器

XMPP系列(四)---发送和接收文字消息,获取历史消息功能

今天开始做到最主要的功能发送和接收消息.获取本地历史数据. 先上到目前为止的效果图:              首先是要在XMPPFramework.h中引入数据存储模块: //聊天记录模块的导入 #import "XMPPMessageArchiving.h" #import "XMPPMessageArchivingCoreDataStorage.h" #import "XMPPMessageArchiving_Contact_CoreDataObje

XMPP协议、IM、客户端互联详解

导读 对于推送,IM服务器,目前可以使用一些厂家提供的SDK来实现,但是我们的老板又总是担心使用别人的SDK,假如别人的服务出现问题,或者别人偷看咱们的信息,那岂不是出现很大问题了 聊一聊xmpp的服务器openfire和测试客户端spark 1.什么是XMPP 这里说一下XMPP,我在前几节说的sdk汇总文章提到的部分推送,IM的SDK提供商用的是XMPP协议,当然也有是自己实现的协议的,例如腾讯.XMPP简单的来说,就是一个发送与接收之间定义的规则,不过这个协议和我们传统的协议有点不同,它不

UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天

这篇博客的代码是直接在上篇博客的基础上增加的,先给出部分代码,最后会给出能实现简单功能的完整代码. UI进阶 即时通讯之XMPP登录.注册 1.好友列表 初始化好友花名册 1 #pragma mark - 管理好友 2 // 获取管理好友的单例对象 3 XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance]; 4 // 用管理好友的单例对象初始化Roster花名册 5 // 好友操

UI进阶 即时通讯之XMPP登录、注册

一.即时通讯 什么是即时通讯. 即时通讯(Instant Messaging)是目前Internet上最为流行的通讯方式,各种各样的即时通讯软件也层出不穷,服务提供商也提供了越来越丰富的通讯服务功能. 即时通讯的实现方式 即时通讯有多种实现方式,例如:XMPP.环信.融云等. 什么是XMPP XMPP(XML,Messages,Presence,Protocol)是基于可扩展标记语言(XML)的协议,可用于即时通信(IM).——可扩展消息处理现场协议 XMPP优点 开放XMPP协议是由JSF开源

XMPP环境搭建 (mac环境下 安装自己独立的mysql与服务器(openfire),实现即时聊天功能)

1简单概览 [一]XMPP简介 http://xmpp.org 即时通讯技术 IM - Instant Messaging ?支持?用户在线实时交谈.交谈双?方都需要?一个聊天窗?口,其中?一个?用户输?入信息,交谈双 ?方都可以看到交谈内容 常?见IM系统 AOL.Yahoo IM.MSN.QQ 它们之间的区别在于各?自的通讯协议的实现,即时通讯技术的核?心在于它的传输协议 [二]XMPP通讯协议 协议?用来说明信息在??网络上如何传输,如果有了统?一的传输协议,各个IM之间都可以直接通讯,

xmpp iOS的框架结构

下载框架 https://github.com/robbiehanson/XMPPFramework(下载releases版本的) Authentication  :  授权登录 Categorise  :  分类 Core  :  核心 -- 和服务器交互的类 主要在Core文件夹里面 Extensions   :  扩展模块  "默认在扩展模块里的功能都是没有开启的" Utilities(tool)   :  工具类 Vendor(供应商)  :  xmpp需要使用的第三方框架 -

项目开发--------XMPP即时通讯

一.基本框架结构: StroyBoard的基本页面搭建: 二.个功能代码块的是实现 LoginViewController.m文件(登录页面的基本配置) #import "LoginViewController.h" #import "XMPPManager.h" @interface LoginViewController ()<XMPPStreamDelegate> @property (weak, nonatomic) IBOutlet UITex

xmpp总结

1. 浅谈对于XMPP协议自己的看法以及对其理解 http://blog.sina.com.cn/s/blog_69f68f880102uyeg.html 2. XMPP协议学习笔记一 http://blog.csdn.net/nomousewch/article/details/6431946 XMPP协议学习笔记二 http://blog.csdn.net/nomousewch/article/details/6432129 3. TCP/IP四层模型和OSI七层模型的概念 http://b