A project I’m currently working on requires periodically publishing a user’s location to their XMPP roster friends on Android.
My initial feeling given the relative simplicity of the problem and readily available XEP-0080: User Location specification was that I’d have something up and running in a matter of hours. How wrong I was. I ended up spending several days in a state of perpetual frustration just trying to get PEP to play nicely with aSmack.
Given the lack of documented Android examples surrounding PEP and aSmack at the time of writing, arriving upon solution was more luck than anything. Frustratingly it came down to some careful (and not entirely intuitive) ordering of a few key statements.
So that others might not have to go through the same trouble I thought I’d document my approach now that I have something working.
I made the decision to loosely follow the XEP-0080 specification as I’m relatively new to XMPP and figured it would lead me down a “best practice” path. It also seemed to cover my requirements nicely:
This specification defines an XMPP protocol extension for communicating information about the current geographical or physical location of an entity.
As aSmack does not support XEP-0080 out the box we’ll need to write:
- A custom
PacketExtension) to hold the user location data
- A custom
PEPEventto store the
- A custom
PacketExtensionProviderto parse the custom user location
PEPEvent’s from incoming packets
- Some boilerplate to tie the above together
- A function to publish a user’s location to the XMPP server
In the interest of brevity the only XML child elements from the specification that I’ll cover in this post are those relating to latitude and longitude. Adding support for the remainder of the specification should be a trivial exercise once we’ve got the foundations in place.
We’re going to be making use of the Smack provider architecture to handle parsing parsing of our custom user location packet extensions. I’ll assume that you’re familiar with this architecture and won’t be covering it any any detail.
A PEPItem to store user location
A PEPEvent to hold the PEPItem
A PacketExtensionProvider to parse incoming friend locations
Whenever a friend on our roster publishes their location it will find it’s way to us nested as an extension deep within an XMPP packet.
Out of the box aSmack will not know what to do with our custom extension that it finds within these packets and will effectively ignore it.
To have them parsed and reported back in a sensible form we need to create and register a custom
Tying it all together
And now for the magic that eluded me for so long… and as I found out the hard way – the ordering of the code snippets in this section is crucial.
In the above code we create a connection and indicate to the
ServiceDiscoveryManager that we support XEP-0080.
+notify suffix indicates our additional interest in receiving notifications related to this protocol too, rather than just publishing them.
Reporting of entity capabilities is also enabled. This means publishing and subscribing XEP-0080 capabilities will be reported within presence updates sent by the Android client.
In the code snippet below we register our custom
UserLocationProvider with the
ProviderManager as per the
Smack provider architecture.
aSmack will now know what to do when it finds a user location extension nested within an XMPP packet i.e. a
UserLocationEvent will ultimately get parsed out of the packet which will then find its way to the
finally reported to our own listener.
And after all that setup we provide a listener to be notified when a friend publishes a
Publishing a users location with PEP
Finally publishing a user’s location is pretty straightforward in comparison to receiving them and can be accomplished as follows