Engineering

Transitioning from Parse Push Notifications

March 29, 2016

So you’re using Parse for push notifications and need to move to another provider. I feel your pain, I too have an app in the iOS and Android app stores that I need to move off Parse push. Not fun at all. My goal here is to show you a relatively painless transition path, something you really ought to tackle sooner rather than later.

We’re going to go through examples using the CleverTap Parse migration service.   Sign up for a free CleverTap account if you want to follow along with the examples.

Minimize disruption to your users during the transition

You’ve got users who’ve come to rely on your push notifications – none of this is their fault – so, minimizing disruption in notification delivery to those users ought to be a primary goal as you consider when, how and where to transition your push notifications.

Step 1: Import your Parse installations to your new service provider

Parse has done a great job in making transition tools available for us. One of those is tools is an export facility for your Parse data.

At CleverTap, we’ve built a Parse user import tool to automatically import your Parse installation data into your CleverTap account.

You can try it out here (make sure to sign up for a CleverTap account first).

When you import your Parse installations into CleverTap, a CleverTap user profile will be created for each of your Parse users. Those profiles will include the corresponding push tokens and channel values (and other custom property values) from your corresponding Parse installation.

Step 2: Connect your imported installation accounts to your user devices

To manage your installation data and handle push notifications going forward, you will need to incorporate your new provider’s SDK into your app. Ideally, as part of this you’d be able match your individual devices to the corresponding imported Parse installation account. In that way, you will be able to immediately access and manage your imported installation data from your app. Moreover, not matching the imported account to the user device may lead to duplicate accounts for the same device installation.

For example, when you install the CleverTap SDK, we will be able to match the imported CleverTap user profile with your device user using the Parse Installation Id. To enable this matching, add the following flag to your Info.plist/AndroidManifest.xml file when integrating the relevant CleverTap SDK.

AndroidManifest.xml:


<meta-data
  android:name="CLEVERTAP_PARSE"
  android:value="1"/>

Info.plist:
Add a key called CleverTapParse as a BOOLEAN truthy value in your .plist file.

With a successful matching, you will be able to access and manage your imported channels and custom variables for that user in your app code.

Step 3: Generate new Android GCM tokens with your GCM Sender Id

The default with Parse was to collect Android GCM tokens using the Parse GCM Sender Id. As a result, those tokens will no longer work (when you switch to a new provider or Parse ceases operations).

If you do not have tokens generated with your own GCM Sender Id, it may be a good idea to run your new provider and Parse side by side in your app for a reasonable time period. During that time, you can generate new tokens using your own GCM Sender Id for use with your new provider, while still sending your current push notifications via Parse using the Parse GCM tokens. Once you feel you’ve generated new tokens for enough of your user base, you can then remove the Parse SDK from your app and begin sending all your push notifications via your new provider.

Check out our Android Push Notification Guide for more information on setting up push notifications with your own GCM Sender Id.

The easiest way to run your new provider (in this example, CleverTap) side by side with Parse temporarily is to declare both the Parse and CleverTap broadcast receivers in your AndroidManifest.xml:


<meta-data
    android:name="GCM_SENDER_ID"
    android:value="id:Your GCM Sender Id"/>

<meta-data android:name="com.parse.push.gcm_sender_id"
    android:value="id:Your GCM Sender Id" />

<receiver
    android:name="com.parse.GcmBroadcastReceiver"
    android:permission="com.google.android.c2dm.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        <category android:name="Your package name" />
    </intent-filter>
</receiver>

<receiver
    android:name="com.clevertap.android.sdk.GcmBroadcastReceiver"
    android:permission="com.google.android.c2dm.permission.SEND">
    <intent-filter>
        <action
            android:name="com.google.android.c2dm.intent.RECEIVE"/>
        <action
            android:name="com.google.android.c2dm.intent.REGISTRATION"/>
        <category android:name="Your package name"/>
    </intent-filter>
</receiver>

Minimize disruption to yourself during and after the transition

When looking at new providers, you owe it to yourself to make sure you have the broadest possible toolset for managing and sending push going forward. Some things to consider here are client-side API’s for accessing and managing your channels, as well as web dashboard capabilities, REST API functionality and parse-server compatibility for sending push.

Accessing and Managing Channels

For example with CleverTap, you can access and manage user channels in your client-side code like this:

Accessing Channels in Android:


clevertap = CleverTapAPI.getInstance(getApplicationContext());
JSONArray channels = (JSONArray ) clevertap.profile.getProperty("channels");
if (channels != null) {
    for (int i=0; i <channels.length(); i++) {
        try {
            Log.d("Channel", "value is " + channels.get(i));
        } catch (JSONException e) {
            // no-op
        }
    }
}

Adding or Removing Channels in Android:


clevertap = CleverTapAPI.getInstance(getApplicationContext());
clevertap.profile.addMultiValueForKey("channels", "mets");

