Building a Jabber Client for iOS: XMPP Setup

Welcome to the third installment of our series on building a Jabber client with the iOS SDK. In this tutorial, we will add XMPP functionalities to the Application Delegate. Placing the functionality in the App Delegate will enable us to access XMPP functionalities from anywhere in the application easily.

Integrating XMPP in the AppDelegate

As mentioned, inserting the XMPP functionality in the App Delegate is a great way to make the functionality easily available throughout the app. At any place in your application code, you can access the App Delegate with the following code snippet:

The XMPP class will dispatch events by means of protocols which we will define below. This is the list of events handled by this class:

  • The client connected with the server
  • The client authenticated with the server
  • The client received a notification of presence (e.g. a user logged in)
  • The client received a message

Let's get started by adding the some property to the application delegate. First we need to import some XMPP stuff in the header:

This is the minimal set of classes needed to build our application. If you want to digg into something more complex you can checkout the example bundled with the XMPP library repository. Here is our first implementation of this class:

XMPPStream will be the barebone of our client-server communication system and all messages will be exchanged through it. We will also define the methods to manage connection and disconnection. The implementation of this class is pretty complex, so we will break it down into many steps. First, we need a few more accessory methods to handle client-server communications. These can be private, so we place them in the implementation of the class:

Here, the most important is setupStream, which creates the channel to manage the exchange of messages.

Just two lines of code, but behind that many things happen. The dispatch_get_main_queue() is a function which returns a reference
to the system level asynchronous execution mechanism, to which we can sumbit tasks and receive notifications. Here we "simply" tell
that our class is the delegate for the notifications sent from the main queue, which is run in the main thread of our application. See here for more details about Grand Central Dispatch.

Offline and Online functions are able to notify other users when we are connected or not. They are defined by sending an XMPPPresence object through the socket. The server will dispatch the notification accordingly.

The connect method is the most important, for it manages the login operation. It returns a boolean representing whether the connection was successful or not. At first it sets up the stream, then it uses data stored in NSUserDefaults to decorate the stream and call a connect message. An alert view is displayed if the connection is not successful.

For sake of completeness, we also implement the disconnect method which is defined as follows:

Now that we have some of the basic functions we can use them in specific cases, for example, when the application becomes active or inactive.

We are left with the core of the system, the notifications of events and related behaviors, which we implement by means of protocols.

Defining Protocols

We will define two protocols, one for chat notifications like "a buddy went offline", and one for dispatching messages received. The first protocol includes the description of three events:

The first two messages are related to the presences of a buddy. We will react to these by adding or removing elements to the online buddies table. The third just notifies the server when our client disconnects. The second protocol is simpler, for it manages just the event of message reception.

For the sake of simplicity, to represent the message we will use a dictionary with two keys, @"msg" and @"sender", to represent the actual message and the actual sender.

Implementing Protocols

Both protocols dispatch messages from the UIApplicationDelegate. So we extend our main class by adding two properties (one for each delegate).

In the implementation we should remember to synthesize these properties.

Now our main class is ready to dispatch events to delegates. But which events? Those received from the Grand Central Dispatch. If you remember,
we have setup our UIApplicationDelegate as a delegate for stream messages. Such delegates have the following signatures. The names
are pretty self explanatory, but we added comments within to make it even clearer.

Let's start by authentication when we connect to the server.

When authentication is successful, we should notify the server that we are online.

When we receive a presence notification, we can dispatch the message to the chat delegate.

The delegate will use these events to populate the online buddies table accordingly (see below). Finally, we are left with the message received notification.

In this case, we build a dictionary as requested by the protocol and we call the corresponding method. At this point the core of our system is ready. We just have to make the user interface components react accordingly.

Hooking Up Views and Controllers

We start by modifying the buddy list controller, which manages the first view displayed when the app is started. We add the chat delegate to the interface as follows:

We add a few access methods to point to the application delegate and stream:

We also have to extend the viewDidLoad message to set our view controller as a delegate for the chat protocol.

When the view appears, if credentials have been entered already, we call the connect method of the application delegate:

Finally, we have to add or remove objects from the array of online buddies according to the events dispatched by the application delegate.

If you run the application now and a buddy comes online, the table view gets populated with his username as in the following figure:

Online buddies in the list view.

Important Note: Depending on the server settings, you might need to wait for some time in order to receive the "new buddy is online" notifications. This time tends to be from 20 to 60 seconds.

To start a chat with the user we have to show the chat view when the corresponding cell is tapped.

To finalize the application we need to add the implementation of the message delegate to the chat view controller. The steps to do so are similar to those applied to the buddy list controller. We add the delegate in the interface file:

We add accessors to the implementation:

We add the implementation of initWithUser:username:

We extend the viewDidLoad to declare the message delegate and we also set the text field as a first responder to keyboard input:

To send a message, we need to create an xml element as required by the XMPP protocol and send it over the stream. Here is how we update the sendMessage method:

We are now done! You can test the final implementation of our iOS client. We start the server, iChat and our jabber client. After awhile, both clients should receive a presence notification and recognize each other as online. On the iPhone we tap on the online buddy and the chat view shows up. Now we are ready to chat. Here is a screenshot of the final application at work.

Final version at work

Source Code

The complete source code for this project can be found on GitHub here.

Tags:

Comments

Related Articles