The following two tabs change content below.
Hi, I have written and developed this site to share my experience and ideas with other colleagues. I also started to prepare interview questions and answers for job seekers. I hope it will help you a lot.

What is XMPP?

XMPP (Extensible Messaging and Presence Protocol) is a protocol based on Extensible Markup Language (XML) and intended for instant messaging (IM) and online presence detection. The protocol may eventually allow Internet users to send instant messages to anyone else on the Internet, regardless of differences in operating systems and browsers.

I am assuming you have done openfire server installation already if not yet please follow below link

http://download.igniterealtime.org/openfire/docs/3.10.0/documentation/install-guide.html

After the Openfire server installation you are ready to create XMPP client for android. In this post I am covering below points
1. Get registered user’s list
2. Start chat with selected user.

To get user list I am using API of openfire server. By default its not coming with openfire if you want to enable on server then you have to install some plugins I am sharing the screenshot of plugin page.

plugin

Note: if you are not able to find this plugin on plugin page then go to “Available Plugins” link where you can find the all openfire plugin and then install as per your requirement.

For user related operation I have installed “Rest API” plugins and for presence operation installed “Presence Service” plugins.

for API details/document of the plugins you can follow highlighted link as per given in below screenshots.

doc_link

once you are familiar with all these thing now going to start development of XMPP android client.  Download full source code from here TextChat

1. Create a android studio project and add the following dependency into “build.gradle” file.

/Used for json parsing
compile 'com.google.code.gson:gson:2.3.1'
//Used for API call
compile 'com.android.volley:volley:1.0.0'
//Below dependency are required for XMPP client
compile "org.igniterealtime.smack:smack-android:4.1.0-rc1"
compile "org.igniterealtime.smack:smack-tcp:4.1.0-rc1"
compile "org.igniterealtime.smack:smack-android-extensions:4.1.0-rc1"


2. For session creation use below code

private void initialiseConnection() {

    XMPPTCPConnectionConfiguration.Builder config = XMPPTCPConnectionConfiguration.builder();
    config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
    config.setServiceName(serverAddress);
    config.setHost(serverAddress);
    config.setPort(5222);
    config.setDebuggerEnabled(true);
    XMPPTCPConnection.setUseStreamManagementResumptiodDefault(true);
    XMPPTCPConnection.setUseStreamManagementDefault(true);
    connection = new XMPPTCPConnection(config.build());

    XMPPConnectionListener connectionListener = new XMPPConnectionListener();
    connection.addConnectionListener(connectionListener);

}

3. For session connect given below code

public void connect(final String caller) {

    AsyncTask<Void, Void, Boolean> connectionThread = new AsyncTask<Void, Void, Boolean>() {
        @Override
        protected synchronized Boolean doInBackground(Void... arg0) {
            if (connection.isConnected())
                return false;
            isconnecting = true;
            if (isToasted)
                new Handler(Looper.getMainLooper()).post(new Runnable() {

                    @Override
                    public void run() {
                        Toast.makeText(context, caller + "=>connecting....", Toast.LENGTH_LONG).show();
                    }
                });
            Log.d("Connect() Function", caller + "=>connecting....");

            try {
                connection.connect();
                DeliveryReceiptManager dm = DeliveryReceiptManager
                        .getInstanceFor(connection);
                dm.setAutoReceiptMode(AutoReceiptMode.always);
                dm.addReceiptReceivedListener(new ReceiptReceivedListener() {

                    @Override
                    public void onReceiptReceived(final String fromid, final String toid, final String msgid, final Stanza packet) {
                    }
                });
                connected = true;

            } catch (IOException e) {
                if (isToasted)
                    new Handler(Looper.getMainLooper())
                            .post(new Runnable() {
                                @Override
                                public void run() {
                                    Toast.makeText( context,"(" + caller + ")" + "IOException: ", Toast.LENGTH_SHORT).show();
                                }
                            });

                Log.e("(" + caller + ")", "IOException: " + e.getMessage());
            } catch (SmackException e) {
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, "(" + caller + ")" + "SMACKException: ", Toast.LENGTH_SHORT).show();
                    }
                });
                Log.e("(" + caller + ")","SMACKException: " + e.getMessage());
            } catch (XMPPException e) {
                if (isToasted)
                    new Handler(Looper.getMainLooper())
                            .post(new Runnable() {

                                @Override
                                public void run() {
                                    Toast.makeText( context,"(" + caller + ")" + "XMPPException: ", Toast.LENGTH_SHORT).show();
                                }
                            });
                Log.e("connect(" + caller + ")", "XMPPException: " + e.getMessage());
            }
            return isconnecting = false;
        }
    };
    connectionThread.execute();
}

