How to send ping using Eclipse Paho MQTT client? - android

We've just started building our own push notification system (due to client's requirement) for Android and found Eclipse Paho (http://www.eclipse.org/paho/). Needless to say, this project is really exciting.
The problem with Android is, if the CPU is in sleep state, the MQTT client may not get the chance to send ping at its set interval. The workaround is using AlarmManager to wake it up and get the job done. The Android documentation says:
The Alarm Manager holds a CPU wake lock as long as the alarm
receiver's onReceive() method is executing. This guarantees that the
phone will not sleep until you have finished handling the broadcast.
Once onReceive() returns, the Alarm Manager releases this wake lock.
This means that the phone will in some cases sleep as soon as your
onReceive() method completes.
http://developer.android.com/reference/android/app/AlarmManager.html
I need to be sure that I could send the ping command within that onReceive() method while the CPU has PARTIAL_WAKE_LOCK, so I was searching a way to manually sending ping to server but it seems the client doesn't expose any such method. Am I missing something? Or, what is the workaround here except publishing my own "ping message"? I want to avoid that because of:
Larger overhead
We'll ensure that Android clients are subscriber only, may be with Mosquitto's ACL. They will not be allowed to publish messages.

I've been doing some work with MQTT on Android and I've experienced exactly the same issue.
As Dale says, the old version of the MQTT client used to have an explicit ping() method, but unfortunately this is now hidden away.
The simplest approach, and the one I use, is to explicitly publish a 1 byte message to a particular topic, to serve as the keepalive. I don't think this should add much to the overhead of your application and, while I'm not familiar with Mosquitto's ACL, I assume you could have every client use the same 'keepalive' topic and just provide write access to all. This shouldn't affect security as long as no-one can read from the topic.
An alternative approach would be to have the server send the client(s) a 'keepalive' message at QoS 1 or 2 (pub/sub through a single topic to all for efficiency) as, due to the QoS flows, this will involve the client sending a message back to the server under the covers; which will serve as the keepalive. This has the advantage of keeping your clients as subscriber only; however it's incompatible with 'clean session = false' (as you would have large amounts of messages queued up for delivery to clients who are offline for a while - needlessly affecting performance on reconnect).
Unfortunately these are the only two workarounds that I can currently think of.
Also, as a brief aside, I've experienced a number of issues using the MqttDefaultFilePersistence on Android, so you might want to be aware of this. In particular to do with file locking and problems when re-instantiating the client. To get around this I've created an implementation of MqttClientPersistence built on top of an SQLite database and this is much more robust; you might want to do the same.

I came across this issue when writing MQTT apps for Android a year or so ago. I've written about it at some length at http://dalelane.co.uk/blog/?p=1599 but in short, yes - I saw the same problem that you describe where if the CPU is asleep when the MQTT client should send it's ping, then the ping never gets sent.
The difference is that I was using a different MQTT client library to you (this was before the days of Paho), and the client library that I used did have a ping() method that I could call. (The full source for my implementation is at that link, and it does solve this problem).
Can you not extend the implementation of the Paho client library to include the PING command? I assume it should be a reasonably small modification.

There is a way to modify the paho code and make a ping at any time. If we use publishing topic to keep alive, we have to send at least 7 or 8 bytes to server. Yes, 8 bytes is still not big data. But the heartbeat of MQTT is only 2bytes. We have lost the best advantage of MQTT.
Look deeply into the paho code, I modify it and write a public method named nnnn() in MQTTClient. This method could send MqttPingReq to th server. the implemetation can be found here...https://github.com/chinesejie/paho-for-android

my solution:
(1) modify: ClientComms comms; from protected to public (in package org.eclipse.paho.client.mqttv3)
public class MqttAsyncClient implements IMqttAsyncClient { // DestinationProvider {
//...
public ClientComms comms; // Add by Ben for pingreq*
//...
}
(2) define new class: (derived from MqttClient)
public class MqttClient2 extends MqttClient {
public MqttClient2(String serverURI, String clientId, MqttClientPersistence persistence) throws MqttException {
super(serverURI, clientId, persistence);
}
public void pingreq() throws MqttException {
MqttDeliveryToken token = new MqttDeliveryToken(getClientId());
MqttPingReq pingMsg = new MqttPingReq();
aClient.comms.sendNoWait(pingMsg, token);
}
}
(3) anywhere, you can:
MqttClient2 mClient = new MqttClient2(url, mDeviceId, mDataStore);
mClient.pingreq();
hope this can be helpfull for you.

Related

Running a task in a Flutter app at certain times

Hello flutter/mobile developers,
I have a particular problem at hand and I need some advice. I need to create an app that will do a certain task at specific times of the day. The times will change daily, and it will get the updated times via a REST call at midnight (or at off peak hours). The task must at the scheduled time no matter what, even after device restart, etc. I have looked into this extensively and I'm coming away with the feeling that Flutter does not handle a scheduled task well, especially in iOS which can terminate an app for whatever reason.
The options I have looked into are:
workmanager (https://pub.dev/packages/workmanager/changelog): This seems the most promising, if not for the minimum frequency of 15 minutes, which is not enough for me. I would need to check every minute if it is time to do the task. Is there a way around this limitation?
Native solution. I have very little-to-no experience with native iOS and Android coding so I would not prefer this solution. But through some research I have seen some examples where a task can be scheduled through this approach.
Server side notification. This seems like a good solution on the surface, and I need advice on this. The calculation whether it is time to run the task will happen server-side, and a notification (through Firebase, for example) can be sent to the device, which will trigger the task to be run. Is this even feasible, will the device actually run code when it gets the notification?
So these are my options. Which doe you think is the most doable? If someone with more mobile experience than me can help me out I would appreciate it, maybe there is a better solution that the three I have proposed. Thank you.
The times will change daily, and it will get the updated times via a REST call at midnight (or at off peak hours).
This smells like bad architecture. Why?
You are DDOS'ing your update server at midnight (if you have many users in the same timezone). You can stagger your HTTP requests by a few seconds to fix this, but this is a band-aid, not a long term solution.
because you are inverting the dependency: It sounds like timing is the responsibility of the server (hence your clients call it to ask for the latest time). Your clients should not be the ones asking the server for updates, because now your client has 2 jobs: Schedule the schedule updates and also schedule the scheduled task for the user. Making clients ask the server is the wrong direction. You should send messages from the server to update the schedule on the device.
Even if you do poll the server for schedule updates, you should make the mobile app schedule notifications/ alarm at the time you want. Using silent notifications is a known workaround the limitations of background scheduling on iOS. On Android, WorkManager is not the right library, you should use AlarmManager.
Here is how another StackOverflow thought about using local notifications to solve the problem: They used flutter_local_notifications
Answering the bullet points
On Android, don't use WorkManager, use AlarmManager instead, or even better, schedule notifications. Having said there are some manufacturer specific quirks on Android, see the flutter_local_notifications docs:
Consequently, scheduled notifications may not work when the application is in the background on certain devices (e.g. by Xiaomi, Huawei). If you experience problems like this then this would be the reason why. As it's a restriction imposed by the OS, this is not something that can be resolved by the plugin.
Its not necessary to use Native code, notifications is a standard feature.
You can keep the polling architecture for now since its simpler (but dirtier). Even if you would so the server side architecture, I would send messages from server to client to only update the client side schedule, not to trigger work/ user alerts, otherwise you are making your application dependent on the internet when it doesn't sound like the internet is required (unlike social media notifications). This would lead to bad user experience for badly connected devices.
You can send Data Notifications through Firebase, and handle them with the onBackgroundMessage callback. See here: https://firebase.flutter.dev/docs/messaging/usage#background-messages
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
print("Handling a background message: ${message.messageId}");
}
void main() {
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyApp());
}
From the documentation (Android/Apple):
It must not be an anonymous function.
It must be a top-level function (e.g. not a class method which requires initialization).

