1. Code
  2. Mobile Development
  3. iOS Development

Building a Jabber Client for iOS: Interface Setup

Scroll to top
This post is part of a series called Building a Jabber Client for iOS.
Building a Jabber Client for iOS: Server Setup
Building a Jabber Client for iOS: XMPP Setup

In this tutorial we will build a Jabber Client for iOS. The application developed in this series will enable users to sign in, add buddies, and send messages. This tutorial will focus on setting up the user interface for the sample chat client.

Overview of the iOS Client

The core of our Jabber application is built around the XMPP capabilities. We will store these functionalities in the main application delegate, which will implement a custom protocol to dispatch events like logging in and sending messages. The application we are going to build is based around three views: login, buddy list, and chat.

iOS Client ViewsiOS Client ViewsiOS Client Views

The buddy list is the default view, which is shown when the application starts up. It shows the list of online buddies. The login view will appear only if there are no credentials previously stored on the device. A button named "Account" will show the login view from the buddy list, to enable changing login credentials when needed. The chat view is displayed when an online buddy is tapped, to initiate a chat. We will build a view controller for each of these views. Controllers will implement a simple protocol to receive notifications dispatched by the application delegate. To keep things simple, login and a chat view will appear as a modal view controller. If you like, you can rework the application to use a navigation controller instead.

Project Setup

Let's open Xcode and start a new project. We will choose a simple view based application and we will name it "JabberClient". To interact with the server, we will adopt a handy library for iOS which is called XMPP framework. This library is compatible with both Mac and iOS applications and will help us in implementing the low-level functionalities to connect with XMPP server and manage message exchanges through sockets. Since the repository does not feature any download link you need to have git installed (see here for more information). Once you have installed git, you can issue the following command in the console:

git clone https://code.google.com/p/xmppframework/ xmppframework

Once the download has completed we should end up with a folder like the following:

XMPP Framework FoldersXMPP Framework FoldersXMPP Framework Folders

We need only the folders highlighted in the picture. Once selected, we drag them over the project to include them. Just remember to check "Copy items into destination group's folder (if needed)".

Importing XMPP FrameworkImporting XMPP FrameworkImporting XMPP Framework

We don't need the integration with Facebook, so in the "Extensions" group we can delete the "X-FACEBOOK-PLATFORM" folder.

Deleting Facebook Part

Now let's add the frameworks needed. We select the project in the navigator, then we select the target and we open "Link Binary With Libraries" as shown in the figure.

Adding Frameworks for ProejctAdding Frameworks for ProejctAdding Frameworks for Proejct

We have to add lots of framework as shown in the following figure:

List of Frameworks needed for the ProjectList of Frameworks needed for the ProjectList of Frameworks needed for the Project

Finally, to compile a project we have to tweak some build settings. Changes have to be added to both the project and the target. First, we find the "User Header Search Paths" and we specify the library needed to parse xml: '/usr/include/libxml2'

Including xml2 libraryIncluding xml2 libraryIncluding xml2 library

Then we select "Other Linker Flags" and the add the following flag: "-lxml2".

Including xml2 libraryIncluding xml2 libraryIncluding xml2 library

The project is now set up correctly and you should be able to build it without errors or warnings.

Creating the Buddy List View

The buddy list contains a table view which shows a list of online contacts. When one is tapped it shows the corresponding chat view. The project wizard has already created a view controller, which we will rename "BuddyListViewController" for sake of consistency. This controller will have a UITableView and an array to store online contacts. It will also have an IBAction to show the login view, in case the user wants to switch account. Moreover it will implement table view delegates. So we update the implementation file as follows.

1
2
@interface JabberClientViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
3
4
	UITableView *tView;
5
	NSMutableArray *onlineBuddies;
6
7
}
8
9
@property (nonatomic,retain) IBOutlet UITableView *tView;
10
11
- (IBAction) showLogin;
12
13
@end

In the implementation file we syntesize the property and we add the standard methods to manage
the table view.

1
2
@implementation JabberClientViewController
3
4
@synthesize tView;
5
6
- (void)viewDidLoad {
7
8
        [super viewDidLoad];
9
	self.tView.delegate = self;
10
	self.tView.dataSource = self;
11
	onlineBuddies = [[NSMutableArray alloc ] init];
12
13
}
14
15
- (void) showLogin {
16
17
	// show login view

18
19
}
20
21
#pragma mark -

22
#pragma mark Table view delegates

23
24
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
25
26
		NSString *s = (NSString *) [onlineBuddies objectAtIndex:indexPath.row];
27
		static NSString *CellIdentifier = @"UserCellIdentifier";
28
		UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
29
30
		if (cell == nil) {
31
			cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
32
		}
33
34
		cell.textLabel.text = s;
35
		cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
36
37
		return cell;
38
39
}
40
41
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
42
43
	return [onlineBuddies count];
44
45
}
46
47
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
48
49
	return 1;
50
51
}
52
53
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
54
55
	// start a chat

56
57
}
58
59
@end

The corresponding xib file will have a table view, and a toolbar with a bar button item as in the following figure:

Designing the Buddy ListDesigning the Buddy ListDesigning the Buddy List

We should remember to link the table view and the showLogin action to their corresponding outlets as shown below:

Buddy List outlets

If we run the application we should see an empty table as in the following screenshot:

The Buddy List at runtime

We can suspend the implementation of this class for awhile. We will integrate the XMPP features when ready. For now, let's move to the login.

Building the Login User Interface

This view shows up when the user has not yet entered login credentials or when the "Account" button is tapped. It is made of two input fields and a button. An additional action will enable the user to hide the view without changes.

