CzarTechnoGeeks.com

Solution for iPhone related problems and Tutorials

06
May

Chat Client for iOS

Chat application:

Let me first introduce you with the Chat Client Application for iPhone.

What exactly this is all about?

Ans: This chat application is just like your yahoo messenger, Skype or Gtalk, and the same functionality will be there in this chat client.

What is used to develop this application?

And: This application needs a Mac OS X, with Xcode installed, and main importantly let me tell you at first note that this will be built on ARC in xcode. This application is based on the XMPP Protocol.

What is ARC in Xcode?

And: ARC is Automatic reference counting. This means that the Xcode is now able to release the memory automatically, so you will not be able to use the “release”, “dealloc” functions in this project.

XMPP stands for eXtensible Messaging and Presence Protocol. Such a protocol is open-standard and oriented to message exchange. You can find more about the XMPP on www.xmpp.org and the library is being developed by the Robbie on Github all credits goes to him.

How Does it Work?

The XMPP protocol is based on XML (Extensible Markup Language) so each type of message (e.g. login, message send, etc.) is encoded in this format. For example, let’s suppose President Obama sends a message to Hillary. The format of the message would be something like this:

<message type="chat" from="jawad@server.com" to="otheruser@server.com">

    <body>Hi there</body>

</message>

For sake of completeness we should mention that XMPP is a decentralized service, much like email. This means that the Hillary and Obama accounts might be on different servers (i.e. jawad@server.com and other@otherserver.com). The message is delivered anyway because XMPP enables server-to-server communication. In case Hillary is offline, the message is cached on the server and delivered when she goes online. To keep things simple and focus on the client side, in this tutorial we will consider a scenario with just one server.
Now Lets divide this Xcode project into 4 parts for our understanding.
1. Making a Local Server.
2. Setting up your UI
3.XMPP Setup
4. Enhancing it with some emoticons

Lets begin with making you computer as a local server for this iOS Chat client application.

1. Goahead and download the ejabberd server from http://www.process-one.net/en/ejabberd/downloads.

2. Once you download that install it to your MAC or Microsoft XP, so in this tutorial we have used the EJabbered 2.1.8 or you can use the higher one.

Once you complete the download, install it and check that you have the folders that are shown in the below image:

Now, lets go ahead and open the terminal of your Mac.

Now type the following command

cd /applications/ejabberd-2.1.X/bin

X is nothing but whatever version you have downloaded it from the ejabberd website.

now you are in the bin folder now write this command.

bin>ls

you will be listed with the files and folders in that bin folder. So, if you look closely there will be start and stop files.

3. The most important commands are ‘start’ and ‘stop’. In case they are not executable you can make them so by issuing the following shell command:
chmod 755 stop

chmod 755 start
The folder also contacts the postinstall.sh so you have to write the following command in your terminal window

./postinstall yourname server.local serverpassword

yourname = Your server admin name

serverpassword =  your server password

We have selected the server.local, the name of the local machine, as domain but ‘localhost’ would work as well.

So now to start the server you have to write the command that is ./start

4. Once you write this command and hit enter you will be redirected to the ejabberd webpage just like this.

So this tells us that your server is now started. And if you see “ejabbed service logs” then you will be able to see the logs that shows that you are connected to the local server and how it got connected.

5. Now login into your server with the details provided on this page itself.

At the moment our service has just administrators. We need to populate it with at least one user. The previous web page contains a link to the admin interface, which is available at http://localhost:5280/admin/. Once you have logged in as the admin you should see a console like the following

6. We click on the “Access Control Lists” item and the list of currently registered users appears. We create a new user, named ‘anyname’, by entering its details and clicking submit

Now let’s test the server

Now we are able to test the server and check that it works correctly. To test it we can run two desktop applications which support the XMPP protocol. One is iChat, which comes with Mac OS X. You can find another, the one that suits you better, from this list:
http://xmpp.org/xmpp-software/clients/
In our case we will use Adium, which is available here. We will configure an account for ‘name’ on iChat and another for ‘sample’ on Adium. Let’s start with iChat. Start the application and open the Preferences menu and select the Accounts tab.