4. And for session login

public void login() {

    try {
        connection.login(loginUser, passwordUser);
        Log.i("LOGIN", "Yey! We're connected to the Xmpp server!");
    } catch (XMPPException | SmackException | IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
    }

}

5. Smack library given some callback functions under “ConnectionListener” which we can use to check our connection status like is “connected”, “connectionClosed” and “reconnectingIn” etc. Below is code with all callbacks

public class XMPPConnectionListener implements ConnectionListener {
    @Override
    public void connected(final XMPPConnection connection) {
        Log.d("xmpp", "Connected!");
        connected = true;
        if (!connection.isAuthenticated()) {
            login();
        }
    }

    @Override
    public void connectionClosed() {
        if (isToasted)

            new Handler(Looper.getMainLooper()).post(new Runnable() {

                @Override
                public void run() {
                    Toast.makeText(context, "ConnectionCLosed!",
                            Toast.LENGTH_SHORT).show();

                }
            });
        Log.d("xmpp", "ConnectionCLosed!");
        connected = false;
        chat_created = false;
        loggedin = false;
    }

    @Override
    public void connectionClosedOnError(Exception arg0) {
        if (isToasted)

            new Handler(Looper.getMainLooper()).post(new Runnable() {

                @Override
                public void run() {
                    Toast.makeText(context, "ConnectionClosedOn Error!!",
                            Toast.LENGTH_SHORT).show();

                }
            });
        Log.d("xmpp", "ConnectionClosedOn Error!");
        connected = false;

        chat_created = false;
        loggedin = false;
    }

    @Override
    public void reconnectingIn(int arg0) {

        Log.d("xmpp", "Reconnectingin " + arg0);

        loggedin = false;
    }

    @Override
    public void reconnectionFailed(Exception arg0) {
        if (isToasted)

            new Handler(Looper.getMainLooper()).post(new Runnable() {

                @Override
                public void run() {

                    Toast.makeText(context, "ReconnectionFailed!",
                            Toast.LENGTH_SHORT).show();

                }
            });
        Log.d("xmpp", "ReconnectionFailed!");
        connected = false;

        chat_created = false;
        loggedin = false;
    }

    @Override
    public void reconnectionSuccessful() {
        if (isToasted)

            new Handler(Looper.getMainLooper()).post(new Runnable() {

                @Override
                public void run() {
                    Toast.makeText(context, "REConnected!",
                            Toast.LENGTH_SHORT).show();

                }
            });
        Log.d("xmpp", "ReconnectionSuccessful");
        connected = true;

        chat_created = false;
        loggedin = false;
    }

    @Override
    public void authenticated(XMPPConnection arg0, boolean arg1) {
        Log.d("xmpp", "Authenticated!");
        loggedin = true;
        ChatManager.getInstanceFor(connection).addChatListener(
                mChatManagerListener);

        chat_created = false;
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }).start();
        if (isToasted)

            new Handler(Looper.getMainLooper()).post(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub

                    Toast.makeText(context, "Connected!",
                            Toast.LENGTH_SHORT).show();

                }
            });
    }
}

6. For send an text message to other user below code I have used.

public void sendMessage(ChatMessage chatMessage) {

    if (!chat_created) {
        Mychat = ChatManager.getInstanceFor(connection).createChat(
                chatMessage.receiver + "@"
                        + context.getString(R.string.server),
                mMessageListener);
        chat_created = true;
    }
    final Message message = new Message();
    message.setBody(chatMessage.getBody());
    message.setType(Message.Type.normal);

    try {
        if (connection.isAuthenticated()) {
            Mychat.sendMessage(message);
        } else {
            login();
        }
    } catch (NotConnectedException e) {
        Log.e("xmpp.SendMessage()", "msg Not sent!-Not Connected!");

    } catch (Exception e) {
        e.printStackTrace();
    }
}

7. And there is “ChatMessageListener” in library using this we can handle incoming message. Under this listener we have a method named “processMessage” which we can use to track incoming message.

private class MMessageListener implements ChatMessageListener {

    public MMessageListener(Context contxt) {
    }

