Parse-Server & Android Push Notifications

Over the last few days I’ve had one hell of a time figuring out how to setup push notifications on Parse-Server for Android. Hopefully this will save some of you a few hours of effort.

Setup Parse-Server

First make sure you’ve got parse-server installed on your own server. For this example I’m using DigitalOcean and a Ubuntu Droplet. You can set up an account and Droplet (Server) in just a few minutes – super easy, and really cheap.

Setting up your Parser-Server out of the scope of this post so here’s a link to help get you going: Setting up a Parse Server

Setup Google Cloud Messaging

First thing I would do is setup a project on Google Developer Console. Once that’s setup you’ll need to turn on the Google Cloud Messaging (Push Notification) API. Do this by clicking on the API Manager and then clicking on “Google Cloud Messaging”. Once you setup the project there are two pieces of information you’ll need:

  1. The API Key
  2. The Project Number.

You can view the API key by going to Credentials. The project Number is the project itself.

Main.js & Index.js

So there are two primary files you’ll modify on Parse-Server to get Push Notifications setup. First the main.js file which is where your Parse Cloud Code will live. Here is a simple example of some cloud cloud code used to sent an announcement to a particular channel.

Parse.Cloud.define("sendAnnouncement", function(request, response) {
        var name = request.params.senderName;
        var msg = request.params.message;

        Parse.Push.send({
                channels: [ request.params.accountId ],
                data: {
                        title: name,
                        message: msg,
                        action: "com.hello.announcement.sample.SEND_ANNOUNCEMENT",
                        senderId: request.params.senderId,
                        accountId: request.params.accountId
                }
        }, {
                success: function() {
                        // Push was successful
                        response.success("sendAnnouncement sent");
                },
                error: function(error) {
                        // Handle error
                        response.error("error with sendAnnouncement: " + error);
                },
                useMasterKey: true
        });
});







I’m not a JavaScript dev so please excuse the poor formatting 🙂 This will get you a function in your cloud code you can call from the Android app which is covered below.

Next we need to setup the index.js. Both these files are created automatically for you. The index is found in your parse-server-example folder assuming you setup everything in the “Setup Parse-Server” section above.

// Example express application adding the parse-server module to expose Parse
// compatible API routes.

var express = require('express');
var ParseServer = require('parse-server').ParseServer;

var databaseUri = process.env.DATABASE_URI || process.env.MONGOLAB_URI

if (!databaseUri) {
  console.log('DATABASE_URI not specified, falling back to localhost.');
}

var api = new ParseServer({

  databaseURI: process.env.DATABASE_URI || 'mongodb://localhost:27017/test',
  cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
  appId: process.env.APP_ID || 'YOUR_PARSE_APP_ID_HERE',
  masterKey: process.env.MASTER_KEY || 'YOUR_PARSE_MASTER_KEY_HERE',
  push: {
    android: {
      senderId: 'YOUR_GOOGLE_DEVELOPER_CONSOLE_PROJECT_NUMBER_HERE', // The Sender ID of GCM
      apiKey: 'YOUR_GOOGLE_DEVELOPER_CONSOLE_API_KEY_HERE' // The Server API Key of GCM
    }
  }
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey

var app = express();

// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);

// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
  res.status(200).send('One day little green androids will rule the world.');
});

var port = process.env.PORT || 1337;
app.listen(port, function() {
    console.log('parse-server-example running on port ' + port + '.');
});








You’ll need to modify a few things here to get this working. First get your keys from Parse.com The keys are found under the App Settings > Security section of your Parse app. The keys we’ll need are the Application IDClient key, and Master key. Other keys may be needed if you have a different setup but since this is just covering Push Notifications that’s all we’ll need for this scope.

Then modify your index.js so your keys replace the following places:

  • YOUR_PARSE_APP_ID_HERE = Application ID
  • YOUR_PARSE_MASTER_KEY_HERE = Master Key
  • The Client Key will be used later in this tutorial for the Android App
  • YOUR_GOOGLE_DEVELOPER_CONSOLE_PROJECT_NUMBER_HERE = The Project Number of your Google Developer Console App. Looks something like #123456789012
  • YOUR_GOOGLE_DEVELOPER_CONSOLE_API_KEY_HERE = The Credentials API key on Google Developer Console. (This will need to be created if you haven’t done so already)

