Introduction
This is a rather atypical way to achieve reliable push notifications, on a single Android device. It does not use Google Cloud Messaging for delivery, thus eliminates the problem of delayed or even lost notifications many of us struggle with when using GCM. On the other hand, unlike GCM, this solution is limited to a single receiving device at once.
The solution uses PAW web server for Android (open source) and a specific BeanShell script to transform web requests into native Android broadcast messages. This makes it ideal if you'd like to target a specific device with your push notifications. You just need a simple BroadcastReceiver
in your app and you're ready to go!
To make the target Android device visible even behind a strictly configured firewall, the solution uses PageKite for Android (open source) which works just fine on 3G/Wifi networks, with carriers which assign private IP addresses to your 3G-connected device (e.g. 10.0.0.3).
What It Is
An alternative way of sending push notifications to an Android device, useful for those who experience badly delayed and many times even completely lost push notifications through Google's own solution (GCM). With this alternative method, push notifications always arrive instantly, as soon as the web server processes a web request. This solution also supports devices older than Android 2.2 (no GCM used) and does not require rooting. It can be also a great resource for an example usage of BeanShell scripting.
Zero hacking is needed to get started.
What It Is Not
Not a full replacement for all features of GCM: mainly because this solution always targets a single device at a time.
If you don't mind setting up a server for Deacon, doing some hacks using MQTT or even utilizing a commercial solution instead, then this article is probably not for you.
Architecture
Any device capable of making web requests can be a push notification sender and any Android device can be a receiver of those push notifications.
Sender makes a web request like this:
(a quick free registration on PageKite is required when not running your own PageKite service)
http://YourName.pagekite.me/pushNotif.xhtml?message=TurnOnCommand
PageKite will redirect the web request to your Android device, even if it is on 3G or trapped behind NAT or strict firewalls. The PAW web server running on your device will process the request by executing the following BeanShell script:
import android.os.*;
import android.content.*;
service = server.props.get("serviceContext");
messageText = parameters.get("message");
intent = new Intent("com.KurAttila.pushToSingleAndroidDevice.WebServerMessage");
intent.putExtra("message", messageText);
service.sendBroadcast(intent);
This BeanShell script sends out a native Android OS broadcast - effectively transforming web requests into native Android OS broadcasts. Your Android application running on the same device can then capture that broadcast through its own, simple BroadcastReceiver
.
Using the Code
Steps to quickly get you up and running:
- Install PAW Server and PageKite (free registration required) on receiver device
- Copy the provided
pushNotif.xhtml
(contains BeanShell script) into /sdcard/paw/html
- Incorporate a simple
BroadcastReceiver
into your app code - like the following:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString("message");
MainActivity.this.onNotification(newMessage);
setResultCode(Activity.RESULT_OK);
}
}
Running the attached example will simply list all the notifications received:
Points of Interest
The basic idea emerged when designing a homebrew solution for gardening. I wanted a way to turn my old Android phone into an irrigation controller in my garden. The initial solution consisted of a polling based architecture: the Android device attached to the watering pump would retrieve some web storage content once every minute, to detect if there are any new "commands" to process (e.g. turn on watering, take a photo of the garden and upload it somewhere, turn off watering). It worked just fine, but the delays bothered me. So I gave a try to Google's push notifications, which happened to work OK - sometimes. And sometimes not. I've experienced heavily delayed and even never arriving notifications.
Instead of having those non-reliable push notifications, I've also tried to get away simply with much more frequent polling of commands ("messages"). This way, I could indeed detect new commands almost instantly, but given a very simple web response of around 250 bytes, being received every 3 seconds (to make it "instant"), the device would get a daily traffic of around 7 MB. Even if there's no new command, actually. This was just too much for that 3G data plan the device actually had, so I knew I needed another solution. Data usage of this web server-based solution indeed turned out to be much less.
In the meantime, I've also discovered several "push notification fixer" apps, which could indeed improve our unpleasant development experience with GCM. Unfortunately, they require Android 2.2+ and a rooted device - not a good match for my specific case.
History
- 2014-May-29: Initial version