    @Override
    public void processMessage(final org.jivesoftware.smack.chat.Chat chat,
                               final Message message) {
        Log.i("MyXMPP_MESSAGE_LISTENER", "Xmpp message received: '"
                + message);

        System.out.println("Body-----"+message.getBody());

        if (message.getType() == Message.Type.chat
                && message.getBody() != null) {
            final ChatMessage chatMessage = new ChatMessage();
            chatMessage.setBody(message.getBody());

            processMessage(chatMessage);
        }
    }

    private void processMessage(final ChatMessage chatMessage) {

        chatMessage.isMine = false;
        Chats.chatlist.add(chatMessage);
        new Handler(Looper.getMainLooper()).post(new Runnable() {

            @Override
            public void run() {
                Chats.chatAdapter.notifyDataSetChanged();

            }
        });
    }

}

8. To get registered user list calling the “plugins/restapi/v1/users” API

public void getUsrList(){
        requestQueue = Volley.newRequestQueue(getActivity());
        try {
            StringRequest strReq = new StringRequest(Request.Method.GET,"http://"+ getString(R.string.server)+":9090/plugins/restapi/v1/users", new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
              //  System.out.println("Response : "+response);
                UserResponse userResponse = new Gson().fromJson(response, UserResponse.class);
                users.clear();
                users.addAll(Arrays.asList(userResponse.getUser()));
                adapter = new UserListAdapter(getActivity(), users);
                userList.setAdapter(adapter);
            }
        }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        error.printStackTrace();
                    }
                }){

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<String, String>();
                headers.put("Authorization", "6rewDIzgr0cqKflL");
                headers.put("Accept", "application/json");
                return headers;
            }
        };
        requestQueue.add(strReq);
    }
    catch (Exception e){
        e.printStackTrace();
    }
}


9. If you want to show the user status like “Online”, “Offline” and “Away” etc in that case I have implemented below API

viewHolder.status.setImageUrl("https://"+activity.getString(R.string.server)+":9090/plugins/presence/status?jid="+userList.get(position).getUsername()+"@domain_name", imageLoader);

10. So thats all that was the main operation which I have done into this post. In the below session I am giving application screenshots.

User List:

userlist     textchat

 

User2 doing using Spark client:

user2

 

Thats all you can download full source code from here TextChat

26,112 total views, 5 views today

26 thoughts on “Android Chat Application using Openfire server and XMPP (SMACK) client”

      1. Thanks for this great tutorial, and m waiting for your group chat tutorial. Hope u will publish it soon.

  1. I’m trying to use your source code to test if i can connect my openfire server. I’ve openfire running on my pc and when start your app i got this error:
    “SMACKException: The following addresses failed: ‘192.168.1.5:5222’ failed because java.net.SocketTimeoutException: connect timed out”
    I’m able to connect with spark client on the same machine where openfire is running, but not with android…

    1. I solved the problem… now i’m able to login from another network (in openfire i can see user is online) but the rest api doesn’t work. No user is in the list.

      1. May be on the console you are getting authentication error.. Please make sure you are call Rest API with proper authentication

        Authentication

        All REST Endpoint are secured and must be authenticated. There are two ways to authenticate:

        Basic HTTP Authentication
        Shared secret key
        The configuration can be done in Openfire Admin console under Server > Server Settings > REST API.

        Basic HTTP Authentication

        To access the endpoints is that required to send the Username and Password of a Openfire Admin account in your HTTP header request.

        E.g. Header: Authorization: Basic YWRtaW46MTIzNDU= (username: admin / password: 12345)

        Shared secret key

        To access the endpoints is that required to send the secret key in your header request. The secret key can be defined in Openfire Admin console under Server > Server Settings > REST API.

        E.g. Header: Authorization: s3cretKey

        You can follow the below link for more details
        https://www.igniterealtime.org/projects/openfire/plugins/restapi/readme.html

        1. hello, I am new to create this application. I dont understand the overall process of chat application. Will you suggest any source or material to learn and get a clear idea about the chat application? And also , have to create a new chat application

  2. Appreciate this tutorial but its not very clear, Please explain every method used in the code for example connecting with my openfire admin account

  3. I ‘m facing this error:
    SMACKException: No response received within packet reply timeout. Timeout was 20000ms (~20s)
    Please give me any suggestions.

  4. haiiii. i want to ask about, how can i connect the android application with my openfire server? hope you can help. thank you

  5. hello sir.. i use your code, work good. but i cant send message to spark client, whats wrong i dont know but can receive message from spark.. what to do please guide me, no error found and nothing else.. i can see the connected toast and as well as user online in server console, spark user also online, but what the prob i dont know… please reply me..

Leave a Reply

Your email address will not be published. Required fields are marked *