Save the index.js and lets move on. Once that’s done your server is ready to start pushing out notifications. We’ll need to now setup the Android bits and pieces and we’ll be good to go.

Android Application

First lets modify the android_manifest of our Android app. Don’t forget the “id:” before the Project Number.

<application>
    ...
    
    <meta-data
            android:name="com.parse.APPLICATION_ID"
            android:value="id:YOUR_GOOGLE_DEVELOPER_CONSOLE_PROJECT_NUMBER_HERE" />
    
</application>
  • YOUR_GOOGLE_DEVELOPER_CONSOLE_PROJECT_NUMBER_HERE = The same project number we setup on our index.js. Looks something like #123456789012

We also need to add the standard GCM XML to our manifest, be sure to replace your package name where “YOUR_PACKAGE_NAME” is. The first snippet of code goes before the <application/> tag, and the second goes inside the <application/> tag.

    <permission android:protectionLevel="signature" android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
    
    
    
    
        <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>
        
        
        
        

Next lets make sure we have our gradle dependencies added: (com.parse:parseinterceptors:0.0.2 is optional but amazingly useful, if you choose not to include this you’ll want to modify the Application class below not to use the interceptor)

    compile 'com.parse:parse-android:1.13.0'
    compile 'com.parse:parseinterceptors:0.0.2'
    compile 'com.facebook.stetho:stetho:1.2.0'

Next lets setup our Application class:

public class AppManager extends MultiDexApplication {

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }

    @Override
    public void onCreate() {
        super.onCreate();

        Parse.Configuration config = new Parse.Configuration.Builder(this)
                .applicationId(YOUR_PARSE_APPLICATION_ID_HERE)
                .clientKey(YOUR_PARSE_CLIENT_KEY_HERE)
                .server("http://YOUR_IP:1337/parse/")
                .addNetworkInterceptor(new ParseStethoInterceptor())
                .build();

        Parse.initialize(config);

        ParseUser account = ParseUser.getCurrentUser();
        if(isAccountValid(account)) {
            //I use a prefix to identify the channel as a user or "account" channel
            //This subscribes the parse user to the channel, you can then use the channel to send a push
            ParsePush.subscribeInBackground("parse_user_channel_" + account.getObjectId());
        }
        ParseInstallation.getCurrentInstallation().saveInBackground();

        //Stetho
        Stetho.initializeWithDefaults(this);
    }
    
    public static boolean isAccountValid(ParseUser account) {
        return !(account == null || TextUtils.isEmpty(account.getObjectId()));
    }
}





So the last thing we’ll need is a method to send a push notification. This assumes the user has subscribed to the push notification channel.

 public static void sendAnnouncement(Context context, String message, String senderName) {

        String channel = "someChannelTheUsersBeenSubscribedToo";
        final Map<String, Object> params = new HashMap<>();
        params.put("accountId", channel);
        params.put("message", message);
        params.put("senderName", senderName);
        params.put("senderId", "theUsersObjectId";
        params.put("useMasterKey", true);//Must have this line

        ParseCloud.callFunctionInBackground("sendAnnouncement", params, new FunctionCallback<String>() {
            public void done(String result, ParseException e) {
                if (e == null) {
                    Utils.d("ANNOUNCEMENT SUCCESS");
                } else {
                    Utils.e("ANNOUNCEMENT FAILURE");
                }
            }
        });
    }
    
    
    
    
    
    

9 thoughts on “Parse-Server & Android Push Notifications”

    1. My mistake, I’ve replaced that class with the correct code. I use ParseUtils to abstract things away related to Parse.

    1. Yes you can send custom data and the channel is what determine who the push notification gets sent too. I believe the custom data is limited in size, not sure what off the top of my head.

    1. Not at the moment, there were a bunch of tutorials I went through and when I went through the process I did not take note of all the steps. Digital Ocean is not very hard, I don’t do servers at all and was able to figure it out, so that says something 🙂

  1. I am using all give in the tutorial and the push is not on my device but the push status in mongodb show succeded

    1. I’m having a similar problem. My push seems to go through the server, but is never received by devices.

Leave a Reply

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

Time limit is exhausted. Please reload CAPTCHA.