1
2
@interface SMLoginViewController : UIViewController {
3
4
	UITextField *loginField;
5
	UITextField *passwordField;
6
7
}
8
9
@property (nonatomic,retain) IBOutlet UITextField *loginField;
10
@property (nonatomic,retain) IBOutlet UITextField *passwordField;
11
12
- (IBAction) login;
13
- (IBAction) hideLogin;
14
15
@end

The implementation is pretty straightforward. When the login action is triggered data in the textfields is stored in NSUSerDefaults with two keys "userID" and "userPassword". This data will be used by the XMPP engine and sent to the server.

1
2
@implementation SMLoginViewController
3
4
@synthesize loginField, passwordField;
5
6
- (IBAction) login {
7
8
	[[NSUserDefaults standardUserDefaults] setObject:self.loginField.text forKey:@"userID"];
9
	[[NSUserDefaults standardUserDefaults] setObject:self.passwordField.text forKey:@"userPassword"];
10
	[[NSUserDefaults standardUserDefaults] synchronize];
11
12
	[self dismissModalViewControllerAnimated:YES];
13
14
}
15
16
- (IBAction) hideLogin {
17
18
	[self dismissModalViewControllerAnimated:YES];
19
20
}
21
22
@end

As above we should remember to link text fields and actions in the XIB file.

Designing the Login ViewDesigning the Login ViewDesigning the Login View

Now we can update the BuddyList controller to show the login view when needed. We import the corresponding class and we update the action as follows.

1
2
- (IBAction) showLogin {
3
4
	SMLoginViewController *loginController = [[SMLoginViewController alloc] init];
5
	[self presentModalViewController:loginController animated:YES];
6
7
}

We also implement the viewDidAppear function so that it shows the login view when no data is stored.

1
2
- (void)viewDidAppear:(BOOL)animated {
3
4
	[super viewDidAppear:animated];
5
6
	NSString *login = [[NSUserDefaults standardUserDefaults] objectForKey:@"userID"];
7
8
	if (!login) {
9
10
		[self showLogin];
11
12
	}
13
}

If we compile the application we should see that the login view appears as expected or when the user taps the button.

Creating the Chat View

The chat view features four visual elements:

  • a toolbar with a button to close the view
  • a textfield to type in messages
  • a button to send messages
  • a table view to display sent and received messages
Designing the Chat ViewDesigning the Chat ViewDesigning the Chat View

The header file is the following:

1
2
@interface SMChatViewController : UIViewController  {
3
4
UITextField		*messageField;
5
NSString		*chatWithUser;
6
UITableView		*tView;
7
NSMutableArray	*messages;
8
9
}
10
11
@property (nonatomic,retain) IBOutlet UITextField *messageField;
12
@property (nonatomic,retain) NSString *chatWithUser;
13
@property (nonatomic,retain) IBOutlet UITableView *tView;
14
15
- (id) initWithUser:(NSString *) userName;
16
- (IBAction) sendMessage;
17
- (IBAction) closeChat;
18
19
@end

Like the buddy view this class implements table delegates. It keeps track of the received by means of the string variable chatWithUser and features two actions, closeChat and sendMessage. The corresponding implementation is the following.

1
2
@implementation SMChatViewController
3
4
@synthesize messageField, chatWithUser, tView;
5
6
- (void)viewDidLoad {
7
8
    [super viewDidLoad];
9
    self.tView.delegate = self;
10
    self.tView.dataSource = self;
11
    messages = [[NSMutableArray alloc ] init];
12
13
    [self.messageField becomeFirstResponder];
14
15
}
16
17
#pragma mark -

18
#pragma mark Actions

19
20
- (IBAction) closeChat {
21
22
    [self dismissModalViewControllerAnimated:YES];
23
24
}
25
26
- (IBAction)sendMessage {
27
28
    NSString *messageStr = self.messageField.text;
29
30
    if([messageStr length] > 0) {
31
32
        // send message through XMPP

33
34
       self.messageField.text = @"";
35
36
       NSString *m = [NSString stringWithFormat:@"%@:%@", messageStr, @"you"];
37
38
       NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
39
       [m setObject:messageStr forKey:@"msg"];
40
       [m setObject:@"you" forKey:@"sender"];
41
42
       [messages addObject:m];
43
       [self.tView reloadData];
44
       [m release];
45
46
    }
47
48
}
49
50
#pragma mark -

51
#pragma mark Table view delegates

52
53
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
54
55
    NSDictionary *s = (NSDictionary *) [messages objectAtIndex:indexPath.row];
56
    static NSString *CellIdentifier = @"MessageCellIdentifier";
57
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
58
59
    if (cell == nil) {
60
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
61
    }
62
63
    cell.textLabel.text = [s objectForKey:@"msg"];
64
    cell.detailTextLabel.text = [s objectForKey:@"sender"];
65
    cell.accessoryType = UITableViewCellAccessoryNone;
66
    cell.userInteractionEnabled = NO;
67
68
    return cell;
69
70
}
71
72
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
73
74
    return [messages count];
75
76
}
77
78
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
79
80
    return 1;
81
82
}
83
84
#pragma mark -

85
#pragma mark Chat delegates

86
87
// react to the message received

88
89
- (void)dealloc {
90
91
    [messageField dealloc];
92
    [chatWithUser dealloc];
93
    [tView dealloc];
94
    [super dealloc];
95
96
}

When the view has loaded we show the keyboard. The table part is pretty similar to the buddy view. Here we use a slightly different type of table cell to display both the message and the name. Below is the intended result when the application is ready:

The Chat View at runtime

We should remember to connect the IBAction properties with the corresponding buttons as usual.

Chat View outlets

The visual part of out application is ready! Now we are left with the core functionality of messaging, and that will be covered in the next part of this series!

Source Code

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

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.