using XMPP for user location
I want to create an application for Android that enables me to get the geolocation of a user. This has to be made as a client-server app and for the server side I'm using OpenFire. For getting the user's location I would have to use XEP-0080, right? And SmackAPI also? I'm completely new to XMPP and Smack, so if anyone could get me a few pointe开发者_运维问答rs or maybe examples or any kind of documentation about this I'd be very grateful.
Thanks in advance for any help.
An Android project I’m currently working on required periodically publishing a user’s location to their XMPP roster friends using aSmack & XEP-0080.
It turned out trickier than I would have liked so I documented my solution here: http://www.dbotha.com/2014/11/02/xep-0080-user-location-on-android-using-pep-with-smack/
For completeness I'll cover the important parts here. In the interest of brevity the only XML child elements from the XEP-0080 specification that I’ll cover are those relating to latitude and longitude.
A PEPItem to hold the user location and transform it into the appropriate XML:
public class UserLocation extends PEPItem {
public static final String NODE =
"http://jabber.org/protocol/geoloc";
public final double latitude, longitude;
public UserLocation(double latitude, double longitude) {
this(StringUtils.randomString(16), latitude, longitude);
}
public UserLocation(double latitude, double longitude,
String id) {
super(id);
this.latitude = latitude;
this.longitude = longitude;
}
@Override
java.lang.String getNode() {
return NODE;
}
// return an XML element approximately inline
// with the XEP-0080 spec
@Override
java.lang.String getItemDetailsXML() {
return String.format(
"<geoloc xmlns='%s'><lat>%f</lat>" +
"<lon>%f</lon></geoloc>",
NODE, latitude, longitude);
}
}
A mostly boilerplate PEPEvent to hold the UserLocation PEPItem:
public class UserLocationEvent extends PEPEvent {
private final UserLocation location;
public UserLocationEvent(UserLocation location) {
this.location = location;
}
public UserLocation getLocation() {
return location;
}
@Override
public String getNamespace() {
return "http://jabber.org/protocol/pubsub#event";
}
@Override
public String toXML() {
return String.format("<event xmlns=" +
"'http://jabber.org/protocol/pubsub#event' >" +
"<items node='%s' >%s</items></event>",
UserLocation.NODE, location.toXML());
}
}
A custom PacketExtensionProvider to parse out the UserLocationEvent's from incoming packets where present.
public class UserLocationProvider
implements PacketExtensionProvider {
// This method will get called whenever aSmack discovers a
// packet extension containing a publish element with the
// attribute node='http://jabber.org/protocol/geoloc'
@Override
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception {
boolean stop = false;
String id = null;
double latitude = 0;
double longitude = 0;
String openTag = null;
while (!stop) {
int eventType = parser.next();
switch (eventType) {
case XmlPullParser.START_TAG:
openTag = parser.getName();
if ("item".equals(openTag)) {
id = parser.getAttributeValue("", "id");
}
break;
case XmlPullParser.TEXT:
if ("lat".equals(openTag)) {
try {
latitude = Double.parseDouble(
parser.getText());
} catch (NumberFormatException ex) {
/* ignore */
}
} else if ("lon".equals(openTag)) {
try {
longitude = Double.parseDouble(
parser.getText());
} catch (NumberFormatException ex) {
/* ignore */
}
}
break;
case XmlPullParser.END_TAG:
// Stop parsing when we hit </item>
stop = "item".equals(parser.getName());
openTag = null;
break;
}
}
return new UserLocationEvent(
new UserLocation(id, latitude, longitude));
}
}
Now tying it all together:
XMPPTCPConnection connection = new XMPPTCPConnection();
ServiceDiscoveryManager sdm = ServiceDiscoveryManager
.getInstanceFor(connection);
sdm.addFeature("http://jabber.org/protocol/geoloc");
sdm.addFeature("http://jabber.org/protocol/geoloc+notify");
EntityCapsManager capsManager = EntityCapsManager
.getInstanceFor(connection);
capsManager.enableEntityCaps();
PEPProvider pepProvider = new PEPProvider();
pepProvider.registerPEPParserExtension(
"http://jabber.org/protocol/geoloc",
new UserLocationProvider());
ProviderManager.addExtensionProvider("event",
"http://jabber.org/protocol/pubsub#event", pepProvider);
PEPManager pepManager = new PEPManager(connection);
pepManager.addPEPListener(PEP_LISTENER);
connection.connect();
connection.login(username, password);
And finally a listener for incoming LocationEvent's:
PEPListener PEP_LISTENER = new PEPListener() {
@Override
public void eventReceived(String from, PEPEvent event) {
if (event instanceof UserLocationEvent) {
// do something interesting
}
}
};
I believe this is close to what you are trying to accomplish.
XEP-0080 User Location in Smack Library
精彩评论