Firebase Cloud Messaging

Using Data Messages for Custom Notifications on Android

Firebase has a coherent, well engineered messaging system in place for sending push notifications to phones. At once, their stock system pretty much just runs out of the box: you configure a notification with message and body, and it gets sent to the apps. If the client app is in the background, it shows up as a notification, and if it's in the foreground, the FCM is handled by your own Service.

There are some limitations however: The PendingIntent for the stock notification always points to your app. If you want to do something else, like load a web page, you basically cannot.

Firebase provides a second style of message however, that they call "Data Messages". These messages send a map of data down to the clients, but don't necesarily have a title and body. They are handled by a custom Service that you have to build. Additionally, there is no console for sending these messages, you have to write a bit of code.

The advantage of this style of message is that they are always, regardless of if the app is in the foreground or background, handled by a custom Service. Here you can rethrow the notification with any PendingIntent that you want to, or do any other processing of the message.

First lets look at sending these messages, as there is no console. The following Python script will send a data message:

FCM_MAIN_MESSAGE_TOPIC = "main_messages"
FCM_URL_EXTRA = "url"
FCM_MESSAGE_EXTRA = "message"
FCM_MESSAGE_TITLE_EXTRA = "title"
FCM_URL_TYPE = "url_messages"
FCM_TYPE_PARAM = "type"

cred = credentials.Certificate('serviceAccountKey.json')
default_app = firebase_admin.initialize_app(cred)

message = messaging.Message(
    data={
        FCM_URL_EXTRA: 'http://www.ford.com',
        FCM_MESSAGE_EXTRA: 'Check out the Ford Motors page.',
        FCM_MESSAGE_TITLE_EXTRA: "Here is a test message",
        FCM_TYPE_PARAM: GCM_URL_TYPE
    },
    topic=FCM_MAIN_MESSAGE_TOPIC
)

response = messaging.send(message)
print('Successfully sent message:', response)

Here we are creating a "topic" channel called "url_messages" and sending out a link, a title, and a body. The intended behavior is that clicking on the notification always opens the Ford website. Again, this isn't something you can readily accomplish without using Data Messages.

For complete implementation details, see the <a href="https://firebase.google.com/docs/cloud-messaging/admin/send-messages" target="__blank">Firebase documentation on sending a message.</a>

Now lets look at the service we are using to handle incoming FCM.

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    public static final String TAG = "messagingService";
    public static final String MSG_EXTRA = "message";

    public MyFirebaseMessagingService() {
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        doLogging(remoteMessage);
        handleNow(remoteMessage);
    }

    public void doLogging(RemoteMessage remoteMessage) {
        Log.d(TAG, "From: " + remoteMessage.getFrom());
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());
        }
    }

    public void handleNow(RemoteMessage remoteMessage) {
        String msgType = remoteMessage.getData().get(Constants.FCM_TYPE_PARAM);
        if (msgType.equals(Constants.FCM_URL_TYPE)) {
            String message = remoteMessage.getData().get(Constants.FCM_MESSAGE_EXTRA);
            String title = remoteMessage.getData().get(Constants.FCM_MESSAGE_TITLE_EXTRA);
            String url = remoteMessage.getData().get(Constants.FCM_URL_EXTRA);
            if (message != null && title !=null && url != null) {
                NotificationHelper.showUrlNotification(this, message, title, url);
            } else {
                Log.e(TAG, "Null in a data field");
            }
        }
    }
}

We are essentially just peeling out the data from the message, and rethrowing a notification with a custom PendingIntent. The incoming FCM is logged for debugging purposes.

See the <a href="https://firebase.google.com/docs/cloud-messaging/android/receive">Firebase docs on receiving an FCM notification in an Android app</a> for a complete walkthrough.

In summary: If you want control of the PendingIntent attached to a FCM notification, the best path is to use Data Messages. It is straightforward to send the messages in a variety of scripting languages, as well as to receive the notification in a custom service on Android. We have also had some success processing the same data message on iOS.

BLAUHAUS Software
605 The Woods
Cherry Hill, NJ
(215)668-1062
sqh@me.com

The Blauhaus, a pun on Bauhaus, the famous school of design, was the fine arts building at Penn c/a 1995. The home of motorcycles in the hallways, and not just one gunfight, it was a center of creativity and experimentalism, a home for radical artist/academics finding their voice amid the dubious commercialism and conservative politics of the university at the time.



Fill out my online form.