The “+” buttons allows adding a new account, which we fill with the following data:

The first connection might take some time (e.g. 30 seconds). iChat will probably ask you to accept the unknown certificate which is bundled with the server. Just click continue.

Once you are connected you can change your status by means of the drop down menu at the top of the window. Let’s set it to online. Now let’s move to Adium. We start the application and we open the Preferences menu. Adding a new account is pretty similar to iChat. Here we enter the ‘Jawad’ details.

In this case we have also to specify the server which is running jabber. We select the ‘Options’ tab and we fill it as follows

Adium will ask you to accept the certificate as well. Now we have to two users connected to the server by means of two different applications. This should also be reflected in the log file of ejabbered. The file is located at: ‘/Applications/ejabberd-2.1.8/logs/ejabberd.log’ and should contain the following messages

If you remember I have shown you the link above, to see the logs.

In the log you will see like this

for example : There will be text like

Accepted Authentication for jawad by ejabberd_auth_internal

Opened session for jawad@sme-macbook.local/sme

27,0,0,1},522}

Accepted authentication for otheruser by ejabberd_auth_internal

Opened session for otheruser@sme-macbook.local/sme

Chatting is about friendship. Although both users are connected to the server their are not enabled to chat unless they add once each other as friends. The scenario will be the following: jawad adds otheruser to his list. In the iChat window we select the “+” button at the bottom.

and we enter the jabber id ‘otheruser@sme-macbook.local’

On Adium we should receive an Authorization Request as follows

Once otheruser accepts it we should end up as in the following figure, jawad is friend with otheruser (and vice versa) and both can exchange messages.

We have tested all the functionalities needed for the server:

  • Login with username and password
  • buddy list
  • chat messages exachange

This was needed to ensure that possible errors in the iOS application are not due to server misconfigurations. Now we are ready to dig into the development of the iOS application.

So, guys click on the next page for the continuation of this tutorial.

Pages: 1 2 3

