Custom Templates for Push Notifications


#1

Aim : To implement Custom handling of push notifications.

Benefits :

  1. Allows rendering of notifications send from CleverTap as well as other providers like Firebase.
  2. Allows you to customise the push notification look and feel inline with your company’s branding.

Output :

Time Required : 1 Day

Steps :

  1. Update Android manifest file :
    Only the following two services should be present in your AndroidManifest file.

a. Your Custom Java Class for passing notification tokens to CleverTap/Firebase etc.

<!-- Generating Push notification tokens -->
        <service android:name=".MyNotificationTokenListener">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>

b. Your Custom Java Class to render push notifications :

    <!-- Generating Push notification tokens -->
            <service android:name=".MyNotificationRenderer">
                <intent-filter>
                    <action android:name="com.google.firebase.MESSAGING_EVENT" />
                </intent-filter>
            </service> 
  1. Create / Update Custom Notification Java classes :

a. MyNotificationTokenListener file :

    package com.example.harshshah.myapplication;

    import android.util.Log;

    import com.clevertap.android.sdk.CleverTapAPI;
    import com.clevertap.android.sdk.exceptions.CleverTapMetaDataNotFoundException;
    import com.clevertap.android.sdk.exceptions.CleverTapPermissionsNotSatisfied;
    import com.google.firebase.iid.FirebaseInstanceId;
    import com.google.firebase.iid.FirebaseInstanceIdService;

    public class MyNotificationTokenListener extends FirebaseInstanceIdService {

        private static final String TAG = "MyFirebaseIIDService";

        /**
         * Called if InstanceID token is updated. This may occur if the security of
         * the previous token had been compromised. Note that this is called when the InstanceID token
         * is initially generated so this is where you would retrieve the token.
         */
        // [START refresh_token]
        @Override
        public void onTokenRefresh() {
            // Get updated InstanceID token.
            String refreshedToken = FirebaseInstanceId.getInstance().getToken();
            Log.d(TAG, "Refreshed token: " + refreshedToken);
            try {
                // The below line passed the FCM token to CleverTap.
                // TODO also pass the device token to CleverTap in the Launcher Activity.
                CleverTapAPI.getInstance(this).data.pushFcmRegistrationId(refreshedToken,true);
            } catch (CleverTapMetaDataNotFoundException e) {
                e.printStackTrace();
            } catch (CleverTapPermissionsNotSatisfied cleverTapPermissionsNotSatisfied) {
                cleverTapPermissionsNotSatisfied.printStackTrace();
            }
            // If you want to send messages to this application instance or
            // manage this apps subscriptions on the server side, send the
            // Instance ID token to your app server.
            sendRegistrationToServer(refreshedToken);
        }
        // [END refresh_token]

        /**
         * Persist token to third-party servers.
         *
         * Modify this method to associate the user's FCM InstanceID token with any server-side account
         * maintained by your application.
         *
         * @param token The new token.
         */
        private void sendRegistrationToServer(String token) {
            // TODO: Implement this method to send token to your app server.
        }
    }

b.MyNotificationRenderer Java Class :

package com.example.harshshah.myapplication;


import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import android.widget.RemoteViews;


import com.bumptech.glide.Glide;
import com.clevertap.android.sdk.CleverTapAPI;
import com.clevertap.android.sdk.NotificationInfo;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

import java.lang.annotation.Target;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

public class MyNotificationRenderer extends FirebaseMessagingService {
    private static final String TAG = "MyFirebaseMsgService";
    RemoteViews remoteViews = null;
    String imageUrl = null;