clevertap = CleverTapAPI.getInstance(getApplicationContext());
clevertap.profile.removeMultiValueForKey("channels", "yankees");

Accessing Channels in iOS:


NSArray *channels = [[CleverTap sharedInstance] profileGet:@"channels"];
if (channels && [channels isKindOfClass:[NSArray class]]) {
    for (NSString *channel in channels) {
        NSLog(@"channel is %@", channel);
    }
}

Adding or Removing Channels in iOS:


[[CleverTap sharedInstance] profileAddMultiValue:@"yankees" forKey:@"channels"];

[[CleverTap sharedInstance] profileRemoveMultiValue:@"mets" forKey:@"channels"];

 

Sending Push Notifications

Ideally, you should be able to send push from a web dashboard, from a REST API and/or from your own instance of the parse-server. With CleverTap, for example, you have the ability to do all three.

Web dashboard:

You can create and manage push notification campaigns directly in your CleverTap Dashboard->Campaigns->Push.

REST API:

In this example using the CleverTap Server API, we are creating a push notification to be sent to users subscribed to the “yankees” and “mets” channels.

Endpoint: https://api.clevertap.com/1/targets/create.json

Sample Request:


curl -H "Content-Type:application/json"
  -H "X-CleverTap-Account-ID: Your CleverTap Account ID"
  -H "X-CleverTap-Passcode: Your CleverTap Account Passcode"
  --data "@payload"
  "https://api.clevertap.com/1/targets/create.json"

Payload:


{
    "name": "My API Campaign",
    "where": {
        "common_profile_prop": {
            "profile_fields": [
                {
                    "name": "channels",
                    "value": ["yankees", "mets"]
                }
            ]
        }
    },
    "content":{
        "title": "Breaking News",
        "body": "Yankees Win 5-4",
        "platform_specific": {
            "ios": {
                "deep_link": "example.com",
                "sound_file": "example.caf",
                "category": "reactive",
                "badge_count": 1,
                "key": "value_ios"
            },
            "android": {
                "background_image": "http://example.jpg",
                "default_sound": true,
                "deep_link": "example.com",
                "key": "value_android"
            }
        }
    },
    "devices": [
        "android",
        "ios",
    ],
    "when": "now"
}

Response:


{
    "status": "success",
    "id": 1457433898,
    "estimates": {
        "android": 90,
        "ios": 300
    }
}

 

Parse Server Cloud Code:

If you are running your own instance of parse-server, you can use the CleverTap Node.js module to send push notifications from your parse-server. Please see our fork of the parse-server-example server for more details and usage.

  • install the CleverTap Node module:
    npm install --save clevertap
  • add your CleverTap Account ID and CleverTap Account Passcode (you can find these in CleverTap Dashboard->Settings) as environment variables (CLEVERTAP_ACCOUNT_ID and CLEVERTAP_ACCOUNT_PASSCODE, respectively).

You can then enable CleverTap in your Cloud Code (see our example cloud/main.js implementation) to send push like this, for example:


const CleverTap = require("clevertap");
const clevertap = CleverTap.init(process.env.CLEVERTAP_ACCOUNT_ID, process.env.CLEVERTAP_ACCOUNT_PASSCODE);

Parse.Cloud.define('push', function(req, res) {

    /**
    * Send an immediate push to users subscribed to the specified channels
    */

    const channels = req.params.channels;

    if (!channels) {
        res.error("channels not present");
        return;
    }

    const payload = {
        "name": "test push " + Math.round(new Date().getTime()/1000),
        "when": "now",
        "where": {
            "common_profile_prop": {
                "profile_fields": [{"name": "channels", "value": channels}]
            }
        },
        "content": {
            "title":"Hello!",
            "body":"Just testing"
        },
        "devices": ["ios", "android"]
    }

    clevertap.targets(clevertap.TARGET_CREATE, payload, {"debug":1}).then((r) => {
        res.success(r);
    });
});

Parse.Cloud.afterSave('GameScore', function(req) {
    /**
     * Send all users an immediate push notifiying them of a new Game Score.
     *
     */
    const gameScore = req.object;
    const body = (gameScore) ? `New Game Score: ${gameScore.get("playerName")} ${gameScore.get("score")}` : "New Game Score";
    const payload = {
        "name": "test push " + Math.round(new Date().getTime()/1000),
        "when": "now",
        "segment":"all",
        "content": {
            "title": "Hey There!",
            "body": body,
        },
        "devices": ["ios", "android"]
    }

    clevertap.targets(clevertap.TARGET_CREATE, payload, {"debug":1}).then((r) => {
        console.log(r);
    });
});

That’s really all there is to it. If you’re like me, you might tend to procrastinate about things like this :), so hopefully this guide will get you started!

,

4000

55 billion

1 billion

10 billion