Instant Messaging in Android using XMPP(Openfire)
- Mobile
- Product & platform Engineering
Instant Messaging in Android using XMPP(Openfire)
Extensible Messaging and Presence Protocol (XMPP) is a communications protocol for message-oriented middleware based on XML (Extensible Markup Language).[1] It enables the near-real-time exchange of structured yet extensible data between any two or more network entities.
In this blog, we are taken Openfire server. Read more about Openfire here http://www.igniterealtime.org/. We divided in following part.
- Download Openfire
- Install Openfire
- Create a new Project and add dependency in build.gradle
- Create Chat Manager class
- Setup with Smack service
Download Openfire- Download Openfire from here http://www.igniterealtime.org/downloads/
Install Openfire- You need to follow few step for setup –http://mindbowser.com/openfire-installation-and-database-configuration/
Add dependency in build.gradle- Add the following dependency in build.gradle
compile 'org.igniterealtime.smack:smack-android-extensions:4.1.5' compile 'org.igniterealtime.smack:smack-tcp:4.1.5'
Build Chat Manager-
Create Connection-
XMPPTCPConnectionConfiguration.Builder config = XMPPTCPConnectionConfiguration.builder(); config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled); config.setServiceName(MyCommunityChatService.XMPP_SERVICE_NAME); config.setResource(MyCommunityChatService.XMPP_SERVICE_NAME); // Add host address here config.setHost(serverAddress); config.setPort(5222); config.setDebuggerEnabled(true); XMPPTCPConnection.setUseStreamManagementResumptiodDefault(true); XMPPTCPConnection.setUseStreamManagementDefault(true); mConnection = new XMPPTCPConnection(config.build());
Add Connection Listener –
XMPPConnectionListener connectionListener = new XMPPConnectionListener(); mConnection.addConnectionListener(connectionListener);
XmppConnection definition is –
public class XMPPConnectionListener implements ConnectionListener { @Override public void connected(final XMPPConnection mConnection) { Log.d("xmpp", "Connected!"); connected = true; if (!mConnection.isAuthenticated()) { login(); } } @Override public void connectionClosed() { Log.d("xmpp", "ConnectionCLosed!"); connected = false; chat_created = false; loggedin = false; } @Override public void connectionClosedOnError(Exception arg0) { 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; disconnect(); initialiseConnection(); } @Override public void reconnectionFailed(Exception arg0) { Log.d("xmpp", "ReconnectionFailed!"); connected = false; chat_created = false; loggedin = false; } @Override public void reconnectionSuccessful() { 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(mConnection).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(); } }
Setup Packet Reply Timeout-
// set packet reply timeout time mConnection.setPacketReplyTimeout(10000);
Add Reconnect Manager with Connection
// Add reconnect manager ReconnectionManager.getInstanceFor(mConnection).enableAutomaticReconnection(); ServerPingWithAlarmManager.onCreate(context); ServerPingWithAlarmManager.getInstanceFor(mConnection).setEnabled(true); ReconnectionManager.setEnabledPerDefault(true);
Add Ping Manager– Ping manager is ping to a server in fixed interval. If server replies as pong then the client is can communicate with a server. Other call callback onPingFalied method call
// Add ping manager here PingManager.getInstanceFor(mConnection).registerPingFailedListener(new PingFailedListener() { @Override public void pingFailed() { disconnect(); initialiseConnection(); } });
Add Stanza(Packet) listener with Connection-
mConnection.addAsyncStanzaListener(new StanzaListener() { private ChatMessage superMessage; private DelayInformation delayInformation; @Override public void processPacket(Stanza packet) throws SmackException.NotConnectedException { if (!packet.getFrom().contains(mConnection.getUser())) { Log.i("TAG", "processPacket: new packet received in service"); superMessage = ChatMessage.instanceOf(((Message) packet).getBody()); delayInformation = null; try { delayInformation = packet.getExtension("delay", "urn:xmpp:delay"); } catch (Exception e) { e.printStackTrace(); } if (delayInformation != null) { Date date = delayInformation.getStamp(); // set up message delay information here } // Message receive here } } }, new StanzaFilter() { @Override public boolean accept(Stanza stanza) { if (stanza instanceof Message) { if (stanza.hasExtension(ChatStateExtension.NAMESPACE)) { Intent intent = new Intent(); intent.setAction("composing"); intent.putExtra(stanza.getExtension(ChatStateExtension.NAMESPACE).getElementName(), stanza.getFrom()); // sendBroadcast(intent); } if (((Message) stanza).getBody() != null) { return true; } } return false; } });
Add Stanza (Packet) acknowledgment listener-
mConnection.addStanzaAcknowledgedListener(new StanzaListener() { @Override public void processPacket(Stanza packet) throws SmackException.NotConnectedException { if (packet instanceof Message) { if (packet.getError() != null) { // Mark Message un sent acknowledgment here } else { // Mark Message sent acknowledgment here } } } });
Connect with Openfire –
public void connect(final String caller) { AsyncTask<Void, Void, Boolean> connectionThread = new AsyncTask<Void, Void, Boolean>() { @Override protected synchronized Boolean doInBackground(Void... arg0) { if (mConnection.isConnected()) return false; isconnecting = true; Log.d("Connect() Function", caller + "=>connecting...."); try { mConnection.connect(); connected = true; } catch (IOException e) { Log.e("(" + caller + ")", "IOException: " + e.getMessage()); } catch (SmackException e) { Log.e("(" + caller + ")", "SMACKException: " + e.getMessage()); } catch (XMPPException e) { Log.e("connect(" + caller + ")", "XMPPException: " + e.getMessage()); } return isconnecting = false; } }; connectionThread.execute(); }
Login in Openfire –
public void login() { try { mConnection.login(loginUser, passwordUser); // Set the status to available Presence presence = new Presence(Presence.Type.available); mConnection.sendPacket(presence); Log.i("LOGIN", "Yey! We're connected to the Xmpp server!" + loginUser); } catch (XMPPException | SmackException | IOException e) { e.printStackTrace(); } catch (Exception e) { } }
Add Delivery Receipt with Message
DeliveryReceiptManager deliveryReceiptManager = DeliveryReceiptManager.getInstanceFor(mConnection); deliveryReceiptManager.autoAddDeliveryReceiptRequests(); deliveryReceiptManager.setAutoReceiptMode(DeliveryReceiptManager.AutoReceiptMode.always); deliveryReceiptManager.addReceiptReceivedListener(new ReceiptReceivedListener() { @Override public void onReceiptReceived(String fromJid, String toJid, String receiptId, Stanza receipt) { // Mark delivered here Message message = new Message(); message.setStanzaId(receipt.getStanzaId()); // message.setType(Message.Type.headline); try { ChatManager.getInstanceFor(mConnection) .createChat("admin" + MyCommunityChatService.JID_SUFFIX) .sendMessage(message); } catch (SmackException.NotConnectedException e) { e.printStackTrace(); } } });
Disconnect with server
public void disconnect() { new Thread(new Runnable() { @Override public void run() { mConnection.disconnect(); } }).start(); }
Send One to One Message
public void sendOneToOneMessage(ChatMessage message) { if (!chat_created) { oneToOneChat = ChatManager.getInstanceFor(mConnection).createChat(message.getReceiver()); chat_created = true; } final Message chatMessage = new Message(); chatMessage.setBody(message.toString()); chatMessage.setStanzaId(message.getMsgid()); chatMessage.setType(Message.Type.chat); try { oneToOneChat.sendMessage(chatMessage); } catch (SmackException.NotConnectedException e) { e.printStackTrace(); disconnect(); init(); } }
Chat Message definition
public class ChatMessage { public String body, sender, receiver, senderName; public String Date, Time; public String msgid; public boolean isMine;// Did I send the message. public ChatMessage() { } public ChatMessage(String Sender, String Receiver, String messageString, String ID, boolean isMINE) { body = messageString; isMine = isMINE; sender = Sender; msgid = ID; receiver = Receiver; senderName = sender; } public static ChatMessage instanceOf(String messageString) { if (messageString == null) { return new ChatMessage(); } else { return new Gson().fromJson(messageString, ChatMessage.class); } public void setMsgID() { msgid += "-" + String.format("%02d", new Random().nextInt(100)); } public String getBody() { return body; } public void setBody(String body) { this.body = body; } public String getSender() { return sender; } public void setSender(String sender) { this.sender = sender; } public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this.receiver = receiver; } public String getSenderName() { return senderName; } public void setSenderName(String senderName) { this.senderName = senderName; } public String getDate() { return Date; } public void setDate(String date) { Date = date; } public String getTime() { return Time; } public void setTime(String time) { Time = time; } public String getMsgid() { return msgid; } public void setMsgid(String msgid) { this.msgid = msgid; } public boolean isMine() { return isMine; } public void setMine(boolean mine) { isMine = mine; } }
Now your complete code look like below code
public class XmppChatManager { public static boolean connected = false; public boolean loggedin = false; public static boolean isconnecting = false; private boolean chat_created = false; private String serverAddress; public static XMPPTCPConnection mConnection; public static String loginUser; public static String passwordUser; Gson gson; SmackService context; public static XmppChatManager instance = null; public static boolean instanceCreated = false; public static final String TAG = "Smack Service"; public XmppChatManager(SmackService context, String serverAdress, String logiUser, String passwordser) { this.serverAddress = serverAdress; this.loginUser = logiUser; this.passwordUser = passwordser; this.context = context; init(); } public static XmppChatManager getInstance(SmackService context, String server, String user, String pass) { if (instance == null) { instance = new XmppChatManager(context, server, user, pass); instanceCreated = true; } return instance; } public static org.jivesoftware.smack.chat.Chat oneToOneChat; public static MultiUserChat groupChat; static { try { Class.forName("org.jivesoftware.smack.ReconnectionManager"); } catch (ClassNotFoundException ex) { // problem loading reconnection manager } } public void init() { gson = new Gson(); //mMessageListener = new MMessageListener(context); //mChatManagerListener = new ChatManagerListenerImpl(); initialiseConnection(); } public static XMPPTCPConnection getConnection() { return mConnection; } private void initialiseConnection() { // Add SSL certificate SASLAuthentication.blacklistSASLMechanism("SCRAM-SHA-1"); SASLAuthentication.blacklistSASLMechanism("DIGEST-MD5"); SASLAuthentication.unBlacklistSASLMechanism("PLAIN"); XMPPTCPConnectionConfiguration.Builder config = XMPPTCPConnectionConfiguration.builder(); config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled); config.setServiceName(MyCommunityChatService.XMPP_SERVICE_NAME); config.setResource(MyCommunityChatService.XMPP_SERVICE_NAME); config.setHost(serverAddress); config.setPort(5222); config.setDebuggerEnabled(true); XMPPTCPConnection.setUseStreamManagementResumptiodDefault(true); XMPPTCPConnection.setUseStreamManagementDefault(true); mConnection = new XMPPTCPConnection(config.build()); XMPPConnectionListener connectionListener = new XMPPConnectionListener(); mConnection.addConnectionListener(connectionListener); mConnection.setUseStreamManagement(true); // set packet reply timeout time mConnection.setPacketReplyTimeout(10000); // Add reconnect manager ReconnectionManager.getInstanceFor(mConnection).enableAutomaticReconnection(); ServerPingWithAlarmManager.onCreate(context); ServerPingWithAlarmManager.getInstanceFor(mConnection).setEnabled(true); ReconnectionManager.setEnabledPerDefault(true); // Add ping manager here PingManager.getInstanceFor(mConnection).registerPingFailedListener(new PingFailedListener() { @Override public void pingFailed() { disconnect(); initialiseConnection(); } }); addStanzaListner(); } public void disconnect() { new Thread(new Runnable() { @Override public void run() { mConnection.disconnect(); } }).start(); } public void connect(final String caller) { AsyncTask<Void, Void, Boolean> connectionThread = new AsyncTask<Void, Void, Boolean>() { @Override protected synchronized Boolean doInBackground(Void... arg0) { if (mConnection.isConnected()) return false; isconnecting = true; Log.d("Connect() Function", caller + "=>connecting...."); try { mConnection.connect(); DeliveryReceiptManager deliveryReceiptManager = DeliveryReceiptManager.getInstanceFor(mConnection); deliveryReceiptManager.autoAddDeliveryReceiptRequests(); deliveryReceiptManager.setAutoReceiptMode(DeliveryReceiptManager.AutoReceiptMode.always); deliveryReceiptManager.addReceiptReceivedListener(new ReceiptReceivedListener() { @Override public void onReceiptReceived(String fromJid, String toJid, String receiptId, Stanza receipt) { // Mark delivered here Message message = new Message(); message.setStanzaId(receipt.getStanzaId()); // message.setType(Message.Type.headline); try { ChatManager.getInstanceFor(mConnection) .createChat("admin" + MyCommunityChatService.JID_SUFFIX) .sendMessage(message); } catch (SmackException.NotConnectedException e) { e.printStackTrace(); } } }); connected = true; } catch (IOException e) { Log.e("(" + caller + ")", "IOException: " + e.getMessage()); } catch (SmackException e) { Log.e("(" + caller + ")", "SMACKException: " + e.getMessage()); } catch (XMPPException e) { Log.e("connect(" + caller + ")", "XMPPException: " + e.getMessage()); } return isconnecting = false; } }; connectionThread.execute(); } public void login() { try { mConnection.login(loginUser, passwordUser); // Set the status to available Presence presence = new Presence(Presence.Type.available); mConnection.sendPacket(presence); Log.i("LOGIN", "Yey! We're connected to the Xmpp server!" + loginUser); } catch (XMPPException | SmackException | IOException e) { e.printStackTrace(); } catch (Exception e) { } } public void sendOneToOneMessage(ChatMessage message) { if (!chat_created) { oneToOneChat = ChatManager.getInstanceFor(mConnection).createChat(message.getReceiver()); chat_created = true; } final Message chatMessage = new Message(); chatMessage.setBody(message.toString()); chatMessage.setStanzaId(message.getMsgid()); chatMessage.setType(Message.Type.chat); try { oneToOneChat.sendMessage(chatMessage); } catch (SmackException.NotConnectedException e) { e.printStackTrace(); disconnect(); init(); } } public class XMPPConnectionListener implements ConnectionListener { @Override public void connected(final XMPPConnection mConnection) { Log.d("xmpp", "Connected!"); connected = true; if (!mConnection.isAuthenticated()) { login(); } } @Override public void connectionClosed() { Log.d("xmpp", "ConnectionCLosed!"); connected = false; chat_created = false; loggedin = false; } @Override public void connectionClosedOnError(Exception arg0) { 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; disconnect(); initialiseConnection(); } @Override public void reconnectionFailed(Exception arg0) { Log.d("xmpp", "ReconnectionFailed!"); connected = false; chat_created = false; loggedin = false; } @Override public void reconnectionSuccessful() { 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(mConnection).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(); } } private void addStanzaListner() { mConnection.addAsyncStanzaListener(new StanzaListener() { private ChatMessage superMessage; private DelayInformation delayInformation; @Override public void processPacket(Stanza packet) throws SmackException.NotConnectedException { if (!packet.getFrom().contains(mConnection.getUser())) { Log.i("TAG", "processPacket: new packet received in service"); superMessage = ChatMessage.instanceOf(((Message) packet).getBody()); delayInformation = null; try { delayInformation = packet.getExtension("delay", "urn:xmpp:delay"); } catch (Exception e) { e.printStackTrace(); } if (delayInformation != null) { Date date = delayInformation.getStamp(); // set up message delay information here } // Message receive here } } }, new StanzaFilter() { @Override public boolean accept(Stanza stanza) { if (stanza instanceof Message) { if (stanza.hasExtension(ChatStateExtension.NAMESPACE)) { Intent intent = new Intent(); intent.setAction("composing"); intent.putExtra(stanza.getExtension(ChatStateExtension.NAMESPACE).getElementName(), stanza.getFrom()); // sendBroadcast(intent); } if (((Message) stanza).getBody() != null) { return true; } } return false; } }); mConnection.addStanzaAcknowledgedListener(new StanzaListener() { @Override public void processPacket(Stanza packet) throws SmackException.NotConnectedException { if (packet instanceof Message) { if (packet.getError() != null) { // Mark Message un sent acknowledgment here } else { // Mark Message sent acknowledgment here } } } }); } }
Background Service that makes Connection alive.
public class SmackService extends Service { private boolean mActive; private Thread mThread; private Handler mHandler; String userName="username52",password="Password123"; private XmppChatManager xmppConnection; private static XMPPTCPConnection mConnection; public SmackService() { } public static void start(Context context) { Intent intent = new Intent(context, SmackService.class); context.startService(intent); } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { mConnection = XmppConnection.getConnection(); if (isConnectingToInternet()) { start(); } return Service.START_STICKY; } @Override public void onDestroy() { super.onDestroy(); stop(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } public void start() { if (!mActive) { mActive = true; // Create ConnectionThread Loop if (mThread == null || !mThread.isAlive()) { mThread = new Thread(new Runnable() { @Override public void run() { Looper.prepare(); mHandler = new Handler(); initConnection(); Looper.loop(); } }); mThread.start(); } } } public void stop() { mActive = false; } private void initConnection() { if (mConnection == null) { xmppConnection = XmppChatManager.getInstance(this, XMPP_HOST, userName, userName); xmppConnection.connect(userName); } else { } } public boolean isConnectingToInternet() { ConnectivityManager connectivity = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivity != null) { NetworkInfo[] info = connectivity.getAllNetworkInfo(); if (info != null) { for (int i = 0; i < info.length; i++) if (info[i].getState() == NetworkInfo.State.CONNECTED) { return true; } } } return false; } }
- Next step Code
Related content
Toll mangement and command centre with TMCC
We’re passionately committed to helping our clients and their customers thrive, working side by side to drive customer value and results..
A Smarter Health Safety Solution
We’re passionately committed to helping our clients and their customers thrive, working side by side to drive customer value and results..
Building fastest loan portal in India
We’re passionately committed to helping our clients and their customers thrive, working side by side to drive customer value and results..
Toll mangement and command centre with TMCC
We’re passionately committed to helping our clients and their customers thrive, working side by side to drive customer value and results...
Toll mangement and command centre with TMCC
We’re passionately committed to helping our clients and their customers thrive, working side by side to drive customer value and results..
Entreprise IT Transformation and Automation
We understand user and market, create product strategy and design experience for customers and employees to make breakthrough digital products and services