xmppframework是一个os x/ios平台的开源项目,使用objective-c实现了xmpp协议(rfc-3920),同时还提供了用于读写xml的工具,大大简化了基于xmpp的通信应用的开发。
1. 登录和好友上下线
1.1xmpp中常用对象们
- xmppstream:xmpp基础服务类
- xmpproster:好友列表类
- xmpprostercoredatastorage:好友列表(用户账号)在core data中的操作类
- xmppvcardcoredatastorage:好友名片(昵称,签名,性别,年龄等信息)在core data中的操作类
- xmppvcardtemp:好友名片实体类,从数据库里取出来的都是它
- xmppvcardavatarmodule:好友头像
- xmppreconnect:如果失去连接,自动重连
- xmpproom:提供多用户聊天支持
- xmpppubsub:发布订阅
1.2登录操作,也就是连接xmpp服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
- ( void )connect {
if (self.xmppstream == nil) {
self.xmppstream = [[xmppstream alloc] init];
[self.xmppstream adddelegate:self delegatequeue:dispatch_get_main_queue()];
}
if (![self.xmppstream isconnected]) {
nsstring *username = [[nsuserdefaults standarduserdefaults] objectforkey:@ "username" ];
xmppjid *jid = [xmppjid jidwithuser:username domain:@ "lizhen" resource:@ "ework" ];
[self.xmppstream setmyjid:jid];
[self.xmppstream sethostname:@ "10.4.125.113" ];
nserror *error = nil;
if (![self.xmppstream connect:&error]) {
nslog(@ "connect error: %@" , [[error userinfo] description]);
}
}
}
|
connect成功之后会依次调用xmppstreamdelegate的方法,首先调用
1
|
- ( void )xmppstream:(xmppstream *)sender socketdidconnect:(gcdasyncsocket *)socket
|
然后
1
|
- ( void )xmppstreamdidconnect:(xmppstream *)sender
|
在该方法下面需要使用xmppstream 的authenticatewithpassword方法进行密码验证,成功的话会响应delegate的方法,就是下面这个
1
|
- ( void )xmppstreamdidauthenticate:(xmppstream *)sender
|
1.3上线
实现 - (void)xmppstreamdidauthenticate:(xmppstream *)sender 委托方法
1
2
3
4
|
- ( void )xmppstreamdidauthenticate:(xmppstream *)sender {
xmpppresence *presence = [xmpppresence presencewithtype:@ "available" ];
[self.xmppstream sendelement:presence];
}
|
1.4退出并断开连接
1
2
3
4
5
6
|
- ( void )disconnect {
xmpppresence *presence = [xmpppresence presencewithtype:@ "unavailable" ];
[self.xmppstream sendelement:presence];
[self.xmppstream disconnect];
}
|
1.5好友状态
获取好友状态,通过实现
1
2
3
|
- ( void )xmppstream:(xmppstream *)sender didreceivepresence:(xmpppresence *)presence
...
|
方法,当接收到 presence 标签的内容时,xmppframework 框架回调该方法
一个 presence 标签的格式一般如下:
presence 的状态:
- available 上线
- away 离开
- do not disturb 忙碌
- unavailable 下线
1
2
3
4
5
6
7
8
9
10
11
|
- ( void )xmppstream:(xmppstream *)sender didreceivepresence:(xmpppresence *)presence {
nsstring *presencetype = [presence type];
nsstring *presencefromuser = [[presence from] user];
if (![presencefromuser isequaltostring:[[sender myjid] user]]) {
if ([presencetype isequaltostring:@ "available" ]) {
//
} else if ([presencetype isequaltostring:@ "unavailable" ]) {
//
}
}
}
|
2. 接收消息和发送消息
2.1接收消息
当接收到 message 标签的内容时,xmppframework 框架回调该方法
根据 xmpp 协议,消息体的内容存储在标签 body 内
1
2
3
|
- ( void )xmppstream:(xmppstream *)sender didreceivemessage:(xmppmessage *)message {
nsstring *messagebody = [[message elementforname:@ "body" ] stringvalue];
}
|
2.2发送消息
发送消息,我们需要根据 xmpp 协议,将数据放到标签内,例如:
1
2
3
4
5
6
7
8
9
10
|
- ( void )sendmessage:(nsstring *) message touser:(nsstring *) user {
nsxmlelement *body = [nsxmlelement elementwithname:@ "body" ];
[body setstringvalue:message];
nsxmlelement *message = [nsxmlelement elementwithname:@ "message" ];
[message addattributewithname:@ "type" stringvalue:@ "chat" ];
nsstring *to = [nsstring stringwithformat:@ "%@@example.com" , user];
[message addattributewithname:@ "to" stringvalue:to];
[message addchild:body];
[self.xmppstream sendelement:message];
}
|
3. 获取好友信息和删除好友
3.1好友列表和好友名片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[_xmpproster fetchroster]; //获取好友列表
//获取到一个好友节点
- ( void )xmpproster:(xmpproster *)sender didrecieverosteritem:(nsxmlelement *)item
//获取完好友列表
- ( void )xmpprosterdidendpopulating:(xmpproster *)sender
//到服务器上请求联系人名片信息
- ( void )fetchvcardtempforjid:(xmppjid *)jid;
//请求联系人的名片,如果数据库有就不请求,没有就发送名片请求
- ( void )fetchvcardtempforjid:(xmppjid *)jid ignorestorage:( bool )ignorestorage;
//获取联系人的名片,如果数据库有就返回,没有返回空,并到服务器上抓取
- (xmppvcardtemp *)vcardtempforjid:(xmppjid *)jid shouldfetch:( bool )shouldfetch;
//更新自己的名片信息
- ( void )updatemyvcardtemp:(xmppvcardtemp *)vcardtemp;
//获取到一盒联系人的名片信息的回调
- ( void )xmppvcardtempmodule:(xmppvcardtempmodule *)vcardtempmodule
didreceivevcardtemp:(xmppvcardtemp *)vcardtemp
forjid:(xmppjid *)jid
|
3.2添加好友
1
2
3
4
5
6
7
8
9
|
//name为用户账号
- ( void )xmppaddfriendsubscribe:(nsstring *)name
{
//xmpphost 就是服务器名, 主机名
xmppjid *jid = [xmppjid jidwithstring:[nsstring stringwithformat:@ "%@@%@" ,name,xmpphost]];
//[presence addattributewithname:@"subscription" stringvalue:@"好友"];
[xmpproster subscribepresencetouser:jid];
}
|
3.3收到添加好友的请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
- ( void )xmpproster:(xmpproster *)sender didreceivepresencesubscriptionrequest:(xmpppresence *)presence
{
//取得好友状态
nsstring *presencetype = [nsstring stringwithformat:@ "%@" , [presence type]]; //online/offline
//请求的用户
nsstring *presencefromuser =[nsstring stringwithformat:@ "%@" , [[presence from] user]];
nslog(@ "presencetype:%@" ,presencetype);
nslog(@ "presence2:%@ sender2:%@" ,presence,sender);
xmppjid *jid = [xmppjid jidwithstring:presencefromuser];
//接收添加好友请求
[xmpproster acceptpresencesubscriptionrequestfrom:jid andaddtoroster:yes];
}
|
3.4删除好友
1
2
3
4
5
6
7
|
//删除好友,name为好友账号
- ( void )removebuddy:(nsstring *)name
{
xmppjid *jid = [xmppjid jidwithstring:[nsstring stringwithformat:@ "%@@%@" ,name,xmpphost]];
[self xmpproster] removeuser:jid];
}
|
4. 聊天室
初始化聊天室
1
2
3
4
5
6
|
xmppjid *roomjid = [xmppjid jidwithstring:room_jid];
xmpproom = [[xmpproom alloc] initwithroomstorage:self jid:roomjid];
[xmpproom activate:xmppstream];
[xmpproom adddelegate:self delegatequeue:dispatch_get_main_queue()];
|
创建聊天室成功
1
2
3
4
|
- ( void )xmpproomdidcreate:(xmpproom *)sender
{
ddloginfo(@ "%@: %@" , this_file, this_method);
}
|
加入聊天室,使用昵称
1
|
[xmpproom joinroomusingnickname:@ "quack" history:nil];
|
获取聊天室信息
1
2
3
4
5
6
7
|
- ( void )xmpproomdidjoin:(xmpproom *)sender
{
[xmpproom fetchconfigurationform];
[xmpproom fetchbanlist];
[xmpproom fetchmemberslist];
[xmpproom fetchmoderatorslist];
}
|
如果房间存在,会调用委托
1
2
3
4
5
6
|
// 收到禁止名单列表
- ( void )xmpproom:(xmpproom *)sender didfetchbanlist:(nsarray *)items;
// 收到好友名单列表
- ( void )xmpproom:(xmpproom *)sender didfetchmemberslist:(nsarray *)items;
// 收到主持人名单列表
- ( void )xmpproom:(xmpproom *)sender didfetchmoderatorslist:(nsarray *)items;
|
房间不存在,调用委托
1
2
3
|
- ( void )xmpproom:(xmpproom *)sender didnotfetchbanlist:(xmppiq *)iqerror;
- ( void )xmpproom:(xmpproom *)sender didnotfetchmemberslist:(xmppiq *)iqerror;
- ( void )xmpproom:(xmpproom *)sender didnotfetchmoderatorslist:(xmppiq *)iqerror;
|
离开房间
1
|
[xmpproom deactivate:xmppstream];
|
xmpproomdelegate的其他代理方法:
离开聊天室
1
2
3
4
|
- ( void )xmpproomdidleave:(xmpproom *)sender
{
ddlogverbose(@ "%@: %@" , this_file, this_method);
}
|
新人加入群聊
1
2
3
4
|
- ( void )xmpproom:(xmpproom *)sender occupantdidjoin:(xmppjid *)occupantjid
{
ddlogverbose(@ "%@: %@" , this_file, this_method);
}
|
有人退出群聊
1
2
3
4
|
- ( void )xmpproom:(xmpproom *)sender occupantdidleave:(xmppjid *)occupantjid
{
ddlogverbose(@ "%@: %@" , this_file, this_method);
}
|
有人在群里发言
1
2
3
4
|
- ( void )xmpproom:(xmpproom *)sender didreceivemessage:(xmppmessage *)message fromoccupant:(xmppjid *)occupantjid
{
ddlogverbose(@ "%@: %@" , this_file, this_method);
}
|
5. 消息回执
这个是xep-0184协议的内容。协议内容:
发送消息时附加回执请求
代码实现
1
2
3
4
5
6
7
|
nsstring *siid = [xmppstream generateuuid];
//发送消息
xmppmessage *message = [xmppmessage messagewithtype:@ "chat" to:jid elementid:siid];
nsxmlelement *receipt = [nsxmlelement elementwithname:@ "request" xmlns:@ "urn:xmpp:receipts" ];
[message addchild:receipt];
[message addbody:@ "测试" ];
[self.xmppstream sendelement:message];
|
收到回执请求的消息,发送回执
代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
- ( void )xmppstream:(xmppstream *)sender didreceivemessage:(xmppmessage *)message
{
//回执判断
nsxmlelement *request = [message elementforname:@ "request" ];
if (request)
{
if ([request.xmlns isequaltostring:@ "urn:xmpp:receipts" ]) //消息回执
{
//组装消息回执
xmppmessage *msg = [xmppmessage messagewithtype:[message attributestringvalueforname:@ "type" ] to:message.from elementid:[message attributestringvalueforname:@ "id" ]];
nsxmlelement *recieved = [nsxmlelement elementwithname:@ "received" xmlns:@ "urn:xmpp:receipts" ];
[msg addchild:recieved];
//发送回执
[self.xmppstream sendelement:msg];
}
} else
{
nsxmlelement *received = [message elementforname:@ "received" ];
if (received)
{
if ([received.xmlns isequaltostring:@ "urn:xmpp:receipts" ]) //消息回执
{
//发送成功
nslog(@ "message send success!" );
}
}
}
//消息处理
//...
}
|
6. 添加autoping
为了监听服务器是否有效,增加心跳监听。用xep-0199协议,在xmppframework框架下,封装了 xmppautoping 和 xmppping两个类都可以使用,因为xmppautoping已经组合进了xmppping类,所以xmppautoping使用起来更方便。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
//初始化并启动ping
-( void )autopingproxyserver:(nsstring*)strproxyserver
{
_xmppautoping = [[xmppautopingalloc] init];
[_xmppautopingactivate:_xmppstream];
[_xmppautopingadddelegate:selfdelegatequeue: dispatch_get_main_queue()];
_xmppautoping.respondstoqueries = yes;
_xmppautoping.pinginterval=2; //ping 间隔时间
if (nil != strproxyserver)
{
_xmppautoping.targetjid = [xmppjid jidwithstring: strproxyserver ]; //设置ping目标服务器,如果为nil,则监听socketstream当前连接上的那个服务器
}
}
//卸载监听
[_xmppautoping deactivate];
[_xmppautoping removedelegate:self];
_xmppautoping = nil;
//ping xmppautopingdelegate的委托方法:
- ( void )xmppautopingdidsendping:(xmppautoping *)sender
{
nslog(@ "- (void)xmppautopingdidsendping:(xmppautoping *)sender" );
}
- ( void )xmppautopingdidreceivepong:(xmppautoping *)sender
{
nslog(@ "- (void)xmppautopingdidreceivepong:(xmppautoping *)sender" );
}
- ( void )xmppautopingdidtimeout:(xmppautoping *)sender
{
nslog(@ "- (void)xmppautopingdidtimeout:(xmppautoping *)sender" );
}
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。