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" ); } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。