to the XMPPFramework. I believe the changes will be great benefit to anyone using the framework, especially those developing extensions (either standard XEP's or custom extensions). However due to several public facing API changes, this framework will require a bit of refactoring to those currently using the framework in their application.
Now, I know you must be thinking, "Mr. Hanson you're insane!" But I assure you everything will be OK. In the end, you'll have a better and more extensible xmpp framework. And it will ship with more included extensions.
As the xmpp framework has matured, it has become clear that the XMPPClient was half-baked and has fractured 3rd party development. The truth of the matter is that XMPPClient was originally designed to be a simple example of how one might use the underlying XMPPStream. But then we added some basic roster management and other little things like automatic reconnect. People saw this and assumed that XMPPClient was what they had to use, but ended up finding it rather brittle.
Take a look at what XMPPClient does:
1. Provides basic roster functionality (poorly)
2. Inflexible security options
3. General XMPPStream wrapper
To go into more detail:
1. The XMPPClient provided a roster by storing the information in memory, accessed via a hashtable. Furthermore it was a closed solution which didn't allow developers to add custom information or properties to a user or resource. Almost anybody who used the xmpp framework ended up finding this solution to be brittle. And what about core data? If you're working with the framework on the iPhone or any environment where there are a lot of users, core data is a much better solution. Plus harnessing core data allows one to easily implment things like roster animation when users sign online/offline. There really needs to be a general purpose XMPPRoster class that abstracts the storage mechanism, which would allow you to choose the proper storage, or even write your own.
2. The security options (such as allowSelfSignedCertificates or allowSSLHostNameMismatch) don't go far enough. On multiple occasions I've been forced to tell developers to manually edit the XMPPStream class in order to allow them to connect to their development server. What we really need is a delegate callback that allows the developers to supply all the various available security options to the stream. This way they have the full potential of the underlying security options via Apple's CFStream.
3. Besides the roster stuff, the entire XMPPClient is just a dumb wrapper around XMPPStream. As in, you invoke a method on XMPPClient, and it literally just turns around and invokes the same method on its underlying XMPPStream. There's really not a lot of point to this.
The other major problem is that extension developers didn't know which class to tie into. Do they tie into XMPPClient or XMPPStream? I've had many developers tell me that they didn't use XMPPClient, and that all their custom extensions tied directly into an altered XMPPStream. Due to this, I was unable to add their extensions to the repository.
So what I've decided to do is merge the good parts of XMPPClient into XMPPStream.For example, XMPPClient had a way to directly set the JID of the user. This was simple, and useful because XMPPStream wanted the various parts of the JID separately. So now the XMPPStream has a myJID property that can be set.
And so I've done a huge refactoring of the XMPP Framework
*T
here is a new XMPPRoster class*
It provides the basic methods for a roster, and has a
storage abstraction (XMPPRosterStorage protocol). I've provided 2 sample implementations:
- XMPPRosterMemoryStorage which uses the old hashtable technique
- XMPPRosterCoreDataStorage which provides a sample core data storage implementation
You are free to customize either of these, or implement your own from scratch. The idea is that the XMPPRoster class handles the basics like requesting the roster and queueing presence elements. It also has basic methods for adding buddies, and accepting/rejecting buddy requests. But it relies on an XMPPRosterStorage implementation for the actual storage, and it provides a really simple straight-forward API for storage classes to implement. Implement this API and you have complete control over how/where you store your roster and what kind of data you store concerning it.
*
There is a new XMPPReconnect class*
Previously if you wanted automatic reconnect, you had to use XMPPClient. All of the implementation and more has been moved into its own class. If you want to use it, simply plug it into the XMPPStream. Furthermore, it has new methods for general network monitoring. For example, say the user tries to connect to the xmpp server for the first time but isn't connected to the Internet. Since they've never connected, automatic reconnect doesn't apply. The XMPPReconnect class allows you to manually start monitoring the network for changes. This way you could listen for an Internet connection, and automatically connect when one appears.
*
New security delegate methods in XMPPStream*
Options like allowSelfSignedCertificates and allowSSLHostNameMismatch do not cut it. This becomes apparent as soon as one tried to connect to a google server. In fact there has been an outstanding ticket about this for quite some time.
Here's the problem:
For a normal google talk session you connect to "
talk.google.com" with a JID like "
us...@gmail.com". According to the RFC, the xmpp server's certificate is supposed to have the name "
talk.google.com". But google's certificate name is "
gmail.com". In addition to this, if you use google apps for your domain then you connect to their server at "
talk.google.com" with a JID like "
us...@yourDomain.com". In this case, the certificate's name is "
talk.google.com".
Now the allowSSLHostNameMismatch option would kinda help, but wasn't exactly the perfect option. What was really needed was the ability to directly specify what name is expected to be on the certificate.
The new xmppStream:willSecureWithSettings: allows you to specify this directly. In addition, you can specify a whole bunch of other security settings that were previously not exposed.
*
New delegate hooks in XMPPStream for extension development*
A solid example will really help highlight how much this will help.
XEP-0115 specifies a way for clients to broadcast their capabilities and discover the capabilities of other users. (For example, support for audio, video, file transfer, message receipts, etc.) This ties into the presence element. So when the client sends its presence element, it includes this information. And when it receives a presence element, it processes the capabilities information in the element.
The problem was, every part of the application that wanted to send a presence element would have to be sure to include the capabilities information. This makes it very difficult to simply plug in xmpp extensions to an existing application.
But not anymore. There are now hooks that extension classes can use:
- (void)xmppStream:(XMPPStream *)sender willSendIQ:(XMPPIQ *)iq;
- (void)xmppStream:(XMPPStream *)sender willSendMessage:(XMPPMessage *)message;
- (void)xmppStream:(XMPPStream *)sender willSendPresence:(XMPPPresence *)presence;
Using these hooks, a XEP-0115 extension would just listen for outgoing presence elements, and could automatically add the capabilities information as needed!
*
New XMPPCapabilities extension class*
Yup, an implementation of XEP-0115. It also contains a
storage abstraction (XMPPCapabilitiesStorage protocol) so you can choose to cache the capabilities information in any way you want.
I understand that these are really big changes, and will require a bit of refactoring on your part within your application. In order to help understand the impact, and understand the changes needed, I've updated all the sample applications included in the repository.
The desktop project (XMPPStream) demonstrates using XMPPRosterMemoryStorage (just like the old XMPPClient), and also makes use of the XMPPReconnect functionality (again just like the old XMPPClient). It also demonstrates the new security delegate methods to specify the expected X509 certificate domain if connecting to Google Talk.
The iphone project (iPhoneXMPP) demonstrated using XMPPRosterCoreDataStorage to store the roster in core data!
Let me know your thoughts, and if you have any questions.