Android Push Notifications

Push notifications are important. Really important, actually.  When we released our first iteration of the LunchBunch, the most common feedback from users was that notifications didn’t act the way they were expected to.  A friend texted me saying, “I think something’s wrong with my phone, because notifications in your app don’t take me where I expect to go.” He thought it was a software issue on his phone’s part, not on ours! It was then that I realized we needed to focus our attention on notifications.

In this post, we’ll discuss two things: how the notifications get to our phones (specific to Google Cloud Messaging [GCM] notifications), and how we as developers parse them and notify the user. We’ll completely and intentionally ignore the aesthetics of the notification.  That’s actually an important discussion but out of the scope for this post. Check out Android’s Notification Design docs for more information.

Okay, first thing’s first–how do these great bundles of information reach my phone? Take this scenario for example: You just downloaded LunchBunch (congrats on the great decision, by the way), and you need some buddies to grab a meal with. So you add your best friend, Taylor. Well, Taylor is super psyched that you requested to be buddies and immediately accepts! Now, you won’t know that until we at LunchBunch send you a friendly notification. So what do we need to do?

Our application server, now knowing that you and Taylor just became buddies, will send a bit of data with the good news to Google’s servers. You, the user, having subscribed to receive notifications from LunchBunch (we’ll talk about this next), are now sent a notification from Google’s servers, and you can begin planning meals with Taylor. For all that to happen, our application servers need to be registered with Google to send them data, and you as a user need to subscribe to the notifications. I won’t walk you through the setup process (it’s boring, and Google does a good job with it here and here), so let’s get into the client-side code.

How do we subscribe to get notifications from LunchBunch? This all happens in an IntentService. When the app is installed, or when Google deems the last subscription stale, an Intent is kicked off to begin an IntentService (let’s call it CoolAppRegistrationIntentService). We kick it off from the MainActivity, the first activity that loads upon the app opening:

Intent intent = new Intent(this, CoolAppRegistrationIntentService.class);
    startService(intent);
}

The job of this IntentService is to get a token from Google to be sent to our Cool App application server. Here are the lines of code that do the magic:

InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
        GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

After these lines, we have a token that will be sent to our application server for communication with the GCM servers. So, we have to get the token to our server. How you do that is up to you, but once you get confirmation from your server that it’s received the token, we’ll want to set some sort of Boolean that keeps the application from sending that token again for no reason, maybe in SharedPreferences:

if (status.equals("success")) {
    sharedPrefsHelper.setRegTokenSentToServer(true);
}

Sweet! Now we’re all set up to receive notifications. Snap, now we have to actually handle that, too!? No worries, it’s a piece of cake. There’s a GcmListenerService that does all the magic. What you’ll want to do is write your own class–let’s call it CoolAppListenerService–which extends GcmListenerService. You’ll implement a method called onMessageReceived, which has an important parameter–the data of the notification. Exciting, huh? That’s the data you’ll parse and (maybe) display to the user!

What’s been said so far is only bits and pieces–enough to get an understanding of the subscription process…But what I’m about to touch on is the nitty gritty application-specific stuff.

How you handle different notifications is totally up to you, but at some point you’ll want to display a message to the user. You can include this in the data, and extract it easily:

String frontFacingMessage = data.getString("message");
boolean sendNotification = !(TextUtils.isEmpty(frontFacingMessage));

Here we’ve included some message in the data if we want the user to see the change, and if that’s empty we don’t want the user to be privy.

Let’s go through two examples of actually parsing the notification data. First up, the story from before: Taylor just accepted you as a buddy, and LunchBunch is letting you know.

intent = new Intent(this, MainActivity.class);
intent.putExtra("action", "to_bunches");
notificationID = 0;
//Create a new buddy from data
String username = data.getString("username");
String firstName = data.getString("first_name");
String lastName = data.getString("last_name");
if (username!=null && firstName!=null && lastName!=null) {
    database.createBuddy(new Buddy(username, firstName, lastName, 0));
bus.post(new Event());
}

Whoa! That’s a big chunk of code. What does it all do? Not a whole lot, really. The first few lines create an intent that will be fired off when you click the notification. This one specifies the MainActivity and has an extra on it that will tell the MainActivity to send you to the Bunches page to see the new buddy. Below that, a notification ID is given to the notification, so we can dismiss it (or update it) manually in case the user doesn’t click on it or swipe it away. Finally, the end of this chunk mainly pertains to creating a new buddy to be added to our local database. We pull the username, first name, and last name from the data, and insert the buddy. Oh, and the last line is important–it posts a broadcast to our bunches page to update, in case you were looking at that page when the notification came in! Since the buddy was inserted into the database already, the adapter on the ListView would refresh, showing you the brand spankin’ new buddy in your list.

Now, a really simple and easy second example. The opposite of a new buddy, an ex-buddy. While we hope you never have any ex-LunchBunch-buddies, it’s a good way of seeing an example of when we wouldn’t want to notify you of a change.

String debuddyer = data.getString("username");
if (debuddyer!=null) {
    database.deleteBuddy(debuddyer); // Delete buddy from DB
}
bus.post(new Event());

In this instance, all we’ve done is parse for the username of our old friend, delete them from our database, and tell the Bunches Page to refresh. You don’t see any notification ID or Intent here, because there won’t be any actual visual notification.

Great! All done? Nope, not yet. You might have realized that we didn’t actually do anything to notify the user in our first example.  Good eyes, chief!

At the end of the parsing code, we check to see if we should send a notification (using our boolean from before), and if we should, we create one:

private void sendNotification(String message, Intent resultIntent, int notificationID) {
    // Notification attributes
    NotificationCompat.Builder mBuilder =
            new NotificationCompat.Builder(this)
                    .setSmallIcon(R.drawable.icon)
.setContentTitle("Cool App)
                    .setContentText(message)
    // Intent to start Activity
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    // Adds the back stack
    stackBuilder.addParentStack(resultIntent.getComponent());
    // Adds the Intent to the top of the stack
    stackBuilder.addNextIntent(resultIntent);
    // Gets a PendingIntent containing the entire back stack
    PendingIntent resultPendingIntent =
            stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder.setContentIntent(resultPendingIntent);
    NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(notificationID, mBuilder.build());
}

This is just the basics, but it will do the trick.  We use the NotificationCompat.Builder to build a notification that will look sweet regardless of the API it’s being displayed on.  We set an icon, a title, and the content to be displayed.  Below that, you’ll see the intent that we defined in our new buddy example, which will fire off when the notification is clicked. In that same block of code, we define a back stack, so that the application will navigate the same as if the user had navigated to that place in the app himself, rather than having clicked on a notification.  Finally, we get an instance of NotificationManager and call notify(), using the notification ID we defined in our code.

And there you have it, the user has been notified! Congratulations, you’re well on your way to an app that meets everybody’s high expectations 🙂

How do you use push notifications in your applications? Interested in learning more about a specific concept? Let us know in the comments below!

Sincerely,
Brandon from The Bunch

Leave a Reply

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