|
1 | 1 | # XMPP获取好友列表
|
2 | 2 |
|
3 |
| -## 报文格式 |
| 3 | +本篇文章主要是介绍如何获取好友列表, 包括客户端的请求和服务器返回的数据. |
| 4 | +关于XMPP的好友协议, 可以参考[RFC3921](http://wiki.jabbercn.org/RFC3921) |
| 5 | + |
| 6 | +## 获取好友列表报文格式 |
4 | 7 |
|
5 | 8 | ### 发送的报文
|
6 | 9 |
|
@@ -77,6 +80,9 @@ XMPPRoster类继承自XMPPModule,主要用于处理Roster相关的网络请求
|
77 | 80 | //设置xmppStream, 并将 _xmppRoster添加到 _xmppStream 的广播中
|
78 | 81 | [_xmppRoster activate:_xmppStream];
|
79 | 82 |
|
| 83 | + //将 self 添加到广播队列中 |
| 84 | + [_xmppRoster addDelegate:self delegateQueue:_xmppQueue] |
| 85 | + |
80 | 86 | 至此, XMPPRoster 对象初始化完成
|
81 | 87 |
|
82 | 88 | ### XMPPRoster如何自动获取好友列表?
|
@@ -112,7 +118,14 @@ XMPPStream 登录成功后, 会发送 xmppStreamDidAuthenticate 广播, XMPPRost
|
112 | 118 | ...
|
113 | 119 | }
|
114 | 120 |
|
115 |
| -上面的代码, 其实只是构造了如下的一个XML报文发送出去到服务器(注意看这里的xmlns是 jabber:iq:roster): |
| 121 | +上面的代码, 添加了一个element到 xmppIDTracker对象中, 用于处理请求超时以及服务器正常返回数据时的操作, 如下代码: |
| 122 | + |
| 123 | + [xmppIDTracker addElement:iq |
| 124 | + target:self |
| 125 | + selector:@selector(handleFetchRosterQueryIQ:withInfo:) |
| 126 | + timeout:60]; |
| 127 | + |
| 128 | +同时构造了如下的一个XML报文发送出去到服务器(注意看这里的xmlns是 jabber:iq:roster): |
116 | 129 |
|
117 | 130 | <iq id="5nKV7-6" type="get"><query xmlns="jabber:iq:roster"></query></iq>
|
118 | 131 |
|
@@ -152,8 +165,88 @@ XMPPRoster解析报文(从服务器返回的报文能看出来,服务器返回
|
152 | 165 | return NO;
|
153 | 166 | }
|
154 | 167 |
|
155 |
| -从服务器返回的报文来看, XMPPRoster应该会走如下方法: |
| 168 | +服务器返回roster列表时, 执行了 [xmppIDTracker invokeForElement:iq withObject:iq]; 方法, 根据上一节XMPPIDTracker的介绍, 该方法会调用 handleFetchRosterQueryIQ:withInfo: 方法, 如下: |
156 | 169 |
|
157 |
| - [xmppIDTracker invokeForElement:iq withObject:iq]; |
| 170 | + - (void)handleFetchRosterQueryIQ:(XMPPIQ *)iq withInfo:(XMPPBasicTrackingInfo *)basicTrackingInfo{ |
| 171 | + |
| 172 | + dispatch_block_t block = ^{ @autoreleasepool { |
| 173 | + |
| 174 | + NSXMLElement *query = [iq elementForName:@"query" xmlns:@"jabber:iq:roster"]; |
| 175 | + |
| 176 | + BOOL hasRoster = [self hasRoster]; |
| 177 | + |
| 178 | + //如果之前未获取过好友列表, 则发送的广播 |
| 179 | + if (!hasRoster) |
| 180 | + { |
| 181 | + [xmppRosterStorage clearAllUsersAndResourcesForXMPPStream:xmppStream]; |
| 182 | + [self _setPopulatingRoster:YES]; |
| 183 | + |
| 184 | + //发送一个 xmppRosterDidBeginPopulating 广播 |
| 185 | + [multicastDelegate xmppRosterDidBeginPopulating:self]; |
| 186 | + [xmppRosterStorage beginRosterPopulationForXMPPStream:xmppStream]; |
| 187 | + } |
| 188 | + |
| 189 | + NSArray *items = [query elementsForName:@"item"]; |
| 190 | + [self _addRosterItems:items]; |
| 191 | + |
| 192 | + if (!hasRoster) |
| 193 | + { |
| 194 | + // We should have our roster now |
| 195 | + |
| 196 | + [self _setHasRoster:YES]; |
| 197 | + [self _setPopulatingRoster:NO]; |
| 198 | + [multicastDelegate xmppRosterDidEndPopulating:self]; |
| 199 | + [xmppRosterStorage endRosterPopulationForXMPPStream:xmppStream]; |
| 200 | + |
| 201 | + // Process any premature presence elements we received. |
| 202 | + |
| 203 | + for (XMPPPresence *presence in earlyPresenceElements) |
| 204 | + { |
| 205 | + [self xmppStream:xmppStream didReceivePresence:presence]; |
| 206 | + } |
| 207 | + |
| 208 | + [earlyPresenceElements removeAllObjects]; |
| 209 | + } |
| 210 | + |
| 211 | + }}; |
| 212 | + |
| 213 | + if (dispatch_get_specific(moduleQueueTag)) |
| 214 | + block(); |
| 215 | + else |
| 216 | + dispatch_async(moduleQueue, block); |
| 217 | + |
| 218 | + } |
| 219 | + |
| 220 | +### 监听Roster获取完成时的回调 |
| 221 | + |
| 222 | +/** |
| 223 | + * Sent when the initial roster is received.<br/> |
| 224 | + * 当roster开始往 storage(coreData 或者 memory) 添加数据时的回调 |
| 225 | +**/ |
| 226 | + |
| 227 | + - (void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender; |
| 228 | + |
| 229 | +/** |
| 230 | + * Sent when the initial roster has been populated into storage.<br/> |
| 231 | + * 当roster往 storage(coreData 或者 memory) 添加数据完成后的回调 |
| 232 | +**/ |
| 233 | + |
| 234 | + - (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender; |
| 235 | + |
| 236 | +/** |
| 237 | + * Sent when the roster receives a roster item.<br/> |
| 238 | + * 在 发送 xmppRosterDidBeginPopulating 广播后, 会陆续收到didReceiveRosterItem 的回调<br/> |
| 239 | + * 在 发送 xmppRosterDidEndPopulating 广播后, 表示roster列表遍历完成 |
| 240 | +**/ |
| 241 | + |
| 242 | + - (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(NSXMLElement *)item; |
| 243 | + |
| 244 | +监听以上三个方法, 可以完成基本的好友获取操作, 使用 XMPPRosterMemoryStorage 类的回调则可以监听到更多的回调, 可以自己参照代码进行查看. |
| 245 | +好友列表完成时的回调方法如下: |
| 246 | + |
| 247 | + - (void)xmppRosterDidPopulate:(XMPPRosterMemoryStorage *)sender{ |
| 248 | + //通过 sortedUsersByName 方法可以从 memory对象中获取roster列表 |
| 249 | + NSArray *roster = [sender sortedUsersByName]; |
| 250 | + } |
158 | 251 |
|
159 |
| -### |
| 252 | +**其它回调方法, 比如: 删除好友、添加好友、接收到好友请求等操作,将会慢慢道来** |
0 commit comments