How to handle FCM notification in backgrounded Android applications

Overview

In this article we want to explain handling notifications in backgrounded applications. as you know FCM ( Firebase Cloud Messaging ) is one of the most powerful Google services that is a replacement for GCM ( Google Cloud Messaging ). According to Google it’s recommended to use FCM instead of GCM and anyone who have used GCM is encouraged to upgrade to FCM SDKs. FCM inherits GCM’s core infrastructure with lots of facilities. It should be noted that unlike GCM, FCM has a console for sending notification messages. You can study Google documents for more information and how to setup FCM in Android applications.

After setting up FCM in Android application, you can use Firebase console to send notifications. When foregrounded application receives a notification, onMessageReceived method is invoked. You should override this method to handle notification, but the problem is when the application is in the background and receives a notification, notification delivers to the device’s system tray and you can not handle notification with onMessageReceived method. When the user taps on a notification, it opens the app launcher by default. For example consider you want to do a specific task when a notification is received to the user or do something in background without the user realizing or don’t want to show notification dialog to the user, you can’t do these when the application is backgrounded. In this article we want to explain the solution.

Message Types

With FCM you can send two types of messages to clients :

  • Notification message, sometimes thought of a “display message”
  • Data message, which are handled by the client application

According to Google documents a notification message has a 2KB limit and a predefined user-visible keys. Data messages let developers send up to 4KB custom key-value pairs.

Based on the type of the message the following event happens:

So if you want to handle notification when the application is backgrounded you should send data message and use onMessageReceived method.

As you know FCM has a console to send messages to clients. With FCM console you can only send notification messages to users, so you can not use it to send data message or both to clients. In this case you should use your application server and FCM server API.

In this way you should send a JSON string to the FCM server. For notification messages use notification key. here is an example of JSON notification message :

{
"to" : “/topics/global“,
"notification" : {
"body" : “New Update Available",
"title" : “Update",
"icon" : "myicon"
}
}

To send data messages use data key. here is example of JSON data message:

{
"to" : “/topics/global“,
"data" : {
“key-1" : “value-1“,
“key-2" : “value-2“,
“key-3" : “value-3"
}
}

and JSON for both is like :

{
"to" : “/topics/global“,
"notification" : {
"body" : "New Update Available",
"title" : "Update",
"icon" : "myicon"
},
"data" : {
“key-1" : “value-1“,
“key-2" : “value-2“,
“key-3" : “value-3"
}
}

Setup FCM HTTP protocol

In this section we learn how to setup FCM HTTP protocol to pass messages from your app server to client apps via FCM. Your app server must direct all HTTP requests to this endpoint :

https://fcm.googleapis.com/fcm/send

Also you need an API KEY to send messages, you can find the API KEY in the following path:

FCM Console -> settings -> Cloud Messaging -> Server Key

After Creating your JSON formatted String, you should send a http request to FCM server url.

Here is the C# snippet to send messages to FCM server :

public static string SendNotification(string message)
{
string returnMessage = null;
var jFCMData = new JObject();
var jData = new JObject();
jData.Add("message", message);
jFCMData.Add("to", "/topics/global");
jFCMData.Add("data", jData);
var url = new Uri("https://fcm.googleapis.com/fcm/send");
try
{using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation(
"Authorization", "key=" + API_KEY);
Task.WaitAll(client.PostAsync(url,
new StringContent(jFCMData.ToString(), Encoding.Default, "application/json"))
.ContinueWith(response =>
{
returnMessage = response + "\nMessage sent";
Console.WriteLine(jFCMData.ToString());
}));
}
}
catch (Exception e)
{
throw (new Exception("Unable to send GCM message:\n" + e.StackTrace));
}
return returnMessage;
}

Conclusion

As explained below, by using FCM console you can only send notification messages. notification messages can be handled by the onMessageReceived method in foregrounded application and deliver to the device’s system tray in backgrounded application. User taps on notification and default application launcher will be opened. if you want to handle notification in every state of application you must use data message and onMessageReceived method.

There is a project on my Github named “Espionage”.I tried to control remotely android device’s camera, microphone, locations and etc with FCM service in background with no activity. Here is the link of this project :

https://github.com/shayantabatabaee/Espionage

Thanks for reading. To help others please click ❤ to recommend this article if you found it helpful.