Proper error handling when sending an XMPP push notification using go-gcm?

I'm using https://github.com/google/go-gcm to send push notifications from our Go backend to Android devices. Recently, these push notifications started failing because the call to SendXmpp() was returning with the following error:
write tcp <IP>:<port>-><IP>:<port>: write: connection timed out
Restarting the Go process that called SendXmpp() makes this error go away, and push notifications start working again. But of course, restarting the Go process isn't ideal. Is there something I can do explicitly to handle this kind of error? For instance, should I close the current XmppClient and retry sending the message, so that the retry instantiates a new XmppClient and opens a new connection?
I would recommend using or implementing a (exponential) backoff. There are a number of options on GitHub here; https://github.com/search?utf8=%E2%9C%93&q=go+backoff though that's surely not a comprehensive list and it's not terribly difficult to implement.
The basic idea is you pass the function you'd like to call in to the back off function which calls it until it hits a max failures limit or it succeeds. Between each failure the amount of time waited is increased. If you're hammering a server, causing it to return errors, a method like this will typically solve your problems and make your application more reliable.
Additionally, I'd recommending looking for one that has an abort feature. This can be implemented fairly easily in Go by passing a channel into the backoff function (with the function you want to call). Then if your app needs to stop you can signal on the abort channel so that the back off isn't sitting there with like a 300 second wait.
Even if this doesn't resolve your specific problem it will generally have a positive effect on your apps reliability and 3rd party API's you interact with (don't want to DOS your partners).

Paho's MQTT client disconnects after the device locks

I'm currently working on a small "Panic Button" app supposed to operate in a medical facility. As one of the project's assumptions is to be Internet-independent, I've decided to go for MQTT with a server set up in the local WLAN.
I've implemented the Paho Android Service and it works pretty good. Up to a certain point. Once I lock the device and turn off the sreen, exactly after one minute the client gets disconnected. As I've set MQTT options to KeepAlive interval of 30s, this must be caused by Android itself, probably going into its lock-sleep. I'm obtaining the same results on couple of different smartphones, so it is probably also not user settings - related.
I'd rather avoid setting up an auto-reconnect procedure in
public class ServerCallback implements MqttCallback
{
public void connectionLost(Throwable cause) {
...
}
}
Because I want to use this method to prompt an error dialog once connection is lost due to less predictable reasons.
If so, what options do I have to prevent this disconnection?
EDIT:
Additional observation of mine is that as long as the device is plugged in and charging, disconnection does not occur.
After googling around I think I found the reason:
The Paho MQTT client uses a TimerTask to schedule the keepalive ping. A TimerTask will stop when the phone goes to sleep, and is therefore a poor choice here... The implementation for the keepalive ping can be found in the class TimerPingSender which is derived from the MqttPingSender class.
In order to get timed events when the phone is sleeping, it must be triggered by the AlarmManager. The best solution to the problem I found was to make an alternative class derived from the MqttPingSender class. Before I started writing such a class myself, I googled and found someone who had already done it on GitHub.
It can be found here:
https://github.com/Suxsem/Domo-Android/blob/master/app/src/main/java/com/suxsem/domo/MqttPingSender.java
I also had to add an alternative constructor to MqttClient:
public MqttClient(String serverURI, String clientId, MqttClientPersistence persistence, MqttPingSender pingSender) throws MqttException {
aClient = new MqttAsyncClient(serverURI, clientId, persistence, pingSender);
}
and where I instantiate the MqttClient (in my Service) I do this:
MqttPingSender pingSender = new MqttPingSenderAlarm(this);
mqClient = new MqttClient("tcp://<IP>:<PORT>", "MyTestServiceID", new MemoryPersistence(), pingSender);
Until now this seems to work flawlessly, but I've only tested it 20-30 minutes.

Store HTTP/REST requests in case no connection is available

I am currently developing an android application using HTTP/REST requests to communicate with my backend. I am not using any particular library yet since until now the built-in HttpURLConnection works fine for me. However I would like to have some kind of fallback mechanism if my requests fail due connectivity issues. A similiar problem is also described in https://stackoverflow.com/questions/31786486/android-volley-internet-queue but has not been answered yet and other related posts rather focus on caching older responses to redirect requests to the cache when there is no connection is available.
Up to now I considered using Volley but as far as I understand it it only allows to retry a failed request until it finally connects. I think it would be a cleaner solution to cache the failed request and attempt to resend it after I registered a change in my connectivity state via a BroadcastReceiver. Is there an existing solution which does that for me or do I have to set up an internal database and manage the whole process myself ?
TL;DR
I want to store failed HTTP/REST requests on my android device when my device is offline and resend them when the device can establish a connection again. What am I looking for ?
I had the same situation with a reporting service. What I implemented was a Service that receives requests and queues them. In a separate thread (started when the service starts) it checks the queue and attempts to make the connection. If you use a BlockingQueue you have the 'signalling' between threads for free, so you don't need to idle-poll.
You can use set up a receiver for WifiManager.WIFI_STATE_CHANGED_ACTION and/or ConnectivityManager.CONNECTIVITY_ACTION events, so that you start the service or wake up the thread and attempt to re-send when the connection is up again.
I suggest a Service so you can detach all this from the code in your Activities and have some facilities for starting and stopping it. I personally used an IntentService because that allows me to serialize the requests through Intents, and let the OS handle the Intent management sending for me. You might implement it differently, even without a Service, just with a Singleton object.
If you also need storing them when your app is not running, I would use a SQLite Database.
As #Sebastian wrote you can write queue handler yourself, or perhaps check if existing implementations, like android-priority-jobqueue is not going to be useful for you.

What is long polling and how to use it in android For Chat Project

i need to know about long polling in android and how to Implementation at Android IDE(Eclipse, IntelliJ Idea, Android Studio) For Chat Project?
Regards
"LongPolling" is a technique which is often used for instant messaging
type applications. Requests from an application to a server, which does not
immediately have any result data, will 'block' from a return for a period of time.
This mechanism benefits applications as they will consume less bandwidth
and have to do less processing than if they had to repeatedly poll the server.
The design of long polling will depend upon whether you need it to run in background as well. if yes, a Service will suit you otherwise you can just start a thread like public void run() { }. I dont think long polling is really necesarry as it will keep on running and keep using the data think about a socket based chat app. Try to look at XMPP. Just a thought ;) .

Categories

Resources