Low-level notification handling (deprecated)
In this article, we'll run through the process of intercepting push notifications and manually read the notification payload, before showing it using Batch or your own implementation.
Notice
This documentation describes what is called a "custom receiver": it is a low level implementation of receiving push notifications. It used to be the only way to tweak how Batch notifications are displayed, so older implementations of Batch SDK might still have one.
To make it so developers don't have to reimplement every feature Batch supports in notifications, we added another way: the notification interceptor, which does not require you to rewrite the NotificationBuilder implementation yourself, and is already started in a threaded service.
You also get free support for new Android versions.
You should pick a notification interceptor if:
- You want to change a single thing about a notification
- Example: Priority, progess, ongoing, ...
- You want to filter notifications at runtime
You should pick a custom receiver if:
- You need to disable Batch's default handling to improve compatibility with other solutions
- You need to react to the push's raw payload, and are not interested in changing how it will be displayed
- In that case, consider using a FirebaseMessagingService
Note that both solutions are not mutually exclusive: a custom receiver can take care of a specific use case, and the notification interceptor will handle another.
Important Android O note
This documentation used to describe a way to implement your own logic when receiving a push message. If your application now targets Android O (API 26) or higher, old implementations might end up crashing due to changes in backgrounding rules.
Please note that, while not directly related to Services and new backgrounding limitations, notifications may suddently not work anymore if your code is not setting up and associating a Notification Channel to your Notification.
Since then, this documentation has been updated to use JobIntentService. You will need a recent version of the support-v4 library to continue.
Enabling Manual display
If you don't want Batch to display notifications, you should activate the manual display mode, you shall do it in your Application.onCreate
method:
@Override
public void onCreate()
{
super.onCreate();
Batch.Push.setGCMSenderId("Your GCM sender ID");
Batch.Push.setManualDisplay(true);
Batch.setConfig(new Config(API_KEY));
}
Be sure to do it in the
onCreate
method of your Application not your Activity because your Activity may not be started when you receive a push notification from GCM.
Registering your own receiver
To receive GCM intents, you'll have to register your own push receiver and service in addition to Batch one.
First create an IntentService and a BroadcastReceiver to subcribe to GCM notifications
Here's the IntentService (note that PushReceiver
references your BroadcastReceiver
):
public class PushService extends JobIntentService
{
/**
* Unique job ID for this service.
*/
static final int JOB_ID = 1002;
/**
* Convenience method for enqueuing work in to this service.
*/
static void enqueueWork(Context context, Intent work) {
enqueueWork(context, PushService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(Intent intent)
{
// Code to display notification will go there
}
}
And here's the BroadcastReceiver (where PushService
is your JobIntentService
implementation):
public class PushReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
PushService.enqueueWork(context, intent);
}
}
Then register them into your application Manifest, near Batch ones:
<service android:name=".PushService"
android:permission="android.permission.BIND_JOB_SERVICE" />
<receiver android:name=".PushReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
Retreiving data from a Batch push
If you want to standard data contained in your Batch Push intent, Batch provides an easy way to retrieve them.
First of all, you can retrieve your push message and title (if you set one) this way:
@Override
protected void onHandleWork(Intent intent)
{
if( Batch.Push.shouldDisplayPush(this, intent) ) // Check that the push is valid
{
String alert = intent.getStringExtra(Batch.Push.ALERT_KEY);
// Use the alert text to display the notification
String title = intent.getStringExtra(Batch.Push.TITLE_KEY);
if( title != null && !title.trim().isEmpty() )
{
// Use the title to display the notification
}
}
}
If you use advanced features like deeplink, custom large icon or big picture, Batch provides with an object that make it easy to retrieve them. Here's how it works:
@Override
protected void onHandleWork(Intent intent)
{
if( Batch.Push.shouldDisplayPush(this, intent) ) // Check that the push is valid
{
BatchPushPayload pushData = BatchPushPayload.payloadFromReceiverIntent(intent);
// Deeplink
if( pushData.hasDeeplink() )
{
String deeplink = pushData.getDeeplink();
}
// Custom large icon
if( pushData.hasCustomLargeIcon() )
{
String largeIconURL = pushData.getCustomLargeIconURL();
// You are responsible of downloading the image at the given url and use it in your notification
}
// Big picture
if( pushData.hasBigPicture() )
{
String bigPictureURL = pushData.getBigPictureURL();
// You are responsible of downloading the image at the given url and use it in your notification
}
}
}
Reading the custom payload's key/values
You can also read the custom payload you've set while creating the campaign or sending a transactional push:
@Override
protected void onHandleWork(Intent intent)
{
if( Batch.Push.shouldDisplayPush(this, intent) ) // Check that the push is valid
{
// Custom payload fields. Root keys are always of the string type, due to GCM limitations.
// Here we'll read the "article_id" key of the following custom payload : {"article_id": 2}
String articleId = intent.getStringExtra("article_id");
// If you have more complex objets, you'll need to parse them using a JSON parser
// Matching custom payload: {"user_data": {"id": 2}}
JSONObject userData = new JSONObject(intent.getStringExtra("user_data"));
int userId = userData.getInt("id");
}
}
Note: If you want to read your custom payload, this should be done directly from the intent using
getStringExtra()
. While you might be tempted to read the extra with the keyBatch.Push.PAYLOAD_KEY
, this key is not applicable in this context, and will not return anything.
That's it, you are now ready to handle push messages that come from Batch Push servers. You can either:
- Perform an action on Push but let Batch display the notification
- Completely take control on notification display
Performing action before push display
If you want to simply do an action based on the received intent but don't want to display the notification yourself, you can do it quite simply:
@Override
protected void onHandleWork(Intent intent)
{
if( Batch.Push.shouldDisplayPush(this, intent) ) // Check that the push is valid
{
// Your code goes here
// Display the notification
Batch.Push.displayNotification(this, intent);
}
}
If you want to have a chance to tweak some values of the notification Batch will show, you can also give Batch.Push.displayNotification
an interceptor. If an interceptor has been configured globally, Batch will try to use the one specified in this method call, if not null.
Displaying your own notification
If you want to display your own custom notification, you can do it yourself using the Notification.Builder
API. Batch provides with helpers that you'll need to use if you want to have the open rate available from our dashboard. Here's how to do it:
Note: If your app targets API 26 or higher (Android 8.0), please make sure that you register a notification channel, and specify it in the builder. Failure to do so will result in the system discarding your notifications.
@Override
protected void onHandleWork(Intent intent)
{
if( Batch.Push.shouldDisplayPush(this, intent) ) // Check that the push is valid
{
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Build your own notification here...
// Assuming you have a drawable named notification_icon, can otherwise be anything you want
builder.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(intent.getStringExtra(Batch.Push.TITLE_KEY))
.setContentText(intent.getStringExtra(Batch.Push.ALERT_KEY));
// Create intent
Intent launchIntent = yourFunction(); // Create your own intent
Batch.Push.appendBatchData(intent, launchIntent); // Call this method to add tracking data to your intent to track opens
// Finish building the notification using the launchIntent
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
// Display your notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
// "id" is supposed to be a unique id, in order to be able to update the notification if you want.
// If you don't care about updating it, you can simply make a random it, like below
int id = (int) (Math.random() * Integer.MAX_VALUE);
notificationManager.notify(id, builder.build());
// Call Batch to keep track of that notification
Batch.Push.onNotificationDisplayed(this, intent);
}
}
Be sure to use the
PendingIntent.FLAG_UPDATE_CURRENT
flag when getting your pending intent. Failure to do so will make open tracking unreliable.