Nowadays many mobile apps have push notifications, or at least have them on the roadmap for future versions. Unfortunately, the technical implementation of push notifications is a complex task. Testing is difficult because automating tests is cumbersome, and some platforms only allow push notifications on actual devices, and not on the developer’s workstation.
In many of our projects we have ended up implementing a proxy server that handles communications with upstream notification services. Unfortunately, due to IPRs (intellectual property rights, in practice copyrights) we have implemented similar functionality multiple times for different projects. This time we made arrangements to make this part of the code open source, and it is now available in GitHub.
An alternative to using a proxy server would be accessing Amazon SNS (or another similar service) directly from the mobile apps. However, we consider this to be worse for a few reasons. First, it requires putting platform credentials inside the mobile apps, which is potentially a security issue. Second, it ties a mobile app to a specific push notifications service, and changing the service would require updating the app for all users. Third, large parts of the implementation need to be redone multiple times, once for each platform (Android, iOS etc.). Fourth, service-specific constants (such as topic IDs and platform IDs) need to be included in the apps, or served from somewhere.
This push notification service supports Amazon SNS, and all push notification platforms supported by SNS: APNS for iOS, GCM for Android, MPNS and WNS for Windows Phone, Baidu for China, and ADM for Amazon’s Android devices. We have found SNS to be a trustworthy, easy to use and reasonably priced tool for integrating with multiple mobile platforms (Android, iOS, Windows Phone and others). Furthermore, we often use other resources from Amazon, which makes setup, maintenance and billing easier.
There are a few important decisions behind the design of this service:
Everything is as simple as possible. No optional functionality is implemented. For example, adding new platforms to the SNS configuration needs to be handled through the SNS console. Handling of SNS permissions is complicated, and is not implemented in this service.
Authentication is just a shared secret.
Authorization has only two hard-coded levels: mobile app and admin. Mobile apps can subscribe, unsubscribe, register and deregister, and fetch some generic information. An admin can publish push notifications, and add and delete topics.
The service is stateless. All client information and subscriptions are stored only in SNS. Scaling becomes straightforward and it does not matter whether some other service is making changes to SNS at the same time, as this service will just use whatever is in SNS.
The API provides common functionality out-of-the-box. For example, we have noticed a common use case where a mobile app needs to register for push notifications and subscribe to predefined topics. The device registration endpoint does exactly that.
There are no direct connections to any push notification services (such as APNS for Apple and GCM for Google). All communication goes through SNS. This way possible changes or updates to APNS or GCM and so on will not affect this service, as the updates will be implemented on SNS side. Furthermore, if SNS adds support for additional platforms, no changes are needed.
The idea with authentication levels — mobile app and admin — is that mobile applications do not contain any secrets that can be used to send notifications or to interfere with other clients. All API operations available to normal users require secrets that are only known by a specific device, so it is not possible to de-register another device or subscribe another device to additional topics.
The publishing API allows sending arbitrary data to each platform, as there are plenty of per-platform options. Thus it is more convenient to just pass through all the options, instead of trying to codify those to a custom format common to all the platforms.
Future development will mainly consist of maintenance, and probably adding some convenience APIs for common operations. It will not consist of adding every possible customization, option, and feature. Similarly, if there will be the need to support other platforms, such as PushWoosh or OneSignal, the same API should be reimplemented as a separate project, instead of making the codebase more complicated.