    /**
     * Called when message is received.
     *
     * @param message Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage message) {

        try {


            if (message.getData().size() > 0) {

                Bundle extras = new Bundle();
                for (Map.Entry<String, String> entry : message.getData().entrySet()) {
                    extras.putString(entry.getKey(), entry.getValue());
                }

                NotificationInfo info = CleverTapAPI.getNotificationInfo(extras);

                if (info.fromCleverTap) {

                    if (extras.get("rich_push") != null) {
                        // Bro time to shine !
                        Intent intent = new Intent(this, RichPushNotifications.class);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                        intent.putExtras(extras);
                        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);

                        // Sending a notification without a channel id is a CRIME !!!! I will crash !!!
                            // time to render
                            NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, extras.getString("wzrk_cid"))
                                    .setSmallIcon(R.mipmap.elon).setSubText(extras.getString("subtext"))
                                    .setColor(getResources().getColor(R.color.colorAccent))
                                    .setContentIntent(pendingIntent)
                                    .setContentTitle(extras.getString("nm"))
                                    .setContentText(extras.getString("nt"))
                                    .setStyle(new NotificationCompat.BigPictureStyle().setSummaryText(extras.getString("summarytext")).setBigContentTitle(extras.getString("bigcontenttitle")).bigPicture(Glide.with(getApplicationContext()).asBitmap().load(extras.getString("wzrk_bp")).into(com.bumptech.glide.request.target.Target.SIZE_ORIGINAL, 300).get()));

                            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);

                            notificationManager.notify(1, mBuilder.build());

                    } else {
                        CleverTapAPI.createNotification(getApplicationContext(), extras);
                    }
                } else {
                    // not from CleverTap handle yourself or pass to another provider
                }


            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }


    }
}

This code is not type safe. Please add null checks.

  1. Dashboard setup :

Output :

Please do share your feedback.


#2

Additional templates for Bold, Italic and Strikethrough styles :

Output :

Moto E2 :

Code Examples :

 // Bold
Spannable sb = new SpannableString("Bold text");
sb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, sb.length(), 
 Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Intent intent = new Intent(this, RichPushNotifications.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
//intent.putExtras(extras);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);


NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, "Private")
        .setSmallIcon(R.drawable.ic_launcher_background)
        .setContentTitle(sb)
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(new NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line...")).setContentIntent(pendingIntent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);notificationManager.notify(1, mBuilder.build());


// Strike through

Spannable sb1 = new SpannableString("Strike through Text");
sb1.setSpan(new StrikethroughSpan(), 0, 19, 0);
//Intent intent = new Intent(this, RichPushNotifications.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
//intent.putExtras(extras);
//PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);


NotificationCompat.Builder mBuilder1 = new NotificationCompat.Builder(this, "Private")
        .setSmallIcon(R.drawable.ic_launcher_background)
        .setContentTitle(sb1)
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(new NotificationCompat.BigTextStyle()
                .bigText("Longer text that cannot fit one line...")).setContentIntent(pendingIntent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManagerCompat notificationManager1 = NotificationManagerCompat.from(this);
notificationManager1.notify(2, mBuilder1.build());
//Italics


Spannable sb2 = new SpannableString("Italic text");
sb2.setSpan(new StyleSpan(Typeface.ITALIC), 0, sb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Intent intent2 = new Intent(this, RichPushNotifications.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
//intent.putExtras(extras);
PendingIntent pendingIntent2 = PendingIntent.getActivity(this, 0, intent, 0);


NotificationCompat.Builder mBuilder2 = new NotificationCompat.Builder(this, "Private")
        .setSmallIcon(R.drawable.ic_launcher_background)
        .setContentTitle(sb2)
        .setContentText("Much longer text that cannot fit one line...")
        .setStyle(new NotificationCompat.BigTextStyle()
                .bigText("Much longer text that cannot fit one line...")).setContentIntent(pendingIntent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

NotificationManagerCompat notificationManager2 = NotificationManagerCompat.from(this);notificationManager2.notify(3, mBuilder2.build());

#3

CleverTap Android SDK 3.4.0 now supports Color, Subtext and Summary out of the box.

wzrk_clr = Color ( String Hex Text - https://htmlcolorcodes.com/ )
wzrk_st = Subtext Text ( String Text )
wzrk_nms = Summary Text ( String Text )

The respective key-value pairs can be added under Custom Key-Value Pairs to Use the same.