示例代码地址
介绍
XMPP(前身是Jabber)是一种即时通讯协议,是一种分散型通讯网络,核心是基于XML流(传输过程中是二进制流,面向开发是XML流)传输数据,没有二进制传输。
扩展协议——Jingle,支持语音和视频,iOS平台尚不支持(可使用链接实现)。
XMPP是典型的C/S架构,定义了客户端,服务器,网关三个角色,通讯可在任意两者之间相互发生。这种架构服务端压力较大。基本的网络形式是基于socket,单客户端通过TCP/IP连接到服务器,在此之上传输XML流。
任何基于XMPP协议的服务器,是可以相互通讯的。
核心概念
- XMPPStream:开发中最主要交互的类,所有扩展和自定义代码都要通过这个类进行
- XMPPParser:供XMPP解析使用
- XMPPJID:提供一个不可变JID的实现 ,遵守NSCoping协议和NSCoding协议
- XMPPElement:
- XMPPQ 请求
- XMPPMessage 消息
- XMPPPresence 出席
- XMPPModule:开发XMPP扩展时使用
- XMPPLogging:XMPP日志框架
- XMPPInternal:整个XMPP框架内部使用的核心和高级底层内容
核心处理流程
- 在AppDelegate中,实现登录
- 初始化XMPPStream
- 连接服务器 [传一个JID]
- 连接服务器成功后,发送密码授权
- 授权成功后,发送 “在线(presence)” 消息
- (void)setupXMPPStream;
- (void)connectToHost;
- (void)sendPwdToHost;
- (void)sendOnlineToHost;
初始化
_xmppStream = XMPPStream.alloc.init;
// 如果需要添加扩展模块(名片、头像等),要在设置代理之前写
[_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
JID
XMPPJID *myJID = [XMPP jidWithUser:@"user" domain:@"text.local" resource:@"iphone"];
_xmppStream.myJID = myJID;
// 可以是域名或IP地址
_xmppStream.hostName = @"www.abc.com";
// 框架,默认端口是5222,可省略
_xmppStream.hostPort = 5222;
NSError*err = nil;
if (![_xmppstream connectWithTimeout:XMPPStreamTimeOutNone error:&err]) {
}
登录
- (void)sendOnlineToHost
{
// 4. 授权成功后,发送“在线”消息
XMPPPresence *presence = [XMPPPresence presence];
// 发送XML类型presense字符串
[_xmppStream sendElement:presence];
}
登出
- (void)loginout {
// 创建消息对象,类型为离线
XMPPresence *offline = [XMPPresence presenceWithType:@"unavailable"];
// xmppStream发送离线消息
[_xmppStream sendElement:offline];
// 与服务器断开连接
[_xmppStream disconnect];
}
常见模块
模块需在XMPPFramework.h头文件中导入。
// 自动连接模块
#import "XMPPReconnect.h"
// 电子名片模块
#import "XMPPvCardTempModule.h"
#import "XMPPvCardCoreDataStorage.h"
// 头像模块
#import "XMPPCardAvatarModule.h"
// 花名册模块
#import "XMPPRoster.h"
#import "XMPPRosterCoreDataStorage.h"
// 聊天(消息)模块
#import "XMPPMessageArchiving.h"
#import "XMPPMessageArchivingCoreDataStorage.h"
每一个模块添加后都要激活!
电子名片模块
- XEP-0054提供一种机制,通过XMPP发送电子名片
- 在XMPPFramework.h中启动电子名片扩展头文件:
#import "XMPPvCardCoreDataStorage.h"
#import "XMPPvCardTempModule.h"
- 定义属性及成员变量
- 为XMPPSteam添加电子名片扩展
- 在需要时使用电子名片
// 添加电子名片模块
_vCard = [[XMPPvCardTempModule alloc] initWithvCardStorage:_vCardStorage];
[_vCard activate:_xmppStream];
头像模块
- 在XMPPFramework.h中启动电子名片扩展头文件:
#import "XMPPvCardAvatarModule.h"
- 初始化
_avatar = [[XMPPvCardAvatarModule alloc] initWithCardTempModule:_vCard]; // 激活 [_avatar activate:_xmppStream];
- 使用
XMPPvCardTemp *vCard = WCXMPPTool.sharedWCXMPPTool.vCard.myvCardTemp;
vCard.photo = UIImagePNGRepresentation(image);
// 更新,这个方法内部实现数据上传到服务器,无需程序自己操作
[WCXMPPTool.sharedWCXMPPTool.vCard updateMyvCardTemp:vCard];
```
#### 当前用户个人信息获取
- 使用coreData获取数据
- 上下文关联到数据
- FetchRequest
- 设置过滤和排序
- 执行请求获取数据
```js
// XMPP提供直接过去个人信息的API
XMPPvCardTemp *myvCard = WCXMPPToll.sharedWCXMPPTool.vCard.myVCardTemp;
// 设置头像
if (myCard.photo) {
// 设置头像的业务代码
headImgV.image = myCard.photo
}
// 设置昵称
nicklabel.text = myCard.nickname;
// 设置微信号(用户名)
NSString *user = WCUserInfo.sharedWCUserInfo.user;
userlabel.text = user;
自动连接模块
_reconnect = XMPPReconnect.alloc.init;
[_reconnect activate:_xmppStream];
花名册模块
- 需要使用花名册,首先在XMPPFramework.h中启用电子名片扩展头文件:
#import "XMPPRoster.h"
#import "XMPPRosterCoreDataStorage.h"
- 定义属性与成员变量
- 为XMPPStream添加花名册扩展
- 设置花名册代理
_rosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
_roster = [[XMPPRoster alloc] initWithRosterStorage:_rosterStorage];
// 激活
[_roster activate:_xmppStream];
- 在需要时使用花名册
// 创建上下文
NSManageObjectContext *context = WCXMPPTool.sharedWCXMPPTool.rosterStorage.mainThreadManagedObjectContext;
// 查询哪张表
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:"XMPPUserCoreDataStorageObject"];
// 设置过滤和排序,过滤当前登录用户的好友
NSString *jid = WCUserInfo.sharedWCUserInfo.jid;
NSPrediate *pre = [NSPrediate predicateWithFormat:@"streamBareJidStr = %@", jid];
request.predicate = pre;
// 排序
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"displayName" ascending:YES];
request.sortDescriptors = @[sort];
// 执行请求获取数据,好友列表
self.friends = [context executeFetchRequest:request error:nil];
// resultsContrl = [[NSFetchedResultsController alloc] initWithFetchRequest:request manageObjectContext:context sectionNameKeyPath:nil cacheName:nil];
// resultsContrl.delegate= self;
// NSError *err = nil;
// [resultsContrl performFetch:&err];
// if (err) return;
// delegate
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// 数据发生改变后的回调
}
好友信息
// cell 代理方法中获取好友信息
XMPPUserCoreDataStorageObject *friend = _resultsContrl.fetchedObjects[indexPath.row];
// 获取好友状态,0表示在线,1表示离开,2表示离线
friend.sectionNum.intValue
添加好友
// 是否为添加自己
if ([user isEqualToString:WCUserInfo.sharedWCUserInfo.user]) return;
NSString *jidStr = [NSString stringWithFormat:@"%@@%@", user, domain];
XMPPJID*friendJid = [XMPPJID jidWithString:jidStr];
// 判断好友是否存在
if ([WCXMPPTool.sharedWCXMPPTool.rosterStorage userExistsWithJID:friendJid xmppStream:WCXMPPTool.sharedWCXMPPTool.xmppStream]) return;
// 添加好友,使用XMPP订阅API
[WCXMPPTool.sharedWCXMPPTool.roster subscribePresenceToUser:friendJid];
删除好友
XMPPUserCoreDataStorageObject *friend = _resultsContrl.fetchedObjects[indexPath.row];
XMPPJID *jid = friend.jid;
[WCXMPPTool.sharedWCXMPPTool.roster removeUser:jid];
聊天模块
- 初始化
_msgStorage = [[XMPPMessageArchivingCoreDataStorage alloc] init];
_msgArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:_msgStorage];
[_msgArchiving activate:_xmppStream];
- 发送聊天消息
- (void)sendMsgWithText:(NSString *)text bodyType:(XMPPBodyType)type {
XMPPMessage *msg = [XMPPMessage messageWithType:@"chat" to:_friendJid];
switch (type) {
case XMPPBodyTypeText:
{
[message addAttributeWithName:@"bodyType" stringValue:@"text"];
}
break;
case XMPPBodyTypeImage:
{
[msg addAttributeWithName:@"bodyType" stringValue:@"image"];
}
break;
case XMPPBodyTypeVideo:
{
[msg addAttributeWithName:@"bodyType" stringValue:@"video"];
}
break;
default:
break;
}
[msg addBody:text];
[WCXMPPTool.sharedWCXMPPTool.xmppStream sendElement:msg];
}
释放XMPPStream相关资源
- (void)teardowmStream {
[xmppStream removeDelegate:self];
[xmppRoster removeDelegate:self];
[xmppReconnect deactivate];
[xmppRoster deactivate];
[xmppCardTempModule deactivate];
[xmppCardAvatarModule deactivate];
[xmppCapabilities deactivate];
[xmppStream disconnect];
xmppReconnect = nil;
xmppStream = nil;
xmppRoster = nil;
xmppCardAvatarModule = nil;
xmppCardTempModule = nil;
xmppCapabilities = nil;
}