17 Responses so far.

  1. Vedant says:

    Hi, I had tried everything that you have stated in this tutorial, but my app crashes when i try to send a message, also the message doesnt get delivered. I can receive messages but the app again crashes after a few messages. The message that i send/receive gets displayed twice.

    I can also email you a screenshot if necessary. Immediate help would be greatly appreciated cause i need to make a jabber client up and running.

    i used my google id for testing since gtalk complies to the XMPP protocol.

    Also could you explain how do these lines of code make sense?

    “NSString *m = [NSString stringWithFormat:@"%@:%@", messageStr, @"you"];

    NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
    [m setObject:messageStr forKey:@"msg"];
    [m setObject:@"you" forKey:@"sender"];

    [messages addObject:m];
    [self.tView reloadData];”

    both the nsstring object and the dictionary bear the same variable name which will create an error.

    Thanks!

    • Czar says:

      All you need to do is just comment the
      //NSString *m = [NSString stringWithFormat:@"%@:%@", messageStr, @"you"];

      and run your app!. It was a mistake in the programming actually I was using NSLOG statement using the NSString *m.

  2. JD says:

    Hmmm that is what I was thinking for to comment NSString. and check my code.

  3. Vedant says:

    Hi, I don’t see the implementation of the protocol method newMessageReceived anywhere, any tips?

  4. Vedant says:

    Any support?

  5. Czar says:

    I have implemented that method have a look at it and let me know if you don’t understand at any point. And this method should be implemented in ChatViewController where you have the send message implemented.

    #pragma mark -
    #pragma mark Chat delegates

    // react to the message received

    
    - (void)newMessageReceived:(NSMutableDictionary *)messageContent {
    
        NSString *m = [messageContent objectForKey:@"msg"];
        [messageContent setObject:[m substituteEmoticons] forKey:@"msg"];
       [messageContent setObject:[NSString getCurrentTime] forKey:@"time"];
        NSLog(@"the message is : %@",m);
    
    //   
    
        NSString *kilme=[NSString stringWithFormat:@"%@",messageContent];
       NSLog(@"the value of j is %d",kilme);
    
            [messages addObject:messageContent];
            [self.tView reloadData];
            NSIndexPath *topIndexPath = [NSIndexPath indexPathForRow:messages.count-1
                                                           inSection:0];
    
            [self.tView scrollToRowAtIndexPath:topIndexPath
                              atScrollPosition:UITableViewScrollPositionMiddle
                                      animated:YES];
    
    }
    

    And you get the message content string content passed from your AppDelegate class from this method

    - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
    {
    }
    

    Check this out!

    • Vedant says:

      Thanks for the info! Well i am assuming that the methods substituteEmoticons and getCurrentTime are the ones that provide emoticon and time stamp support. Since I have not implemented those methods, I have commented them out.

      I can receive messages now, but the problem is that I cannot send messages, ie. my message doesn’t get delivered. Also The message that I want to send, gets displayed twice on my app. I could use help to know where I went wrong, I have crossed checked my code with the one in the tutorial and there are no differences.

      Thanks Czar for all the help :)

  6. Czar says:

    Check your send message method, that you have also mentioned the line to pass the message in xml format using xmppStream.

    [self.xmppStream sendelement:m];

    where m would be your message string.

    • Vedant says:

      Just checked it out and I can say that I have not missed that line of code out. Is it because of something else?

      My sendMessage method entails the following code:

      NSString *messageStr = self.messageField.text;
           if([messageStr length] &gt; 0) {
                NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
                [body setStringValue:messageStr];
                NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
                [message addAttributeWithName:@"type" stringValue:@"chat"];
                [message addAttributeWithName:@"to" stringValue:chatWithUser];
                [message addChild:body];
                [self.xmppStream sendElement:message];
                self.messageField.text = @"";
                NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
                [m setObject:messageStr forKey:@"msg"];
                [m setObject:@"you" forKey:@"sender"];
                [messages addObject:m];
                [self.tView reloadData];
      
      • Czar says:

        I want you to put this line in your send message code

        Nslog(@”ChatWithUser Name is %@”,chatWithUser);

        and check that you are getting the correct username, to whome you want to send the message.

        • Vedant says:

          Hey Czar!

          Well I did what you asked me to do, i could see the username on the console. But, I identified the problem. It was only showing the name that appears before the “@email.com”, which is why it was not delivering the message. Now I can send messages!

          Thanks a lot for the help :-)

          I have another question, are push notifications supported? The reason being that if I dont have my chatViewcontroller View open, i do not receive any messages, neither do i get any notifications regarding the same. Can we implement that feature?

          Thanks a ton once again!

          • Czar says:

            Yes, there is a way but I have not yet implemented it. If you think in another way of getting the message received pop up, then just implement the UIAlertView, In your Didreceive message method. And in your code tell that, if you are not in chatviewcontroller then alert me with the alertview that I received the messsage from particular user. And if you in chatview controller then put the alertview off.

            Do it using the if else condition. It can be implemented.

  7. Vedant says:

    Thanks for the insight! Well If i do implement the alert message, will the message get cached and displayed later when I open the chat view?

  8. Czar says:

    You are adding the messages received to the Array “messages” and the table view data resource is this Array. So, if you are able to insert the message in this array and not releasing it. Then you will be able to have the message available in your Chat tableview.

    Anyways in other words and with the best concept is to store the messages in database like core datastorage or sql lite is the best way to store the chat history of the client.

    I’ve not implemented the chat history with the core datastorage or with sql lite. As I’ve not have much knowledge in core datastorage or sql lite as of now.

    So, if you are able to implement it, please let me know. So that I can also implement the chat history.

  9. Vedant says:

    I was implementing the timestamp feature, and i am having issues in following method

    - (void)newMessageReceived:(NSDictionary *)messageContent;

    the following lines in the method produce the error “No visible @interface for NSDictionary declares the the selector ‘setObject:forkey’”
    [messageContent setObject:[NSString getCurrentTime] forKey:@”time”];

    I had imported the files that declare and state the getCurrentTime method.
    so that shouldn’t be the issue.

    I also made a mutablecopy of the messageContent dictionary and replaced the places where messageContent was used but it didn’t help.

    Any suggestions?