I had to implement push notifications for an application that runs on both iOS and Android. We had Node.js running on the server, and I wanted to integrate the push notification functionality into it.
For some reason, working out all the moving parts and the flow of information involved in generating a push notification is rather tricky.
At the time of writing, the main options are:
The upside of node-apn + fcm-node is that it’s the least complicated solution in terms of dependencies. On the other hand, integrating two separate libraries wasn’t very appealing.
node-pushserver is a full fledged server rather than a library, so it has its own storage (MongoDB) but on the other hand it’s only meant to be hosted internally as it doesn’t have any security mechanisms. I would need to do a significant amount of rework to get it to work on Heroku together with Postgres, so this was a non-starter.
Next I looked at using third party services on top of the platform gateways: Pushwoosh, Urban Airship and Amazon SNS. Pushwoosh and Urban Airship didn’t seem to offer any clear advantage in terms of API or documentation over SNS, while SNS offers extra features because it supports other platforms (eg Windows) and delivery mechanisms (eg SMS) in addition to iOS and Android, which could become useful in the future. I ended up selecting SNS.
The resulting components in the system look like this:
In order to receive push notifications, the device has to register with its platform’s notification service:
Once it’s registered, here is how a notification gets sent:
Terminology:
When I was reading documentation on Android push notifications, I found references to FCM and GCM. GCM has been superseded by FCM, although GCM continues to function and this is actually what SNS relies on.
SNS doesn’t actually provide a uniform interface across platforms. Instead, separate payloads have to be specified for each platform unless you happen to be sending a simple text message:
payload =
default: message
APNS: JSON.stringify iosPayload
GCM: JSON.stringify androidPayload
sns.publish Message: JSON.stringify(payload), MessageStructure: "json", TargetArn: endpointArn
Note also that platform specific payloads have to be stringified, and then the whole combined payload has to be stringified before it’s sent to SNS.
Production and development on APNs have to be set up separately, leading to confusing results if the wrong push ID is used.
Ad hoc or production builds will be set up for production APNs access, whereas development builds will be set up for development APNs access.
When I was reading about APNs, I found references to a “feedback service”. This used to provide information about devices which have become inactive. However, it turns out that this has been removed, and individual requests to APNs now return a status. Consequently, APNs marks the device endpoint as inactive if it receives a failure response from APNs.
Action buttons have to be defined in the message payload, and there is some corresponding setup to be done on the mobile client side.
It’s apparently possible to use GCM on iOS as well as Android, but it’s not going to be as efficient because it isn’t built into the OS.
On Android, notifications can be marked as normal or high priority. The delivery of normal priority notifications can be delayed.