废话:最近一段时间由于项目需要研究了一下xmpp框架,个人认为如果想使用xmpp框架,他的相关扩展协议是你必须要搞清楚的。例如本片文章要讲的搜索协议,我们知道框架扩展里面是没有原生搜索扩展的,而且网上也很难搜到现成的比较好用的扩展封装类。这样你想要实现这些功能你就要清楚的理解扩展协议,其实学懂了一个协议,你会发现xmpp所有模块的协议,理解起来都差不多,也就是说一通则全通。
主题:搜索协议即 http://xmpp.org/extensions/xep-0055.html ,这里我就不摘抄大量的内容了(最讨厌写博客到处copy),自己去看看吧。
功能:这里所说的搜索协议主要是对服务器用户进行搜索,比如qq,要想加某一个用户为好友,需要先查找这个用户,然后搜出用户的信息,然后添加好友。这个查找功能就是用搜索协议实现的。(当然qq肯定不会用xmpp)
说了这么多,下面看是在代码中实现这个搜索功能。
首先查看一下你的openfire 服务器是否已经安装search插件:
如下图红色标记位置:
服务器端已经提供了用户搜索功能,我们看一下服务器端的搜索功能是怎样的:
如下图:
看了服务器的搜素功能,已经很清楚,我们在客服端实现的搜索功能也是用到search插件实现的,所以也是这样的参数和结果。
客户端代码实现:
看过前面的协议,我们知道客户端与服务器端的交互是通过xml数据流交互的。那么我们首先要知道搜索请求的数据流,根据几个参数和搜索协议不难写出如下搜索请求:
<?xml version="1.0"?>
<iq id="search2" to="sh.m.tie1tie.com" type="set">
<query xmlns="jabber:iq:search">
<x type="submit" xmlns="jabber:x:data">
<field type="hidden" var="FORM_TYPE">
<value>jabber:iq:search</value>
</field>
<field type="text-single" var="search">
<value><span style="color:#ff6666;">774</span></value>
</field>
<field type="boolean" var="Username">
<value>1</value>
</field>
<field type="boolean" var="Name">
<value>1</value>
</field>
<field type="boolean" var="Email">
<value>1</value>
</field>
</x>
</query>
</iq>
id = "search2"这个是搜索info,search1 是搜索fields;
to =“sh.m.tie1tie.com”这个是搜索服务器的名称,admin控制台 - 服务器 - 服务器设置 - search service propertis下面查看搜索的服务名称;
红色字体是搜索的关键字,可以是username,name,email。
在代码中封装这个数据流,即搜索方法的实现:
- (void)searchUserInfo:(NSString *)searchValue
{
NSXMLElement *iq = [NSXMLElement elementWithName:@"iq"];
[iq addAttributeWithName:@"type" stringValue:@"set"];
XMPPJID *myJID = self.xmppStream.myJID;
[iq addAttributeWithName:@"from" stringValue:myJID.description];
[iq addAttributeWithName:@"to" stringValue:@"sh.m.tie1tie.com"];
[iq addAttributeWithName:@"id" stringValue:@"search2"];
NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:search"];
NSXMLElement *x = [NSXMLElement elementWithName:@"x" xmlns:@"jabber:x:data"];
[x addAttributeWithName:@"type" stringValue:@"submit"];
NSXMLElement *field1 = [NSXMLElement elementWithName:@"field"];
[field1 addAttributeWithName:@"type" stringValue:@"hidden"];
[field1 addAttributeWithName:@"var" stringValue:@"FROM_TYPE"];
NSXMLElement *value1 = [NSXMLElement elementWithName:@"value" stringValue:@"jabber:iq:search"];
[field1 addChild:value1];
NSXMLElement *field2 = [NSXMLElement elementWithName:@"field"];
[field2 addAttributeWithName:@"type" stringValue:@"text-single"];
[field2 addAttributeWithName:@"var" stringValue:@"search"];
NSXMLElement *value2 = [NSXMLElement elementWithName:@"value" stringValue:searchValue];
[field2 addChild:value2];
NSXMLElement *field3 = [NSXMLElement elementWithName:@"field"];
[field3 addAttributeWithName:@"type" stringValue:@"boolean"];
[field3 addAttributeWithName:@"var" stringValue:@"Username"];
NSXMLElement *value3 = [NSXMLElement elementWithName:@"value" stringValue:@"1"];
[field3 addChild:value3];
NSXMLElement *field4 = [NSXMLElement elementWithName:@"field"];
[field4 addAttributeWithName:@"type" stringValue:@"boolean"];
[field4 addAttributeWithName:@"var" stringValue:@"Name"];
NSXMLElement *value4 = [NSXMLElement elementWithName:@"value" stringValue:@"1"];
[field4 addChild:value4];
NSXMLElement *field5 = [NSXMLElement elementWithName:@"field"];
[field5 addAttributeWithName:@"type" stringValue:@"boolean"];
[field5 addAttributeWithName:@"var" stringValue:@"Email"];
NSXMLElement *value5 = [NSXMLElement elementWithName:@"value" stringValue:@"1"];
[field5 addChild:value5];
[x addChild:field1];
[x addChild:field2];
[x addChild:field3];
[x addChild:field4];
[x addChild:field5];
[query addChild:x];
[iq addChild:query];
[self.xmppStream sendElement:iq];
}
如此便完成了向服务器搜索用户信息的功能,然后们在代理里面解析返回的result(也是xml数据流)就可以得到结果了。
补充说明:
上面我们讲了如何请求info,接下来我们看一下结果处理:
<?xml version="1.0"?>
<iq xmlns="jabber:client" type="result" id="search1" from="sh.m.tie1tie.com" to="000000000326@m.tie1tie.com/spark”>
<query xmlns="jabber:iq:search”>
<span style="white-space:pre"> </span><instructions>The following fields are available for searching. Wildcard (*) characters are allowed as part of the query.</instructions>
<span style="white-space:pre"> </span><first />
<span style="white-space:pre"> </span><last />
<span style="white-space:pre"> </span><nick />
<span style="white-space:pre"> </span><email />
<span style="white-space:pre"> </span><x xmlns="jabber:x:data" type="hidden">
<span style="white-space:pre"> </span> <value>jabber:iq:search</value>
<span style="white-space:pre"> </span> <field var="search" type="text-single" label="Search">
<required />
<span style="white-space:pre"> </span> </field>
<field var="Username" type="boolean" label="Username">
<span style="white-space:pre"> </span><value>1</value>
</field>
<field var="Name" type="boolean" label="Name">
<span style="white-space:pre"> </span><value>1</value>
</field>
<field var="Email" type="boolean" label="Email">
<span style="white-space:pre"> </span><value>1</value>
</field>
<span style="white-space:pre"> </span> </x>
</query>
</iq>
这个iq是在
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
代理方法中获取的iq结果,我们从中获取我们需要的信息。
//返回用户信息查询结果
if ([@"result" isEqualToString:iq.type] && [[iq attributeStringValueForName:@"id"] isEqualToString:@"search2"]) {
NSString *name;
XMPPJID *jid;
NSXMLElement *query = iq.childElement;
if ([@"query" isEqualToString:query.name]) {
NSXMLElement *x = [self childElement:query];
NSArray *elements = [x children];
for (NSXMLElement *item in elements) {
if ([item.name isEqualToString:@"item"]) {
NSArray *fields = [item children];
for (NSXMLElement *field in fields) {
if ([[field attributeStringValueForName:@"var"] isEqualToString:@"Name"]) {
name = [[[field elementsForName:@"value"] firstObject] stringValue];
}
if ([[field attributeStringValueForName:@"var"] isEqualToString:@"jid"]) {
NSString *jidStr = [[[field elementsForName:@"value"] firstObject] stringValue];
jid = [XMPPJID jidWithString:jidStr];
}
}
}
}
}
[self handlePresence:jid name:name];
}
这样我们就完成了结果处理。
PS:所有的功能都可以这样实现!