Android/Smack: Keep XMPP connection alive in sleep

2019-03-28 06:28发布

问题:

I have an Android application that has a chat client as one of its features. The chat client uses XMPP based on the Smack library for Android and running Openfire as XMPP server in the background. The connection is established using BOSH The whole XMPP connection handling is implemented as a service to run and listen in the background for incoming messages even if not activity of the app is in the foreground. So far, everything works perfectly fine.

The only problem seems to be the sleep mode. In the emulator (when set to "Stay Awake") or with the phone in use, the XMPP connections is holding and the app can send and receive messages. However, once the phone goes into sleep mode, the XMPP connection breaks down -- I can see it in the Admin Console of the Openfire server that the user is offline. Intuitively, I want to receive messages all the time like, e.g., WhatsApp.

Of course, I've searched online including Stackoverflow, but I couldn't get a definitive answer. Often the use case seems to be that a task has to be performed periodically, say, once every hour. But this doesn't seem to fir in case of a chat client. Since I assume this is a common use case -- after all, there a so many chat apps or apps with chat features out there -- these are my question:

  • How to I have to change / extend the app that I can receive chat message while the phone is sleeping?

  • I've stumbled upon WakeLock. Is this the way to go or are these not suitable for my use case?

  • Since Lollipop, there's also the JobScheduler API which itself uses WakeLock. Any better?

  • How does, for example, WhatsApp handles this case?

On a side note: I have problems with the sleep mode using the emulator for debugging. When I switch off "Stay Awake" in the emulator, the screen goes black after 1+ min and the XMPP connection breaks. But I somehow have no idea how to wake up / switch the emulator back on once it went black. Android Studio actually tells me at some point that the device or something is gone, and I have to restart the emulator again.

回答1:

The exact way to resolve this issue is by using push notification.

It is the natural behavior of XMPP connection to get disconnected after the specified idle interval i.e when the device goes to sleep.

Coming to the case of WhatsApp, it also uses the same XMPP and maintains a server which acts as a wrapper class on the messages exchanged. This server checks the message status whether it is delivered or not. If not delivered, it sends a push notification, now at the device end in the push service when a message is received, it checks if the connection is active and is authenticated or not.

If not authenticated, it re-establishes the connection. In this way, the most chat apps manage this timeout exception.

Hope this helps :)



回答2:

You don't need push notifications, you don't need WakeLocks. Instead simply

  • Whitelist your app from doze mode
  • Use a sticky (START_STICKY) background service
  • Use Smack's ServerPingWithAlarmManager
  • Act on CONNECTIVY_CHANGED intents send by Android, and use XMPPTCPConnection's instantShutdown() in that case.