Migrating from Parse Push Notifications

Several months ago Parse took everyone by surprise and informed developers that they would shut down all of their services by the end of January 2017. While the news initially seemed like an April Fool’s joke similar to their public announcement of Parse Pigeon, we disregarded the migration message that appeared in on the screen every time you logged into your Parse Dashboard:

The Parse hosted service will be retired on January 28, 2017. If you are planning to migrate an app, you need to begin work as soon as possible.

However after countless logins into the Parse Dashboard the message kept appearing in the topmost banner, almost as if laughing at us, and gradually we began coming to terms with the harsh reality – Parse was indeed shutting down and we were (again) forced to migrate our apps to a different Push Notifications provider. This is not new to us – we’ve been dealing with these kinds of migrations since early 2015 when we migrated one of our apps from Urban Airship to Parse.

Back then we had a single Android app that used Urban Airship to receive push notifications from a web application written in Rails. The notifications workflow was simple – the app user would receive a push notification every time an order was placed by a customer through the YouOrderIt platform. The Android app was intended for an administrative audience such as restaurant managers and admin staff and the push notifications simply contained basic order details. We built the app in October 2014 and selected Urban Airship as the push platform of choice because it was free and because we refused to evaluate other options – Urban seemed like a tried and tested choice so we picked it.

And then sometime in January 2015 Urban Airship began charging monthly fees for their services. We had been all along in the beggar’s free tier, which they couldn’t support anymore (I don’t think any provider truly achieves high margins in this push notifications business) so we got an email from Urban Airship Support to the effect that we had to pay a $200 monthly fee going forward. We didn’t have that kind of money to spare so we had to switch to something else (free) immediately.

A friend recommended Parse so we started looking into it. The platform seemed solid, very well documented and their Dashboard was more user friendly than Urban Airship’s. They also had a beggar’s free tier throttled up to 30 requests per second (RPS) and we were confident we would fall beneath that threshold since our apps were not experiencing load above 30 RPS. We migrated the Android app to Parse and experienced good push notifications performance and decent reliability. After this experience we decided to use Parse for our complete app portfolio.

So a couple of months ago while mourning Parse’s looming demise we were faced with a tough question: migrate to what? We were back again to the drawing board just like in the pre-Urban Airship days. For a complete month we deliberated the idea of implementing our own platform based on Amazon SNS, and we even studied technical guides on how to migrate from Parse to Amazon SNS (gruesome process), but we didn’t wish to become a push notifications technology provider. That would have further derailed us from our core focus.

We realized that no matter what we wouldn’t be able to come up with a flawed assessment that identified a perfect, always-free and long-lived push notifications platform. The #1 push notifications platform today might be dead one year from now (even if it’s backed by Amazon, Google or even Facebook – ironically, before announcing their shut-down Parse had been engulfed by Facebook), and that’s just a fact of the brutality of technology. Even if it doesn’t die the platform’s creator might wake up annoyed one day and decide to start charging monthly fees, giving you only two viable options – pay or get the hell out and migrate.

Given the fast-changing technology landscape we are constantly subjected to, we have to be willing to switch platforms ever year if possible and be prepared for the changes entailed with these migrations. We decided to switch to the next best FREE choice that catered to our requirements. So when another colleague recommended OneSignal, we checked it out and after noticing it was free and had a decent breadth of features, we decided to migrate to that.

Android Setup

From an Android standpoint migrating to OneSignal only entails a couple of code changes. Besides the OneSignal SDK setup, generation of a Google Server API Key and Gradle changes mentioned in the OneSignal documentation, you just need to add the following initialization method. Make sure this is called in your main Application’s onCreate() method:

void initOneSignal() {
    OneSignal.startInit(this).
              setNotificationOpenedHandler(notificationsHandler).
              setNotificationReceivedHandler(notificationsHandler).
              init();
}

In this example we are using a custom notifications handler but this is optional. For instance if your app only needs to display the push notification using the built-in behavior a custom notifications handler is not required. However if you need your app to perform custom logic every time a notification is received or opened, we recommend using a notifications handler:

public static PushNotificationsHandler notificationsHandler;

If you decide to use a custom notifications handler make sure you override the notificationReceived() and notificationOpened() methods depending on your notification handling requirements.

public class PushNotificationsHandler implements OneSignal.NotificationOpenedHandler, OneSignal.NotificationReceivedHandler {

    public PushNotificationsHandler() {
        super();
    }

    @Override
    public void notificationReceived(OSNotification notification) {
        // Handle notification received event here
    }

    @Override
    public void notificationOpened(OSNotificationOpenResult result) {
        // Handle notification opened event here
    }

}

That’s all for the basic code changes. However these code changes might not be enough to fully migrate your app and platform to the new notifications service. Consider the following situation – you make your code changes in your Android app to migrate from Parse to OneSignal and push the changes to Google Play Developer Console. If you already have users using a previous version of your app (the codebase of the previous version uses Parse or some other platform), they might opt to NOT update the app (which contains the new OneSignal code changes) for a while. You will be faced with a situation where different users are running different versions of your app – one Parse enabled and the other OneSignal enabled, and you have to support them both for business continuity’s sake.

As part of your business, if you are sending notifications to apps directly from the Admin Dashboard, this is simple since you can manually target these two audiences separately. However if you have a complex platform where notifications are sent from a web application that sends notifications to devices using the OneSignal API, you need to write logic to handle these 2 separate paths – the path to send notifications to devices using Parse and the other path where you send notifications via OneSignal. However this code will be temporary, once all of your users update their apps to the newest version using OneSignal, you just need to handle the OneSignal path.

We faced this situation with one of our apps. We have an e-commerce app that can be used to place orders. It is currently used by thousands of customers and was originally Parse-enabled. With the Parse implementation, when users placed orders the Android app would send order details to our platform’s RESTful JSON API, including the Parse device token of the user’s device placing the order. This info would be saved in a database server-side for later use. If an order was confirmed, the web app would read the order details (including the device token), and send a push notification to that specific device token using the Parse API. This was the Parse path. To handle OneSignal we made one small code change in the Android app – the app would send the device’s OneSignal userId instead (also known as playerId) to our platform’s API when sending order details. Retrieving the userId is simple, but you have to make sure you retrieve it after OneSignal successfully initializes. Also the implementation is asynchronous so your Android app needs to handle this non-blocking behavior gracefully:

// Call this inside your Android app if you need to retrieve the device's userId for later use

OneSignal.idsAvailable(new OneSignal.IdsAvailableHandler() {
    @Override
    public void idsAvailable(String userId, String registrationId) {
        if (userId != null) {
            // Save userId or registrationId
        }
    }
});

When we introduced OneSignal we had to create a separate path server-side to handle the OneSignal-enabled apps. The server-side pseudocode to handle both paths ran something like this:

// The code below runs when the server needs to send a push notification to a device

Order order = getOrderById(orderId);

// Parse path
if (order.hasParseDeviceToken()) {
    String deviceToken = order.getDeviceToken();
    Notifications.sendPushUsingParse(deviceToken);
}
// OneSignal path
else if (order.hasOneSignalUserId()) {
    String userId = order.getUserId();
    Notifications.sendPushUsingOneSignal(userId);
}

Once all of your users update their Android apps to the latest version running OneSignal, you no longer need the first IF statement in the server-side code to handle the Parse path. You can remove it and your notifications platform will continue uninterrupted.

Leave a Reply

Your email address will not be published. Required fields are marked *