Customizing Push Notifications
Step-by-step guide to customizing the appearance of Push Notifications through your app
Custom Push Notification Layouts
WebEngage Android SDK has included two new functional interfaces in v3.10.1 which allows you to modify the default push notification layouts.
Please ensure you follow the Android notification layout guidelines before creating your own custom layouts. Usually, collapsed view layouts are limited to 64 dp, and expanded view layouts are limited to 256 dp.
1. CustomPushRender: Called for rendering push notifications. This is where you can set your custom layouts and notify push notifications.
public interface CustomPushRender {
/**
* @return: Return true if notification is rendered successfully, else return false.
*/
boolean onRender(Context context, PushNotificationData pushNotificationData);
}
2. CustomPushRerender: Called for re-rendering/updating push notifications. This is where you can update your push notifications.
public interface CustomPushRerender {
/**
* @return: Return true if notification is re-rendered successfully, else return false.
*/
boolean onRerender(Context context, PushNotificationData pushNotificationData, Bundle extras);
}
Custom push render callbacks are only called when you provide we_custom_render:
true in the custom key-values while creating push campaign from WebEngage dashboard and CustomPushRender and CustomPushRerender implementations are registered using WebEngage.registerCustomPushRenderCallback
and WebEngage.registerCustomPushRerenderCallback
APIs.
If onRender
or onRerender
method returns false, then notification will not be displayed.
Push Notification Data
The instance of PushNotificationData
available to you in the onRender
and onRerender
callbacks contains the details required to construct and show the push notification.
Rich Text handling
Available from SDK v3.20.0 and needs to be handled properly to avoid showing proper title and message in push notifications.
Handling Rich text
From SDK version 3.20.0 and above you will start getting rich text in PushNotifictaionData hence it needs to be handled accordingly.
Push title, message, summary and action text will start coming in HTML format so to handle them, kindly follow the steps below.
Handling Push Title text
WEHtmlParserInterface weHtmlParserInterface = new WEHtmlParserInterface();
Spannable title = weHtmlParserInterface.fromHtml(pushNotificationData.getTitle());
...
//Now use the title as your input to remote views.
val weHtmlParserInterface = WEHtmlParserInterface()
val title = weHtmlParserInterface.fromHtml(pushNotificationData.title)
...
//Now use the title as your input to remote views.
Handling Push Description text
WEHtmlParserInterface weHtmlParserInterface = new WEHtmlParserInterface();
Spannable description = weHtmlParserInterface.fromHtml(pushNotificationData.getContentText());
...
//Now use the description as your input to remote views.
val weHtmlParserInterface = WEHtmlParserInterface()
val description = weHtmlParserInterface.fromHtml(pushNotificationData.contentText)
...
//Now use the description as your input to remote views.
Handling Push Summary text
WEHtmlParserInterface weHtmlParserInterface = new WEHtmlParserInterface();
Spannable summary = weHtmlParserInterface.fromHtml(pushNotificationData.getContentSummary());
...
//Now use the summary as your input to remote views.
val weHtmlParserInterface = WEHtmlParserInterface()
val summary = weHtmlParserInterface.fromHtml(pushNotificationData.contentSummary)
...
//Now use the summary as your input to remote views.
Important changes while getting data from PushNotificationData
Follow the changes mentioned in the table below
Description | less than v3.20.0 | greater equal v3.20.0 |
---|---|---|
Fetching Description | pushNotificationData.getSummary() | pushNotificationData.getContentText() |
Fetching Summary | Not Available | pushNotificationData.getContentSummary() |
Tracking Push Notification Actions
In order to correctly track the push notification actions such as clicks, updates, dismissed, etc. in custom push notifications, it is mandatory to use the PendingIntents constructed through the APIs provided in the WebEngage's PendingIntentFactory
class.
PendingIntentFactory
includes the APIs for constructing the following PendingIntents
which must be set in the Notification for tracking different push notification actions.
1. Click PendingIntent
PendingIntent constructPushClickPendingIntent(Context context, PushNotificationData pushNotificationData, CallToAction cta, boolean autoCancel)
method returns a PendingIntent
which can be set as PendingIntent
for content intent or for any action button in your custom push notification.
boolean autoCancel = true; // true if notification should be dismissed on click, else false
PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), autoCancel);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, MY_CHANNEL_ID)
...
.setContentIntent(contentPendingIntent)
...
2. Delete PendingIntent
PendingIntent constructPushDeletePendingIntent(Context context, PushNotificationData pushNotificationData)
method returns a PendingIntent
that must be set as delete intent in your notification, which will help WebEngage SDK to track push notification dismisses.
PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, MY_CHANNEL_ID)
...
.setDeleteIntent(deletePendingIntent)
...
3. Rerender PendingIntent
PendingIntent constructRerenderPendingIntent(Context context, PushNotificationData pushNotificationData, String requestCodePrefix, Bundle extraData)
method returns a PendingIntent
which will trigger the onRerender
callback on click. This callback can be used to update/rerender your notification.
param String requestCodePrefix: The request code of the returned PendingIntent
is generated using the following code:
...
int requestCode = (requestCodePrefix + pushNotificationData.getVariationId()).hashCode();
PendingIntent pendingIntent = PendingIntent.getService(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
param Bundle extraData: This bundle must include additional data required for rerendering the notification. This bundle will be passed in boolean onRerender(Context context, PushNotificationData pushNotificationData, Bundle extraData)
method as extraData
for updating the notification.
For eg. You might want to update the push notification content when a user selects a star in rating push notification. In order to mark the star(s) as selected, you might need an additional information that tells you which star was clicked. Such additional data can be passed in the extraData
bundle.
Bundle rateClickExtraData = new Bundle();
rateClickExtraData.putInt("current", i);
...
PendingIntent rateClickPendingIntent = PendingIntentFactory.constructRerenderPendingIntent(context, pushNotificationData, "rate_click_" + i, rateClickExtraData);
ratingView.setOnClickPendingIntent(R.id.selected_star, rateClickPendingIntent);
4. Carousel Browse PendingIntent
PendingIntent constructCarouselBrowsePendingIntent(Context context, PushNotificationData pushNotificationData, int newIndex, String navigation, String requestCodePrefix, Bundle extraData)
method returns a PendingIntent
which will automatically track the carousel browse event on click of left/right arrows in the carousel push notification. It also triggers the onRerender
callback which can be used to update the current carousel item.
param int newIndex: This is the newly calculated index of the carousel item to be shown.
param String navigation: This indicates the direction in which the carousel is browsed.
int currIndex = 0;
PendingIntent leftPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, currIndex, "left", "carousel_left", browseExtraData);
PendingIntent rightPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, currIndex, "right", "carousel_right", browseExtraData);
...
carouselView.setOnClickPendingIntent(R.id.left_arraow, leftPendingIntent);
carouselView.setOnClickPendingIntent(R.id.right_arrow, rightPendingIntent);
...
5. Rating Submit PendingIntent
PendingIntent constructPushRatingSubmitPendingIntent(Context context, PushNotificationData pushNotificationData, int rateValue)
method takes an integer for rating as parameter which will track rating submit event on click of submit button in rating notification.
param int rateValue: This is the last rating value selected by the user.
int currIndex = extraData.getInt("current"); // current index can be obtained from extraData bundle provided while setting Click PendingIntent
PendingIntent rateSubmitPendingIntent = PendingIntentFactory.constructPushRatingSubmitPendingIntent(context, pushNotificationData, currIndex);
ratingView.setOnClickPendingIntent(R.id.rating_submit_button, rateSubmitPendingIntent);
Note: Any PendingIntents
used in the push notification which is not provided by the above specified APIs, will not be tracked by the WebEngage Android SDK and hence will not be seen on the campaign stats page in your WebEngage dashboard.
Sample usage of these PendingIntents can be found in the code snippets of sample custom layouts given below.
Sample Custom Layouts
Prerequisites:
- Create implementations of
CustomPushRender
andCustomPushRerender
interfaces as shown below.
public class MyPushRenderer implements CustomPushRender, CustomPushRerender {
@Override
public boolean onRender(Context context, PushNotificationData pushNotificationData) {
// render your notification here
return true;
}
@Override
public boolean onRerender(Context context, PushNotificationData pushNotificationData, Bundle bundle) {
// re-render your notification here
return true;
}
}
- Make sure to register for custom push render callbacks in your Application class as shown below.
public class MainApplication extends Application {
private static final String TAG = MainApplication.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
...
// Register for custom push render callbacks
MyPushRenderer myPushRenderer = new MyPushRenderer();
WebEngage.registerCustomPushRenderCallback(myPushRenderer);
WebEngage.registerCustomPushRerenderCallback(myPushRenderer);
}
}
Please refer to the following sample code snippets which might help you to build your own custom push notification layouts - Text Layout, Banner Layout, Carousel Layout (Landscape), Carousel Layout (Portrait), Rating Layout.
For the following sections, you can customize your push messages by implementing push message callbacks in your application.
Overriding Push Title, Message and Image
You can override the title, message or image of the push notification that you had set on WebEngage dashboard while creating the campaign.
@Override
public PushNotificationData onPushNotificationReceived(Context context, PushNotificationData notificationData) {
notificationData.setTitle("YOUR_TITLE"); // Add or change title
notificationData.setContentText("YOUR_MESSAGE"); // Change message
WebEngageConstant.STYLE style = notificationData.getStyle();
if (style != null) {
switch (style) {
case BIG_PICTURE:
// Change image
notificationData.getBigPictureStyleData().setBigPictureUrl("http://www.example.com");
//Add title which will be shown when notification is expanded
notificationData.getBigPictureStyleData().setBigContentTitle("YOUR_EXPANDED_TITLE");
// Add summary which will be shown when notification is expanded.
notificationData.getBigPictureStyleData().setSummary("YOUR_SUMMARY");
break;
case BIG_TEXT:
// Add or change title which will be shown when notification is expanded.
notificationData.getBigTextStyleData().setBigContentTitle("YOUR_EXPANDED_TITLE");
// Change message which will be shown when notification is expanded.
notificationData.getBigTextStyleData().setBigText("YOUR_EXPANDED_MESSAGE");
break;
}
}
return notificationData;
}
Campaign-level Customization
While creating a push message campaign on WebEngage dashboard, you can define key-value pairs. This data is a part of the push message payload, and can be accessed using push callbacks. This allows you to customize your push messages at a campaign level from within your app. This is illustrated below using onPushNotificationDismissed
. You can use any of the push message callbacks depending on where you want to customize the user experience.
@Override
public void onPushNotificationDismissed(Context context, PushNotificationData notificationData) {
Bundle customData = notificationData.getCustomData();
if (customData != null) {
// Your customization logic goes here
}
}
If you have multiple apps using the same WebEngage license code, you can target them selectively using push notifications by adding key-value pairs in the campaign body and using them as identifiers in your apps as illustrated above.
Call to Action
Calls to action are the deep links or URIs where a user lands on clicking the push message. You can add CTAs while creating your push campaign on WebEngage dashboard. They are divided into two categories in WebEngage Android SDK - Primary CTA and Non-primary CTA.
Primary CTA
A push message can have at most one primary CTA which performs action (directs the user to a particular URI or a deep link) when the user taps on the content of the push notification. If no URI or deep link is configured for primary CTA then the user will be redirected to your application's launcher activity upon clicking the push notification.
Non-primary CTAs
A push notification can have at most 2 non-primary CTAs which perform action when the user clicks on their respective action buttons.
Sometimes you may desire to take control of the click action of a push notification for performing tasks such as creating your own back navigation. When the user enters your app with a deep link that starts the activity in its own task, it's necessary for you to synthesize a new back stack because the activity is running in a new task without any back stack at all. This is illustrated below using push message callbacks.
@Override
public boolean onPushNotificationClicked(Context context, PushNotificationData notificationData) {
return buildNavigation(context, notificationData.getPrimeCallToAction());
}
@Override
public boolean onPushNotificationActionClicked(Context context, PushNotificationData notificationData, String buttonID) {
return buildNavigation(context, notificationData.getCallToActionById(buttonID));
}
private boolean buildNavigation(Context context, CallToAction callToAction) {
if (callToAction != null) {
if (callToAction.isPrimeAction()) {
//User clicked on notification content
String action = callToAction.getAction();
if (action == null) {
// Primary CTA was not configured with a URI or deep link.
// Return false if you want WebEngage SDK to open launcher activity with default intent flags.
// Return true and write your own code to open desired activity with custom intent flags.
} else {
CallToAction.TYPE type = callToAction.getType();
if (type != null) {
switch (type) {
case LINK:
//This CTA was configured with a link while creating the push notification campaign.
// This link can be either an http url or your custom deep link.
// Return false if you want WebEngage SDK to open this link with default flags or return true
// and write your own code to open this link.
break;
case LAUNCH_ACTIVITY:
//This CTA was configured with an activity path while creating the push notification.
// Return false if you want WebEngage SDK to open this activity with default flags or return true
// and write your own code to open this activity.
break;
}
}
}
//NOTE: To get action string use callToAction.getAction()
} else {
// User clicked on one of the action buttons.
// Handle this CTA in the same way above primary CTA is handled, if only desired.
}
}
return false;
}
Please Note
Read operation on
PushNotificationData
fields can be done from any push notification callback function.Any changes done to
PushNotificationData
fields will be reflected only if they are called fromonPushNotificationReceived
callback.For example :
notificationData.getPrimeCallToAction().setAction("https://www.example.com", CallToAction.TYPE.LINK,context)
will be effective only if it is called fromonPushNotificationReceived
.
Render Timer Push notifications
Timer push notifications are custom push notification layouts wherein clients can configure a timer within push notifications for Android.
WebEngage offers clients 2 layout options for timer push notifications: Countdown timer and Timer with progress bar.
Supported via custom push
Timer notification layouts are not offered out of the box on the dashboard currently. We have provided this capability using custom layouts.
These pre-defined timer template support is added for text layouts only. But it can always be extended to other layouts as these are powered through custom push.
Steps to configure timer push notifications in your app
- Add custom push render support within your app as per the steps mentioned here
- Integrate our timer push template from Github.
- Add below line to the application class of your app or edit your callbacks for including the callbacks provided in the module.
WebEngage.registerCustomPushRenderCallback(CustomCallback())
WebEngage.registerCustomPushRerenderCallback(CustomCallback())
Once the above steps are completed, your App will be able to support these timer notifications.
To render Countdown Timer push notifications
Once your app is set up to support timer notifications, you can run countdown timer push notification by passing the below 'Key-values' in the 'Message' section of the push campaigns on the dashboard.
Key | Value | Description |
---|---|---|
we_custom_render | true | Required for allowing apps to render custom push notifications. |
template_type | timer | Countdown timer template. |
future_time | epoch time in milliseconds | Add the time till when the notification is required to be displayed. Example: If you are sending a notification at 12PM and want the notification to expire by 9 PM then add the value as epoch time (in milliseconds) for 9 PM on that day. |
timer_color | # 000000 {Hex color code} | (Optional) Hex code for the color in which timer is required to be displayed. Note: If no value added then default hex values passed: Light mode: #000000 Dark mode: #ffffff If Notification background color added: #ffffff |
show_dismiss_cta | true/false | (Optional) Clicking on this CTA will dismiss the notification and log the notification dismiss event. |
Once added test the campaigns to make sure notifications are rendering as expected.
To render timer push notifications with Progress Bar
Progress bar notifications are sticky by default. Its highly recommneded to add a Dismiss CTA using the
show_dismiss_cta
key mentioned below for giving users the option to dismiss the notification.
Once your app is set up to support timer notifications, you can run progress bar push notification with timer by passing the below 'Key-values' in the 'Message' section of the push campaigns on the dashboard.
Key | Value | Description |
---|---|---|
we_custom_render | true | Required for allowing apps to render custom push notifications. |
template_type | bar | Countdown timer template with progress bar. |
future_time | epoch time in milliseconds | Add the time till when the notification is required to be displayed. Example: If you are sending a notification at 12PM and want the notification to expire by 9 PM then add the value as epoch time (in milliseconds) for 9 PM on that day |
timer_color | # 000000 {Hex color code} | (Optional) Hex code for the color in which timer is required to be displayed. If no value added then default hex values passed: Light mode: #000000 Dark mode: #ffffff If Notification background color added: #ffffff |
show_dismiss_cta | true / false | (Optional) Clicking on this CTA will dismiss the notification and log the notification dismiss event. Note: Its highly recommended to keep this true as progress bar notifications are by default sticky. |
pb_color | # 000000 {Hex color code} | Hex code for the color in which progress bar is to be displayed. Note: Supported only for Android 12 and above. If no value added then default hex values passed: Light mode: #4CAF50 Dark mode: #2196F3 |
pb_bg_color | # 000000 {Hex color code} | Hex code for the background color in which progress bar is to be displayed. Note: Supported only for Android 12 and above. If no value added then default hex values passed: Light mode: #808080 Dark mode: #dddddd |
Once added test the campaigns to make sure notifications are rendering as expected.
Understanding timer notification logic and layout
Countdown timer notification
The template logic for the countdown notification renderer is located at path com.webengage.pushtemplates.templates.CountDownRenderer
The layout for the notification is located at layout_timer_template.xml
. The view ids and layouts will be used by the NotificationConfigurator to show the notification contents.
-
View id :
@id/we_notification_container
.
The background colour of the notification will set to this view. -
View Id:
@id/we_notification_timer
.
This is the chronometer view which will act as a countdown timer for your notifications. -
<include layout="@layout/pushbase" />
This is used for adding notification header details (like app name, summary, time in devices below Android 12) -
<include layout="@layout/title" />
This is used for adding notification title to the notification. -
<include layout="@layout/description" />
This is used for adding notification description to the notification. -
<include layout="@layout/push_actions" />
This is used to add the CTA button lists to the notifications.
Timer notification with progress bar
The template logic for the countdown notification renderer is located at path com.webengage.pushtemplates.templates.ProgressBarRenderer
The template uses a foreground service to update the progress-bar. The service is located at path com.webengage.pushtemplates.services.NotificationService
.
The notification will be updated after every second with the new values for the progress bar.
The layout for the notification is located at layout_progressbar_template.xml
. The view ids and layouts will be used by the NotificationConfigurator to show the notification contents.
-
View id :
@id/we_notification_container
.
The background colour of the notification will set to this view. -
View Id:
@id/we_notification_timer
This is the chronometer view which will act as a countdown timer for your notifications. -
View Id:
@id/we_notification_progressBar
This is the progress-bar view for your notifications. -
<include layout="@layout/pushbase" />
This is used for adding notification header details (like app name, summary, time in devices below Android 12) -
<include layout="@layout/title" />
This is used for adding notification title to the notification. -
<include layout="@layout/description" />
This is used for adding notification description to the notification. -
<include layout="@layout/push_actions" />
This is used to add the CTA button lists to the notifications.
Customizing layouts and elements for timer notifications
All the elements added for timer notifications can be customized as per the desired use cases.
Customizing Max title and description length
The max lines of the title and description have been set to 2 by default.
To change the limit, go to your Template File and provide the required value in maxLines.
NotificationConfigurator().setTitleMaxLines(remoteView,maxLinesValue)
NotificationConfigurator().setDescriptionMaxLines(remoteView,maxLinesValue)
Configure the remoteView
Configure the remoteView using below method. This will set the notification background colour and header details like app name, time, summary.
whenTimeInEpoch
is the time at which the notification was received to be be shown in the notification
NotificationConfigurator().configureRemoteView(
context,remoteView, pushNotificationData, whenTimeInEpoch)
Configure the title
NotificationConfigurator().setNotificationTitle(
context,pushNotification,remoteView)
Configure the description
NotificationConfigurator().setNotificationDescription(
context,pushNotification,remoteView)
Adding the deep-link intent for notification clicks (Applicable only for Countdown timer notification)
NotificationConfigurator().setClickIntent(
context,remoteView,pushNotification)
Adding the dismiss intent for notification dismiss (Applicable only for Countdown timer notification)
NotificationConfigurator().setDismissIntent(
context,notificationBuilder,pushNotificationData)
Set the notification action intents
Configure the showDismissCTA
boolean value based on whether to show the dismiss CTA button at end of the action list.
NotificationConfigurator().setCTAList(
context,
remoteView,
pushNotification,
showDismissCTABoolean)
Set the notification timer color
NotificationConfigurator().setChronometerViewColor(
context,remoteView,pushNotificationData,timerColorHexValue)
Set the progress bar colour
NotificationConfigurator().setProgressBarColor(
remoteView, progressBarColorValue, progressBarBackgroundColorValue)
Get the pending intent for removing the notification from notification panel after clicking on it. (Applicable only for timer notification with progress bar)
Set this pending intent on the remoteView of your notification.
NotificationConfigurator().getClickAndDismissPendingIntent(
context,PushNotificationData,ctaID)
Please feel free to drop in a few lines at [email protected] in case you have any further queries. We're always just an email away!
Updated about 1 month ago