Badblog

welcome to our blog

We are Learncodz.


Posts

Comments

The Team

Blog Codz Author

Connect With Us

Join To Connect With Us

Portfolio

  • We have seen a large number of applications come up in the recent past, to help us connect with each other across different mediums, like Hike, Whatsapp, Viber etc. You would be surprised to learn that its rather quite easy to develop one yourself. I thought providing an insight into developing such an application would be helpful for you guys.

    Today we are going to learn how to build a simple group chat app using sockets. I won’t say this is the only way to build a chat app, but it is the quick & easiest way to build one. The best and efficient way would be using the push notifications instead of sockets.

    Overall we are going to build three components in this article. The first and important component is the socket server. The socket server plays a major role like handling the socket client connections, passing the messages between clients. Second component is the web app where you can join the chat conversation from a browser. Finally the android app. The main advantage of this app is, you can chat between web – web, web – android or android – android.

    As this article seems pretty much lengthy, I am dividing the tutorial into two parts. In this first part, all the basic setup and building the web app is covered. In the 2nd Part, building the actual android app is covered.

    Below are the final outcomes from this tutorial.

    How the App Works Over Sockets?
    If you are coming across the ‘sockets’ for the first time, the wikipedia page give you basic knowledge about socket communication. Below you can find a brief info about how our app works.

    1. First we’ll have a socket server running. When the android app or web app connects to socket server, the server opens a TCP connection between server and client. The server is capable of opening concurrent connections when there are multiple clients.

    2. When a socket connection is established few callback methods like onOpen, onMessage, onExit will be triggered on the both the ends (on server side and client side). There will be another method available to send message from client to server, or vice versa.

    3. JSON strings will be exchanged between server and client as a communication medium. Each JSON contains a node called flag to identify the purpose of JSON message. Below is example of JSON when a client joined the conversation that contains the client name, session id and number of people online.

    {
        "message": " joined conversation!",
        "flag": "new",
        "sessionId": "4",
        "name": "Ravi Tamada",
        "onlineCount": 6
    }
    4. Whenever a JSON message received on client side, the JSON will be parsed and appropriate action will be taken.

    I hope the above information gave enough knowledge over the app. Now we can move forward and start building one by one component.

    1. Eclipse adding J2EE & Tomcat 7 Support
    The eclipse IDE that comes along with android SDK, doesn’t have J2EE and Tomcat server support. So we have to add J2EE and tomcat extensions. Another option would be downloading another eclipse that supports J2EE, but I would like use the eclipse that supports both android and j2ee instead of two different IDEs.

    1. Download apache tomcat 7 from tomcat website. (You can download it from this direct link). Once downloaded, extract it in some location.

    2. In Eclipse go to Help ⇒ Install New Software. Click on Work with drop down and select Juno – http://download.eclipse.org/releases/juno. (You might need to select the appropriate eclipse release depending upon your eclipse flavour)

    3. Expand Web, XML, Java EE and OSGi Enterprise Development and select below extensions and proceed with installation.
       > Eclipse Java EE Developer Tools
       > JST Server Adapters
       > JST Server Adapters Extensions

    4. Once the extensions are installed, Eclipse will prompt you to restart. When the eclipse re-opened, we need to create a server first. Goto Windows ⇒ Show View ⇒ Server ⇒ Servers.

    5. In servers tab, click on new server wizard and select Apache ⇒ Tomcat v7.0 Server. Give server name, browse and select the tomcat home directory which we downloaded previously.

    Check out the below video if you not very clear with the above steps.

    2. Finding Your PC IP Address
    As we need to test this app on multiple devices (it can be a mobile, PC or a laptop) in a wifi network, we need to know the IP address of the PC where the socket server project running. So instead of using localhost, we need to use the ip address in the url. In order to get the ip address of your machine, execute below commands in terminal.

    On Windows

    ipconfig

    On Mac

    ifconfig

    Note: The ip address of your machine might changes whenever you disconnected from wifi or a new device added to wifi network. So make sure that you are using the correct ip address every time you test the app.

    Once the Eclipse Tomcat setup is ready and you know the IP address, you are good to go with socket server development. Building the socket server is very easy. The socket server we are going to build won’t take more than two class files.

    3. Building the Socket Server
    1. In Eclipse create a new Dynamic Web Project by navigating to File ⇒ New ⇒ Other ⇒ Web ⇒ Dynamic Web Project. Give the project name and select the Target runtime as Tomcat 7. I gave my project name as WebMobileGroupChatServer.

    Once the project is created, it contains below directory structure.

    2. Right click on src ⇒ New ⇒ Package and give the package name. I gave my package name as info.androidhive.webmobilegroupchat.

    3. Now download google-collections-0.8.jar, javaee-api-7.0.jar, json-org.jar files and paste them in project’s WebContent ⇒ WEB-INF ⇒ lib folder.

    4. Create a new class named JSONUtils.java under project’s src package folder. This class contains methods to generate JSON strings those are required to have the communication b/w socket server and clients.

    In the below code, if you observer each json contains flag node which tell the clients the purpose of JSON message. On the client side we have to take appropriate action considering the flag value.

    Basically the flag contains four values.

    self = This JSON contains the session information of that particular client. This will be the first json a client receives when it opens a sockets connection.

    new = This JSON broadcasted to every client informing about the new client that is connected to socket server.

    message = This contains the message sent by a client to server. Hence it will broadcasted to every client.

    exit = The JSON informs every client about the client that is disconnected from the socket server.

    JSONUtils.java
    package info.androidhive.webmobilegroupchat;

    import org.json.JSONException;
    import org.json.JSONObject;

    public class JSONUtils {

        // flags to identify the kind of json response on client side
        private static final String FLAG_SELF = "self", FLAG_NEW = "new",
                FLAG_MESSAGE = "message", FLAG_EXIT = "exit";

        public JSONUtils() {
        }

        /**
         * Json when client needs it's own session details
         * */
        public String getClientDetailsJson(String sessionId, String message) {
            String json = null;

            try {
                JSONObject jObj = new JSONObject();
                jObj.put("flag", FLAG_SELF);
                jObj.put("sessionId", sessionId);
                jObj.put("message", message);

                json = jObj.toString();
            } catch (JSONException e) {
                e.printStackTrace();
            }

            return json;
        }

        /**
         * Json to notify all the clients about new person joined
         * */
        public String getNewClientJson(String sessionId, String name,
                String message, int onlineCount) {
            String json = null;

            try {
                JSONObject jObj = new JSONObject();
                jObj.put("flag", FLAG_NEW);
                jObj.put("name", name);
                jObj.put("sessionId", sessionId);
                jObj.put("message", message);
                jObj.put("onlineCount", onlineCount);

                json = jObj.toString();
            } catch (JSONException e) {
                e.printStackTrace();
            }

            return json;
        }

        /**
         * Json when the client exits the socket connection
         * */
        public String getClientExitJson(String sessionId, String name,
                String message, int onlineCount) {
            String json = null;

            try {
                JSONObject jObj = new JSONObject();
                jObj.put("flag", FLAG_EXIT);
                jObj.put("name", name);
                jObj.put("sessionId", sessionId);
                jObj.put("message", message);
                jObj.put("onlineCount", onlineCount);

                json = jObj.toString();
            } catch (JSONException e) {
                e.printStackTrace();
            }

            return json;
        }

        /**
         * JSON when message needs to be sent to all the clients
         * */
        public String getSendAllMessageJson(String sessionId, String fromName,
                String message) {
            String json = null;

            try {
                JSONObject jObj = new JSONObject();
                jObj.put("flag", FLAG_MESSAGE);
                jObj.put("sessionId", sessionId);
                jObj.put("name", fromName);
                jObj.put("message", message);

                json = jObj.toString();

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

            return json;
        }
    }

    5. Create another class named SocketServer.java and add the below code. This is the where we implement actual socket server.

    This class mainly contains four callback methods.

    onOpen() – This method is called when a new socket client connects.
    onMessage() – This method is called when a new message received from the client.
    onClose() – This method is called when a socket client disconnected from the server.
    sendMessageToAll() – This method is used to broadcast a message to all socket clients.

    SocketServer.java
    package info.androidhive.webmobilegroupchat;

    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URLDecoder;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;

    import javax.websocket.OnClose;
    import javax.websocket.OnMessage;
    import javax.websocket.OnOpen;
    import javax.websocket.Session;
    import javax.websocket.server.ServerEndpoint;

    import org.json.JSONException;
    import org.json.JSONObject;

    import com.google.common.collect.Maps;

    @ServerEndpoint("/chat")
    public class SocketServer {

        // set to store all the live sessions
        private static final Set<Session> sessions = Collections
                .synchronizedSet(new HashSet<Session>());

        // Mapping between session and person name
        private static final HashMap<String, String> nameSessionPair = new HashMap<String, String>();

        private JSONUtils jsonUtils = new JSONUtils();

        // Getting query params
        public static Map<String, String> getQueryMap(String query) {
            Map<String, String> map = Maps.newHashMap();
            if (query != null) {
                String[] params = query.split("&");
                for (String param : params) {
                    String[] nameval = param.split("=");
                    map.put(nameval[0], nameval[1]);
                }
            }
            return map;
        }

        /**
         * Called when a socket connection opened
         * */
        @OnOpen
        public void onOpen(Session session) {

            System.out.println(session.getId() + " has opened a connection");

            Map<String, String> queryParams = getQueryMap(session.getQueryString());

            String name = "";

            if (queryParams.containsKey("name")) {

                // Getting client name via query param
                name = queryParams.get("name");
                try {
                    name = URLDecoder.decode(name, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                // Mapping client name and session id
                nameSessionPair.put(session.getId(), name);
            }

            // Adding session to session list
            sessions.add(session);

            try {
                // Sending session id to the client that just connected
                session.getBasicRemote().sendText(
                        jsonUtils.getClientDetailsJson(session.getId(),
                                "Your session details"));
            } catch (IOException e) {
                e.printStackTrace();
            }

            // Notifying all the clients about new person joined
            sendMessageToAll(session.getId(), name, " joined conversation!", true,
                    false);

        }

        /**
         * method called when new message received from any client
         *
         * @param message
         *            JSON message from client
         * */
        @OnMessage
        public void onMessage(String message, Session session) {

            System.out.println("Message from " + session.getId() + ": " + message);

            String msg = null;

            // Parsing the json and getting message
            try {
                JSONObject jObj = new JSONObject(message);
                msg = jObj.getString("message");
            } catch (JSONException e) {
                e.printStackTrace();
            }

            // Sending the message to all clients
            sendMessageToAll(session.getId(), nameSessionPair.get(session.getId()),
                    msg, false, false);
        }

        /**
         * Method called when a connection is closed
         * */
        @OnClose
        public void onClose(Session session) {

            System.out.println("Session " + session.getId() + " has ended");

            // Getting the client name that exited
            String name = nameSessionPair.get(session.getId());

            // removing the session from sessions list
            sessions.remove(session);

            // Notifying all the clients about person exit
            sendMessageToAll(session.getId(), name, " left conversation!", false,
                    true);

        }

        /**
         * Method to send message to all clients
         *
         * @param sessionId
         * @param message
         *            message to be sent to clients
         * @param isNewClient
         *            flag to identify that message is about new person joined
         * @param isExit
         *            flag to identify that a person left the conversation
         * */
        private void sendMessageToAll(String sessionId, String name,
                String message, boolean isNewClient, boolean isExit) {

            // Looping through all the sessions and sending the message individually
            for (Session s : sessions) {
                String json = null;

                // Checking if the message is about new client joined
                if (isNewClient) {
                    json = jsonUtils.getNewClientJson(sessionId, name, message,
                            sessions.size());

                } else if (isExit) {
                    // Checking if the person left the conversation
                    json = jsonUtils.getClientExitJson(sessionId, name, message,
                            sessions.size());
                } else {
                    // Normal chat conversation message
                    json = jsonUtils
                            .getSendAllMessageJson(sessionId, name, message);
                }

                try {
                    System.out.println("Sending Message To: " + sessionId + ", "
                            + json);

                    s.getBasicRemote().sendText(json);
                } catch (IOException e) {
                    System.out.println("error in sending. " + s.getId() + ", "
                            + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    With this we have completed the socket server part. Now quickly we can build a web app to the test the socket server. Again building the web app is very simple. The complete web app can be built using basic web technologies like HTML, CSS & jQuery.

    4. Building The Web App (HTML, CSS & jQuery)
    To create the web app, we don’t have to create another project. This is the part of same socket server project, so follow the below steps in the same project.

    1. Create a file named style.css under WebContent ⇒ WEB-INF folder. This contains the css styles for the web UI.

    style.css
    body {
        padding: 0;
        margin: 0;
    }

    .body_container {
        width: 1000px;
        margin: 0 auto;
        padding: 0;
    }

    .clear {
        clear: both;
    }

    .green {
        color: #8aaf0d;
    }

    #header {
        margin: 0 auto;
        padding: 50px 0;
        text-align: center;
    }

    #header h1,#header p.online_count {
        font-family: 'Open Sans', sans-serif;
        font-weight: 300;
    }

    #header p.online_count {
        font-size: 18px;
        display: none;
    }

    .box_shadow {
        background: #f3f4f6;
        border: 1px solid #e4e4e4;
        -moz-box-shadow: 0px 0px 2px 1px #e5e5e5;
        -webkit-box-shadow: 0px 0px 2px 1px #e5e5e5;
        box-shadow: 0px 0px 2px 1px #e5e5e5;
    }

    #prompt_name_container {
        margin: 0 auto;
        width: 350px;
        text-align: center;
    }

    #prompt_name_container p {
        font-family: 'Open Sans', sans-serif;
        font-weight: 300;
        font-size: 24px;
        color: #5e5e5e;
    }

    #prompt_name_container #input_name {
        border: 1px solid #dddddd;
        padding: 10px;
        width: 250px;
        display: block;
        margin: 0 auto;
        outline: none;
        font-family: 'Open Sans', sans-serif;
    }

    #prompt_name_container #btn_join {
        border: none;
        width: 100px;
        display: block;
        outline: none;
        font-family: 'Open Sans', sans-serif;
        color: #fff;
        background: #96be0e;
        font-size: 18px;
        padding: 5px 20px;
        margin: 15px auto;
        cursor: pointer;
    }

    #message_container {
        display: none;
        width: 500px;
        margin: 0 auto;
        background: #fff;
        padding: 15px 0 0 0;
    }

    #messages {
        margin: 0;
        padding: 0;
        height: 300px;
        overflow: scroll;
        overflow-x: hidden;
    }

    #messages li {
        list-style: none;
        font-family: 'Open Sans', sans-serif;
        font-size: 16px;
        padding: 10px 20px;
    }

    #messages li.new,#messages li.exit {
        font-style: italic;
        color: #bbbbbb;
    }

    #messages li span.name {
        color: #8aaf0d;
    }

    #messages li span.red {
        color: #e94e59;
    }

    #input_message_container {
        margin: 40px 20px 0 20px;
    }

    #input_message {
        background: #f0f0f0;
        border: none;
        font-size: 20px;
        font-family: 'Open Sans', sans-serif;
        outline: none;
        padding: 10px;
        float: left;
        margin: 0;
        width: 348px;
    }

    #btn_send {
        float: left;
        margin: 0;
        border: none;
        color: #fff;
        font-family: 'Open Sans', sans-serif;
        background: #96be0e;
        outline: none;
        padding: 10px 20px;
        font-size: 20px;
        cursor: pointer;
    }

    #btn_close {
        margin: 0;
        border: none;
        color: #fff;
        font-family: 'Open Sans', sans-serif;
        background: #e94e59;
        outline: none;
        padding: 10px 20px;
        font-size: 20px;
        cursor: pointer;
        width: 100%;
        margin: 30px 0 0 0;
    }

    2. Create another file named main.js and add below javascript. This file contains all the methods required to handle communication between socket server and client. The other things like parsing JSON, appending messages to chat list also taken care in the same file.

    main.js
    // to keep the session id
    var sessionId = '';

    // name of the client
    var name = '';

    // socket connection url and port
    var socket_url = '192.168.0.102';
    var port = '8080';

    $(document).ready(function() {

        $("#form_submit, #form_send_message").submit(function(e) {
            e.preventDefault();
            join();
        });
    });

    var webSocket;

    /**
    * Connecting to socket
    */
    function join() {
        // Checking person name
        if ($('#input_name').val().trim().length <= 0) {
            alert('Enter your name');
        } else {
            name = $('#input_name').val().trim();

            $('#prompt_name_container').fadeOut(1000, function() {
                // opening socket connection
                openSocket();
            });
        }

        return false;
    }

    /**
    * Will open the socket connection
    */
    function openSocket() {
        // Ensures only one connection is open at a time
        if (webSocket !== undefined && webSocket.readyState !== WebSocket.CLOSED) {
            return;
        }

        // Create a new instance of the websocket
        webSocket = new WebSocket("ws://" + socket_url + ":" + port
                + "/WebMobileGroupChatServer/chat?name=" + name);

        /**
         * Binds functions to the listeners for the websocket.
         */
        webSocket.onopen = function(event) {
            $('#message_container').fadeIn();

            if (event.data === undefined)
                return;

        };

        webSocket.onmessage = function(event) {

            // parsing the json data
            parseMessage(event.data);
        };

        webSocket.onclose = function(event) {
            alert('Error! Connection is closed. Try connecting again.');
        };
    }

    /**
    * Sending the chat message to server
    */
    function send() {
        var message = $('#input_message').val();

        if (message.trim().length > 0) {
            sendMessageToServer('message', message);
        } else {
            alert('Please enter message to send!');
        }

    }

    /**
    * Closing the socket connection
    */
    function closeSocket() {
        webSocket.close();

        $('#message_container').fadeOut(600, function() {
            $('#prompt_name_container').fadeIn();
            // clearing the name and session id
            sessionId = '';
            name = '';

            // clear the ul li messages
            $('#messages').html('');
            $('p.online_count').hide();
        });
    }

    /**
    * Parsing the json message. The type of message is identified by 'flag' node
    * value flag can be self, new, message, exit
    */
    function parseMessage(message) {
        var jObj = $.parseJSON(message);

        // if the flag is 'self' message contains the session id
        if (jObj.flag == 'self') {

            sessionId = jObj.sessionId;

        } else if (jObj.flag == 'new') {
            // if the flag is 'new', a client joined the chat room
            var new_name = 'You';

            // number of people online
            var online_count = jObj.onlineCount;

            $('p.online_count').html(
                    'Hello, <span class="green">' + name + '</span>. <b>'
                            + online_count + '</b> people online right now')
                    .fadeIn();

            if (jObj.sessionId != sessionId) {
                new_name = jObj.name;
            }

            var li = '<li class="new"><span class="name">' + new_name + '</span> '
                    + jObj.message + '</li>';
            $('#messages').append(li);

            $('#input_message').val('');

        } else if (jObj.flag == 'message') {
            // if the json flag is 'message', it means somebody sent the chat
            // message

            var from_name = 'You';

            if (jObj.sessionId != sessionId) {
                from_name = jObj.name;
            }

            var li = '<li><span class="name">' + from_name + '</span> '
                    + jObj.message + '</li>';

            // appending the chat message to list
            appendChatMessage(li);

            $('#input_message').val('');

        } else if (jObj.flag == 'exit') {
            // if the json flag is 'exit', it means somebody left the chat room
            var li = '<li class="exit"><span class="name red">' + jObj.name
                    + '</span> ' + jObj.message + '</li>';

            var online_count = jObj.onlineCount;

            $('p.online_count').html(
                    'Hello, <span class="green">' + name + '</span>. <b>'
                            + online_count + '</b> people online right now');

            appendChatMessage(li);
        }
    }

    /**
    * Appending the chat message to list
    */
    function appendChatMessage(li) {
        $('#messages').append(li);

        // scrolling the list to bottom so that new message will be visible
        $('#messages').scrollTop($('#messages').height());
    }

    /**
    * Sending message to socket server message will be in json format
    */
    function sendMessageToServer(flag, message) {
        var json = '{""}';

        // preparing json object
        var myObject = new Object();
        myObject.sessionId = sessionId;
        myObject.message = message;
        myObject.flag = flag;

      // converting json object to json string
        json = JSON.stringify(myObject);

        // sending message to server
        webSocket.send(json);
    }
    3. Now download jquery-1.11.1.min and the paste the file in WebContent ⇒ WEB-INF.

    4. Finally create another file named index.html and add below code.

    index.html
    <!DOCTYPE html>

    <html>
    <head>
    <title>Android, WebSockets Chat App | AndroidHive
        (www.androidhive.info)</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <script type="text/javascript" src="jquery-1.11.1.min.js"></script>
    <link
        href='http://fonts.googleapis.com/css?family=Open+Sans:400,600,300,700'
        rel='stylesheet' type='text/css'>
    <link href="style.css" type="text/css" rel='stylesheet' />
    <script type="text/javascript" src="main.js"></script>
    </head>
    <body>
        <div class="body_container">

            <div id="header">
                <h1>Android WebSockets Chat Application</h1>
                <p class='online_count'>
                    <b>23</b> people online right now
                </p>
            </div>

            <div id="prompt_name_container" class="box_shadow">
                <p>Enter your name</p>
                <form id="form_submit" method="post">
                    <input type="text" id="input_name" /> <input type="submit"
                        value="JOIN" id="btn_join">
                </form>
            </div>

            <div id="message_container" class="box_shadow">

                <ul id="messages">
                </ul>

                <div id="input_message_container">
                    <form id="form_send_message" method="post" action="#">
                        <input type="text" id="input_message"
                            placeholder="Type your message here..." /> <input type="submit"
                            id="btn_send" onclick="send();" value="Send" />
                        <div class="clear"></div>
                    </form>
                </div>
                <div>

                    <input type="button" onclick="closeSocket();"
                        value="Leave Chat Room" id="btn_close" />
                </div>

            </div>

        </div>

    </body>
    </html>

    5. Now run the project by Right Click on project ⇒ Run As ⇒ Run on Server. You can see the project running on http://localhost:8080/WebMobileGroupChatServer/

    5. Testing The Socket Server (using the web app)
    In order to test the socket server using the web app, follow below steps. You can use multiple devices (like desktop PC, Laptop) or just one machine is enough.

    1. Make sure that all the machines connected to same wifi router if you are testing the app on multiple machines. If you are testing the app using a single computer, you don’t have to connect to a wifi network.

    2. Find the IP address of the machine on which socket server project is running. (Follow the steps mentioned in 2nd point to get the ip address)

    3. Replace the ip address in main.js with your machine’s ip address.

    var socket_url = '_YOUR_IP_ADDRESS_';
    4. Now access your project url in browser. Replace localhost with your machine ip address in the url. My project url is http://192.168.0.104:8080/WebMobileGroupChatServer/. Access same url in another browser software or another machine’s browser to chat with different machines.

    WEB CHAT APP DEMO

    Once you are able to chat between multiple clients, we can go forward and build the android app in Android Building Group Chat App using Sockets – Part 2

  • In the 1st part, we have learned how to build the socket server and the web chat app. We also did tested the socket server using the web app.

    In this part we are going to build the next important component, i.e. android chat app. The app we are about to create will have two screens. The first screen will prompt the user to enter his/her name. This name is to identify the sender whenever a message is received. The second screen is to list the chat messages and to compose a new message.

    So let’s start the app by creating a new android project in Eclipse IDE.

    6. Building The Android Chat App
    1. In Eclipse create new android project by navigating to File ⇒ New ⇒ Android Application Project and fill out all the required details.

    I gave my project name as WebMobileGroupChat and package name as
    info.androidhive.webgroupchat.

    2. Add the below color values in res ⇒ values ⇒ colors.xml file.

    colors.xml
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <color name="actionbar">#3cb879</color>
        <color name="body_background">#e8e8e8</color>
        <color name="body_background_green">#82e783</color>
        <color name="server_status_bar">#2b2b2b</color>
        <color name="title_gray">#434343</color>
        <color name="white">#ffffff</color>
        <color name="bg_msg_you">#5eb964</color>
        <color name="bg_msg_from">#e5e7eb</color>
        <color name="msg_border_color">#a1a1a1</color>
        <color name="bg_btn_join">#1e6258</color>
        <color name="bg_msg_input">#e8e8e8</color>
        <color name="text_msg_input">#626262</color>
        <color name="lblFromName">#777777</color>
    </resources>

    3. Also add the below string values in res ⇒ values ⇒ strings.xml file.

    strings.xml
    <?xml version="1.0" encoding="utf-8"?>
    <resources>

        <string name="app_name">WebMobileGroupChat</string>
        <string name="title">(Android WebSockets Chat App)</string>
        <string name="author_name">By Ravi Tamada</string>
        <string name="author_url">www.androidhive.info</string>
        <string name="enter_name">Enter your name</string>
        <string name="btn_join">JOIN</string>
        <string name="btn_send">Send</string>

    </resources>

    4. Edit styles.xml located under res ⇒ values ⇒ styles.xml and add below styles. Here we are adding the styles for the action bar.

    styles.xml
    <resources>
     
        <style name="ChatAppTheme" parent="@android:style/Theme.Holo.Light">
            <item name="android:actionBarStyle">@style/MyActionBarTheme</item>
        </style>
     
        <style name="MyActionBarTheme" parent="@android:style/Widget.Holo.Light.ActionBar">
            <item name="android:background">@color/actionbar</item>
            <item name="android:titleTextStyle">@style/TitleTextStyle</item>
        </style>
        
         <style name="TitleTextStyle" parent="android:TextAppearance.Holo.Widget.ActionBar.Title">
            <item name="android:textColor">@color/white</item>
        </style>
     
    </resources>

    5. Now we need an activity to take the username that is required when connecting to socket server. So under res ⇒ layout folder create an xml file named activity_name.xml

    activity_name.xml
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/actionbar"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/imgLogo"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="60dp"
            android:src="@drawable/ic_launcher" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/imgLogo"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="15dp"
            android:text="@string/title"
            android:textColor="@color/white"
            android:textSize="13dp" />

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center_horizontal"
            android:orientation="vertical"
            android:padding="20dp" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:layout_marginTop="15dp"
                android:text="@string/enter_name"
                android:textColor="@color/white"
                android:textSize="18dp" />

            <EditText
                android:id="@+id/name"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:layout_marginTop="10dp"
                android:background="@color/white"
                android:inputType="textCapWords"
                android:padding="10dp" />

            <Button
                android:id="@+id/btnJoin"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="40dp"
                android:background="@color/bg_btn_join"
                android:paddingLeft="25dp"
                android:paddingRight="25dp"
                android:text="@string/btn_join"
                android:textColor="@color/white" />
        </LinearLayout>

      <!-- author info -->

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="20dp"
            android:gravity="center_horizontal"
            android:orientation="vertical" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/author_name"
                android:textColor="@color/white"
                android:textSize="12dp" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/author_url"
                android:textColor="@color/white"
                android:textSize="12dp" />
        </LinearLayout>

    </RelativeLayout>

    6. Create a new activity named NameActivity.java under project’s main package. In this activity we don’t handle anything complex. We just take the user input from EditText and send it to other activity.

    NameActivity.java
    package info.androidhive.webgroupchat;

    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;

    public class NameActivity extends Activity {

        private Button btnJoin;
        private EditText txtName;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_name);

            btnJoin = (Button) findViewById(R.id.btnJoin);
            txtName = (EditText) findViewById(R.id.name);

            // Hiding the action bar
            getActionBar().hide();

            btnJoin.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    if (txtName.getText().toString().trim().length() > 0) {

                        String name = txtName.getText().toString().trim();

                        Intent intent = new Intent(NameActivity.this,
                                MainActivity.class);
                        intent.putExtra("name", name);

                        startActivity(intent);

                    } else {
                        Toast.makeText(getApplicationContext(),
                                "Please enter your name", Toast.LENGTH_LONG).show();
                    }
                }
            });
        }
    }

    7. Finally make NameActivity.java as launcher activity in AndroidManifest.xml. Also add INTERNET permission as we need to make internet calls. This is how your manifest file should look like.

    AndroidManifest.xml
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="info.androidhive.webgroupchat"
        android:versionCode="1"
        android:versionName="1.0" >

        <uses-sdk
            android:minSdkVersion="13"
            android:targetSdkVersion="21" />

        <uses-permission android:name="android.permission.INTERNET" />

        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/ChatAppTheme" >
            <activity
                android:name=".NameActivity"
                android:label="@string/app_name"
                android:windowSoftInputMode="adjustPan" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity
                android:name=".MainActivity"
                android:screenOrientation="portrait" >
            </activity>
        </application>

    </manifest>

    After doing the above changes, if you run the app, you should see the name activity launched as first activity. Below is the output of name activity where user can enter their name and move to next activity.

    Before going to implement sockets, I would like to create few resource files first which required to create messages interface.

    8. Download this background image and paste it in project’s res ⇒ drawable folder. (If you don’t see drawable folder, create a new one and name it as drawable). This image will be used as background repeat image for the chat conversation.

    9. Create 3 new xml files under drawable folder named tile_bg.xml, bg_msg_from.xml and bg_msg_you.xml and add below codes. These drawable xml files are used as background for chat messages.

    tile_bg.xml
    <?xml version="1.0" encoding="utf-8"?>
    <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
      android:src="@drawable/bg_messages"
      android:tileMode="repeat" />
    bg_msg_from.xml
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle" >

        <!-- view background color -->
        <solid android:color="@color/bg_msg_from" >
        </solid>

        <corners android:radius="5dp" >
        </corners>

    </shape>

    bg_msg_you.xml
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle" >

        <!-- view background color -->
        <solid android:color="@color/bg_msg_you" >
        </solid>

        <corners android:radius="5dp" >
        </corners>

    </shape>

    10. Now under res ⇒ layout folder create two more xml files named list_item_message_left.xml and list_item_message_right.xml. These two layout files are used to align chat messages on left and right in the list view.

    list_item_message_left.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="5dp"
        android:paddingTop="5dp"
        android:paddingLeft="10dp">

        <TextView
            android:id="@+id/lblMsgFrom"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12dp"
            android:textColor="@color/lblFromName"
            android:textStyle="italic"
            android:padding="5dp"/>

        <TextView
            android:id="@+id/txtMsg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16dp"
            android:layout_marginRight="80dp"
            android:textColor="@color/title_gray"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="5dp"
            android:paddingBottom="5dp"
            android:background="@drawable/bg_msg_from"/>

    </LinearLayout>
    list_item_message_right.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="right"
        android:orientation="vertical"
        android:paddingBottom="5dp"
        android:paddingRight="10dp"
        android:paddingTop="5dp" >

        <TextView
            android:id="@+id/lblMsgFrom"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:textColor="@color/lblFromName"
            android:textSize="12dp"
            android:textStyle="italic" />

        <TextView
            android:id="@+id/txtMsg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="80dp"
            android:background="@drawable/bg_msg_you"
            android:paddingBottom="5dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="5dp"
            android:textColor="@color/white"
            android:textSize="16dp" />

    </LinearLayout>

    11. Now we need to create another layout to list all the chat messages and an option to compose a new message. Create another layout activity_main.xml and add below code.

    activity_main.xml
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/tile_bg"
        android:orientation="vertical" >

        <ListView
            android:id="@+id/list_view_messages"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@null"
            android:divider="@null"
            android:transcriptMode="alwaysScroll"
            android:stackFromBottom="true">
        </ListView>

        <LinearLayout
            android:id="@+id/llMsgCompose"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@color/white"
            android:orientation="horizontal"
            android:weightSum="3" >

            <EditText
                android:id="@+id/inputMsg"
                android:layout_width="0dp"
                android:layout_height="fill_parent"
                android:layout_weight="2"
                android:background="@color/bg_msg_input"
                android:textColor="@color/text_msg_input"
                android:paddingLeft="6dp"
                android:paddingRight="6dp"/>

            <Button
                android:id="@+id/btnSend"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="@color/bg_btn_join"
                android:textColor="@color/white"
                android:text="@string/btn_send" />
        </LinearLayout>

    </LinearLayout>

    12. With the above step, the creation of layout resources is done. Now we’ll quickly create few helper classes. In your project create a new package and name it as other.

    After creating the new package my package name will be info.androidhive.webgroupchat.other.

    13. In other package, create a class named Utils.java and add below code. This class contains methods to save the user’s session id in shared preferences.

    Utils.java
    package info.androidhive.webgroupchat.other;

    import org.json.JSONException;
    import org.json.JSONObject;

    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.SharedPreferences.Editor;

    public class Utils {

        private Context context;
        private SharedPreferences sharedPref;

        private static final String KEY_SHARED_PREF = "ANDROID_WEB_CHAT";
        private static final int KEY_MODE_PRIVATE = 0;
        private static final String KEY_SESSION_ID = "sessionId",
                FLAG_MESSAGE = "message";

        public Utils(Context context) {
            this.context = context;
            sharedPref = this.context.getSharedPreferences(KEY_SHARED_PREF,
                    KEY_MODE_PRIVATE);
        }

        public void storeSessionId(String sessionId) {
            Editor editor = sharedPref.edit();
            editor.putString(KEY_SESSION_ID, sessionId);
            editor.commit();
        }

        public String getSessionId() {
            return sharedPref.getString(KEY_SESSION_ID, null);
        }

        public String getSendMessageJSON(String message) {
            String json = null;

            try {
                JSONObject jObj = new JSONObject();
                jObj.put("flag", FLAG_MESSAGE);
                jObj.put("sessionId", getSessionId());
                jObj.put("message", message);

                json = jObj.toString();
            } catch (JSONException e) {
                e.printStackTrace();
            }

            return json;
        }

    }

    14. Create another class named Message.java. This model class defines each chat message where it contains message id, text and a boolean flag (isSelf) to define message owner. Using this boolean flag we’ll align message left or right in the list view.

    Message.java
    package info.androidhive.webgroupchat.other;

    public class Message {
        private String fromName, message;
        private boolean isSelf;

        public Message() {
        }

        public Message(String fromName, String message, boolean isSelf) {
            this.fromName = fromName;
            this.message = message;
            this.isSelf = isSelf;
        }

        public String getFromName() {
            return fromName;
        }

        public void setFromName(String fromName) {
            this.fromName = fromName;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public boolean isSelf() {
            return isSelf;
        }

        public void setSelf(boolean isSelf) {
            this.isSelf = isSelf;
        }

    }

    15. Create a class named WsConfig.java. This is where we define socket configuration i.e the socket url, port number and end point.

    WsConfig.java
    package info.androidhive.webgroupchat.other;

    public class WsConfig {
        public static final String URL_WEBSOCKET = "ws://192.168.0.102:8080/WebMobileGroupChatServer/chat?name=";
    }

    16. Now under your main package create a class named MessagesListAdapter.java to implement the custom list view adapter class. This class plays a major role in rendering the list by aligning the chat messages left or right.

    MessagesListAdapter.java
    package info.androidhive.webgroupchat;

    import info.androidhive.webgroupchat.other.Message;

    import java.util.List;

    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.TextView;

    public class MessagesListAdapter extends BaseAdapter {

        private Context context;
        private List<Message> messagesItems;

        public MessagesListAdapter(Context context, List<Message> navDrawerItems) {
            this.context = context;
            this.messagesItems = navDrawerItems;
        }

        @Override
        public int getCount() {
            return messagesItems.size();
        }

        @Override
        public Object getItem(int position) {
            return messagesItems.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @SuppressLint("InflateParams")
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            /**
             * The following list not implemented reusable list items as list items
             * are showing incorrect data Add the solution if you have one
             * */

            Message m = messagesItems.get(position);

            LayoutInflater mInflater = (LayoutInflater) context
                    .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

            // Identifying the message owner
            if (messagesItems.get(position).isSelf()) {
                // message belongs to you, so load the right aligned layout
                convertView = mInflater.inflate(R.layout.list_item_message_right,
                        null);
            } else {
                // message belongs to other person, load the left aligned layout
                convertView = mInflater.inflate(R.layout.list_item_message_left,
                        null);
            }

            TextView lblFrom = (TextView) convertView.findViewById(R.id.lblMsgFrom);
            TextView txtMsg = (TextView) convertView.findViewById(R.id.txtMsg);

            txtMsg.setText(m.getMessage());
            lblFrom.setText(m.getFromName());

            return convertView;
        }
    }

    17. Download the android websockets library and extract somewhere. Thanks to Koush for writing such a useful library.

    18. Import the downloaded android websockets library into Eclipse workspace. Goto File ⇒ Import ⇒ Android ⇒ Existing Android Code Into Workspace and select the downloaded library project home directory.

    19. Now add this project as a Library to our project. Right Click on project ⇒
    Properties ⇒ Android (on left) ⇒ Add (on right, under Library section) and select the imported project.

    20. Finally open the main activity class (MainActivity.java) do the below changes. The below code very simple and everything is self explanatory.

    > A web socket is created using WebSocketClient class and it has all the callback methods like onConnect, onMessage and onDisconnect.

    > In onMessage method parseMessage() is called to parse the JSON received from the socket server.

    > In parseMessage() method, the purpose of JSON is identified by reading the flag value.

    > When a new message is received, the message is added to list view data source and adapter.notifyDataSetChanged() is called to update the chat list.

    > sendMessageToServer() method is used to send the message from android device to socket server.

    > playBeep() method is called to play device’s default notification sound whenever a new message is received.

    MainActivity.java
    package info.androidhive.webgroupchat;

    import info.androidhive.webgroupchat.other.Message;
    import info.androidhive.webgroupchat.other.Utils;
    import info.androidhive.webgroupchat.other.WsConfig;

    import java.net.URI;
    import java.net.URLEncoder;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Locale;

    import org.json.JSONException;
    import org.json.JSONObject;

    import android.app.Activity;
    import android.content.Intent;
    import android.media.Ringtone;
    import android.media.RingtoneManager;
    import android.net.Uri;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ListView;
    import android.widget.Toast;

    import com.codebutler.android_websockets.WebSocketClient;

    public class MainActivity extends Activity {

        // LogCat tag
        private static final String TAG = MainActivity.class.getSimpleName();

        private Button btnSend;
        private EditText inputMsg;

        private WebSocketClient client;

        // Chat messages list adapter
        private MessagesListAdapter adapter;
        private List<Message> listMessages;
        private ListView listViewMessages;

        private Utils utils;

        // Client name
        private String name = null;

        // JSON flags to identify the kind of JSON response
        private static final String TAG_SELF = "self", TAG_NEW = "new",
                TAG_MESSAGE = "message", TAG_EXIT = "exit";

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            btnSend = (Button) findViewById(R.id.btnSend);
            inputMsg = (EditText) findViewById(R.id.inputMsg);
            listViewMessages = (ListView) findViewById(R.id.list_view_messages);

            utils = new Utils(getApplicationContext());

      // Getting the person name from previous screen
            Intent i = getIntent();
            name = i.getStringExtra("name");

            btnSend.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    // Sending message to web socket server
                    sendMessageToServer(utils.getSendMessageJSON(inputMsg.getText()
                            .toString()));

                    // Clearing the input filed once message was sent
                    inputMsg.setText("");
                }
            });

            listMessages = new ArrayList<Message>();

            adapter = new MessagesListAdapter(this, listMessages);
            listViewMessages.setAdapter(adapter);

            /**
             * Creating web socket client. This will have callback methods
             * */
            client = new WebSocketClient(URI.create(WsConfig.URL_WEBSOCKET
                    + URLEncoder.encode(name)), new WebSocketClient.Listener() {
                @Override
                public void onConnect() {

                }

                /**
                 * On receiving the message from web socket server
                 * */
                @Override
                public void onMessage(String message) {
                    Log.d(TAG, String.format("Got string message! %s", message));

                    parseMessage(message);

                }

                @Override
                public void onMessage(byte[] data) {
                    Log.d(TAG, String.format("Got binary message! %s",
                            bytesToHex(data)));

                    // Message will be in JSON format
                    parseMessage(bytesToHex(data));
                }

                /**
                 * Called when the connection is terminated
                 * */
                @Override
                public void onDisconnect(int code, String reason) {

                    String message = String.format(Locale.US,
                            "Disconnected! Code: %d Reason: %s", code, reason);

                    showToast(message);

                    // clear the session id from shared preferences
                    utils.storeSessionId(null);
                }

                @Override
                public void onError(Exception error) {
                    Log.e(TAG, "Error! : " + error);

                    showToast("Error! : " + error);
                }

            }, null);

            client.connect();
        }

        /**
         * Method to send message to web socket server
         * */
        private void sendMessageToServer(String message) {
            if (client != null && client.isConnected()) {
                client.send(message);
            }
        }

        /**
         * Parsing the JSON message received from server The intent of message will
         * be identified by JSON node 'flag'. flag = self, message belongs to the
         * person. flag = new, a new person joined the conversation. flag = message,
         * a new message received from server. flag = exit, somebody left the
         * conversation.
         * */
        private void parseMessage(final String msg) {

            try {
                JSONObject jObj = new JSONObject(msg);

                // JSON node 'flag'
                String flag = jObj.getString("flag");

                // if flag is 'self', this JSON contains session id
                if (flag.equalsIgnoreCase(TAG_SELF)) {

                    String sessionId = jObj.getString("sessionId");

                    // Save the session id in shared preferences
                    utils.storeSessionId(sessionId);

                    Log.e(TAG, "Your session id: " + utils.getSessionId());

                } else if (flag.equalsIgnoreCase(TAG_NEW)) {
                    // If the flag is 'new', new person joined the room
                    String name = jObj.getString("name");
                    String message = jObj.getString("message");

                    // number of people online
                    String onlineCount = jObj.getString("onlineCount");

                    showToast(name + message + ". Currently " + onlineCount
                            + " people online!");
           } else if (flag.equalsIgnoreCase(TAG_MESSAGE)) {
                    // if the flag is 'message', new message received
                    String fromName = name;
                    String message = jObj.getString("message");
                    String sessionId = jObj.getString("sessionId");
                    boolean isSelf = true;

                    // Checking if the message was sent by you
                    if (!sessionId.equals(utils.getSessionId())) {
                        fromName = jObj.getString("name");
                        isSelf = false;
                    }

                    Message m = new Message(fromName, message, isSelf);

                    // Appending the message to chat list
                    appendMessage(m);

                } else if (flag.equalsIgnoreCase(TAG_EXIT)) {
                    // If the flag is 'exit', somebody left the conversation
                    String name = jObj.getString("name");
                    String message = jObj.getString("message");

                    showToast(name + message);
                }

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

        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            
            if(client != null & client.isConnected()){
                client.disconnect();
            }
        }

        /**
         * Appending message to list view
         * */
        private void appendMessage(final Message m) {
            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    listMessages.add(m);

                    adapter.notifyDataSetChanged();

                    // Playing device's notification
                    playBeep();
                }
            });
        }

        private void showToast(final String message) {

            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), message,
                            Toast.LENGTH_LONG).show();
                }
            });

        }

        /**
         * Plays device's default notification sound
         * */
        public void playBeep() {

            try {
                Uri notification = RingtoneManager
                        .getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
                Ringtone r = RingtoneManager.getRingtone(getApplicationContext(),
                        notification);
                r.play();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();

        public static String bytesToHex(byte[] bytes) {
            char[] hexChars = new char[bytes.length * 2];
            for (int j = 0; j < bytes.length; j++) {
                int v = bytes[j] & 0xFF;
                hexChars[j * 2] = hexArray[v >>> 4];
                hexChars[j * 2 + 1] = hexArray[v & 0x0F];
            }
            return new String(hexChars);
        }

    }

    Now if you run the app, you can see the below screen as main activity output.

    With this we have completed the android app part too.

    7. Testing the Web and Android App
    To test the android app you need two android mobiles or you can just use one android mobile and a web app. Follow below steps to test the android app.

    1. Make sure that all your devices are connected to same wifi network. If you are using two android mobiles, connect them to same wifi network.

    2. Get the ip address of the machine on which socket server is running. Follow 2nd step in Part1 tutorial to get the ip address of your machine.

    3. Replace the ip address in WsConfig.java and main.js with your machine IP address.

    4. Deploy the app on to android devices. If you are testing the app using web and android apps, open both the apps and test.

    The same conversation can be seen on web app too.

    I hope everyone could able to build the app without any hurdles. If you have any queries or suggestions, please do let me know in the comment section below.

Comments

The Visitors says
Download Free Software Latest Version