Instant Messaging in Android using XMPP(Openfire)
- Digital Engineering
- Mobile
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
1 2 |
compile 'org.igniterealtime.smack:smack-android-extensions:4.1.5' compile 'org.igniterealtime.smack:smack-tcp:4.1.5' |
Build Chat Manager-
Create Connection-
1 2 3 4 5 6 7 8 9 10 11 12 |
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 –
1 2 |
XMPPConnectionListener connectionListener = new XMPPConnectionListener(); mConnection.addConnectionListener(connectionListener); |
XmppConnection definition is –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
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-
1 2 |
// set packet reply timeout time mConnection.setPacketReplyTimeout(10000); |
Add Reconnect Manager with Connection
1 2 3 4 5 |
// 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
1 2 3 4 5 6 7 |
// Add ping manager here PingManager.getInstanceFor(mConnection).registerPingFailedListener(new PingFailedListener() { @Override public void pingFailed() { disconnect(); initialiseConnection(); } }); |
Add Stanza(Packet) listener with Connection-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
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-
1 2 3 4 5 6 7 8 9 10 11 12 |
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 –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
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 –
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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
1 2 3 4 5 6 7 |
public void disconnect() { new Thread(new Runnable() { @Override public void run() { mConnection.disconnect(); } }).start(); } |
Send One to One Message
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
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
Auriga: Leveling Up for Enterprise Growth!
Auriga’s journey began in 2010 crafting products for India’s