Firebase FCM notifications click_action payload

AndroidAndroid NotificationsFirebase Cloud-MessagingFirebase Notifications

Android Problem Overview


I am trying to open a particular activity when the user clicks the notification when the app is in the background. From the Docs, I have got that click_action has to be added in the payload and an intent filter in the App to handle it. But, how to add click_action in the Firebase Notifications via Firebase Console? I am open to any other Work Around too. Thanks in Advance.

Android Solutions


Solution 1 - Android

If your app is in background, Firebase will not trigger onMessageReceived(). Why.....? I have no idea. In this situation, I do not see any point in implementing FirebaseMessagingService.

According to docs, if you want to process background message arrival, you have to send 'click_action' with your message. But it is not possible if you send message from Firebase console, only via Firebase API. It means you will have to build your own "console" in order to enable marketing people to use it. So, this makes Firebase console also quite useless!

There is really good, promising, idea behind this new tool, but executed badly.

I suppose we will have to wait for new versions and improvements/fixes!

Solution 2 - Android

As far as I can tell, at this point it is not possible to set click_action in the console.

While not a strict answer to how to get the click_action set in the console, you can use curl as an alternative:

curl --header "Authorization: key=<YOUR_KEY_GOES_HERE>" --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send  -d "{\"to\":\"/topics/news\",\"notification\": {\"title\": \"Click Action Message\",\"text\": \"Sample message\",\"click_action\":\"OPEN_ACTIVITY_1\"}}"

This is an easy way to test click_action mapping. It requires an intent filter like the one specified in the FCM docs:

<intent-filter>
  <action android:name="OPEN_ACTIVITY_1" />
  <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

This also makes use of topics to set the audience. In order for this to work you will need to subscribe to a topic called "news".

FirebaseMessaging.getInstance().subscribeToTopic("news");

Even though it takes several hours to see a newly-created topic in the console, you may still send messages to it through the FCM apis.

Also, keep in mind, this will only work if the app is in the background. If it is in the foreground you will need to implement an extension of FirebaseMessagingService. In the onMessageReceived method, you will need to manually navigate to your click_action target:

    @Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    //This will give you the topic string from curl request (/topics/news)
    Log.d(TAG, "From: " + remoteMessage.getFrom());
    //This will give you the Text property in the curl request(Sample Message): 
    Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
    //This is where you get your click_action 
    Log.d(TAG, "Notification Click Action: " + remoteMessage.getNotification().getClickAction());
	//put code here to navigate based on click_action
}

As I said, at this time I cannot find a way to access notification payload properties through the console, but I thought this work around might be helpful.

Solution 3 - Android

You can handle all your actions in function of your message in onMessageReceived() in your service extending FirebaseMessagingService. In order to do that, you must send a message containing exclusively data, using for example Advanced REST client in Chrome. Then you send a POST to https://fcm.googleapis.com/fcm/send using in "Raw headers":

> Content-Type: application/json > Authorization: key=YOUR_PERSONAL_FIREBASE_WEB_API_KEY

And a json message in the field "Raw payload".

Warning, if there is the field "notification" in your json, your message will never be received when app in background in onMessageReceived(), even if there is a data field ! For example, doing that, message work just if app in foreground:

{
	"condition": " 'Symulti' in topics || 'SymultiLite' in topics",
	"priority" : "normal",
	"time_to_live" : 0,
	"notification" : {
	    "body" : "new Symulti update !",
	    "title" : "new Symulti update !",
	    "icon" : "ic_notif_symulti"
	},
	"data" : {
	    "id" : 1,
	    "text" : "new Symulti update !"
	}
}

In order to receive your message in all cases in onMessageReceived(), simply remove the "notification" field from your json !

Example:

{
	"condition": " 'Symulti' in topics || 'SymultiLite' in topics",
	"priority" : "normal",
	"time_to_live" : 0,,
	"data" : {
	    "id" : 1,
	    "text" : "new Symulti update !",
	    "link" : "href://www.symulti.com"
	}
}

and in your FirebaseMessagingService :

public class MyFirebaseMessagingService extends FirebaseMessagingService {

	private static final String TAG = "MyFirebaseMsgService";

	@Override
	public void onMessageReceived(RemoteMessage remoteMessage) {
	  String message = "";
	  obj = remoteMessage.getData().get("text");
	  if (obj != null) {
	    try {
	      message = obj.toString();
	    } catch (Exception e) {
	      message = "";
	      e.printStackTrace();
	    }
	  }

	  String link = "";
	  obj = remoteMessage.getData().get("link");
	  if (obj != null) {
	    try {
	      link = (String) obj;
	    } catch (Exception e) {
	      link = "";
	      e.printStackTrace();
	    }
	  }

	  Intent intent;
	  PendingIntent pendingIntent;
	  if (link.equals("")) { // Simply run your activity
	    intent = new Intent(this, MainActivity.class);
	    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
	  } else { // open a link
	    String url = "";
	    if (!link.equals("")) {
	      intent = new Intent(Intent.ACTION_VIEW);
	      intent.setData(Uri.parse(link));
	      intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
	    }
	  }
	  pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
	      PendingIntent.FLAG_ONE_SHOT);


	  NotificationCompat.Builder notificationBuilder = null;

	  try {
	    notificationBuilder = new NotificationCompat.Builder(this)
	        .setSmallIcon(R.drawable.ic_notif_symulti)          // don't need to pass icon with your message if it's already in your app !
	        .setContentTitle(URLDecoder.decode(getString(R.string.app_name), "UTF-8"))
	        .setContentText(URLDecoder.decode(message, "UTF-8"))
	        .setAutoCancel(true)
	        .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
	        .setContentIntent(pendingIntent);
	    } catch (UnsupportedEncodingException e) {
	      e.printStackTrace();
	    }

	    if (notificationBuilder != null) {
	      NotificationManager notificationManager =
	          (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
	      notificationManager.notify(id, notificationBuilder.build());
	    } else {
	      Log.d(TAG, "error NotificationManager");
	    }
	  }
	}
}

Enjoy !

Solution 4 - Android

This falls into workaround category, containing some extra information too:

Since the notifications are handled differently depending on the state of the app (foreground/background/not launched) I've seen the best way to implement a helper class where the selected activity is launched based on the custom data sent in the notification message.

  • when the app is on foreground use the helper class in onMessageReceived
  • when the app is on background use the helper class for handling the intent in main activity's onNewIntent (check for specific custom data)
  • when the app is not running use the helper class for handling the intent in main activity's onCreate (call getIntent for the intent).

This way you do not need the click_action or intent filter specific to it. Also you write the code just once and can reasonably easily start any activity.

So the minimum custom data would look something like this:

Key: run_activity
Value: com.mypackage.myactivity

And the code for handling it:

if (intent.hasExtra("run_activity")) {
    handleFirebaseNotificationIntent(intent);
}


private void handleFirebaseNotificationIntent(Intent intent){
    String className = intent.getStringExtra("run_activity");
    startSelectedActivity(className, intent.getExtras());
}

private void startSelectedActivity(String className, Bundle extras){
    Class cls;
    try {
        cls = Class.forName(className);
    }catch(ClassNotFoundException e){
        ...
    }
    Intent i = new Intent(context, cls);

    if (i != null) {
        i.putExtras(extras);
        this.startActivity(i);
    } 
}

That is the code for the last two cases, startSelectedActivity would be called also from onMessageReceived (first case).

The limitation is that all the data in the intent extras are strings, so you may need to handle that somehow in the activity itself. Also, this is simplified, you probably don't what to change the Activity/View on an app that is on the foreground without warning your user.

Solution 5 - Android

Well this is clear from firebase docs that your onMessageReceived will not work when app is in background.

When your app is in background and click on your notification your default launcher will be launched. To launch your desired activity you need to specify click_action in your notification payload.

$noti = array
    (
    'icon' => 'new',
    'title' => 'title',
    'body' => 'new msg',
    'click_action' => 'your activity name comes here'
); 

And in your android.manifest file

Add the following code where you registered your activity

     <activity
                android:name="your activity name">
                <intent-filter>
                    <action android:name="your activity name" />
                   <category android:name="android.intent.category.DEFAULT"/>
               </intent-filter>
   </activity>

Solution 6 - Android

If your app is in background, Firebase will not trigger onMessageReceived(). onMessageReceived() is called when app is in foreground . When app is in background,onMessageReceived() method will be called only if the body of https://fcm.googleapis.com/fcm/send contain only data payload.Here ,i just created a method to build custom notification with intent having ur your required activity . and called this method in onMessageRecevied() .

In PostMan:

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

header:Authorization:key=ur key

body --->>

{  "data" : {
      "Nick" : "Mario",
      "Room" : "PoSDenmark",
      
    },

  "to" : "xxxxxxxxx"
  
}

in your application.

class MyFirebaseMessagingService  extends FirebaseMessagingService {

 public void onMessageReceived(RemoteMessage remoteMessage) {
       if (remoteMessage.getData().size() > 0) {
           sendNotification("ur message body") ;
        }
    }
private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, Main2Activity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_ic_notification)
                .setContentTitle("FCM Message")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }

 }

when the data payload comes to the mobile,then onMessageReceived() method will be called.. inside that method ,i just made a custom notification. this will work even if ur app is background or foreground.

Solution 7 - Android

Update:

So just to verify, it is not currently possible to set the click_action parameter via the Firebase Console.


So I've been trying to do this in the Firebase Notifications Console with no luck. Since I can't seem to find anywhere to place the click_action value in the console, what I mainly did to test this out is to add a custom key/value pair in the Notification (Advance Options > Custom Data):

Key: click_action
Value: <your_preferred_value>

then tried calling RemoteMessage.getNotification().getClickAction() in onMessageReceived() to see if it was retrieving the correct value, but it always returns null. So next I tried calling RemoteMessage.getData().get(< specified_key >) and was able to retrieve the value I added.

NOTE: I am not entirely sure if that is okay to be used as a workaround, or if it's against best practice. I would suggest using your own app server but your post is specific to the Firebase Console.

The way the client app and the notification behaves still depends on how you program it. With that said, I think you can use the above as a workaround, using the value retrieved from the getData(), then having the Notification call this or that. Hope this helps somehow. Cheers! :D

Solution 8 - Android

Now it is possible to set click_action in Firebase Console. You just go to notifications-send message-advanced option and there you will have two fields for key and value. In first field you put click_action and in second you put some text which represents value of that action. And you add intent-filter in your Manifest and give him the same value as you wrote in console. And that is simulation of real click_action.

Solution 9 - Android

there is dual method for fcm fcm messaging notification and app notification in first your app reciever only message notification with body ,title and you can add color ,vibration not working,sound default. in 2nd you can full control what happen when you recieve message example onMessageReciever(RemoteMessage rMessage){ notification.setContentTitle(rMessage.getData().get("yourKey")); } you will recieve data with(yourKey) but that not from fcm message that from fcm cloud functions reguard

Solution 10 - Android

In Web, simply add the url you want to open:

{  
  "condition": "'test-topic' in topics || 'test-topic-2' in topics",  
  "notification": {
            "title": "FCM Message with condition and link",
            "body": "This is a Firebase Cloud Messaging Topic Message!",            
            "click_action": "https://yoururl.here"
        }
}

Solution 11 - Android

One simple work around is, in the fcm options - add / as the link value, the background notification click will be redirected to the app.

Solution 12 - Android

I'm looking this Firebase is , development from google cloud messaging push notification fundamental so we can use the gcm tutorial,function and implementation in firebase , i using funtion of gcm push notification function to solve this click_action problem i use gcm function **

> 'notificationclick'

** try this save url click_action in variable url this is in server-worker.js

var url =  "";

messaging.setBackgroundMessageHandler(function(payload) {

  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  // Customize notification here
  url = payload.data.click_action;
  
  const notificationTitle = payload.data.title;
  const notificationOptions = {
    body: payload.data.body , 
    icon: 'firebase-logo.png'
  };

  return self.registration.showNotification(notificationTitle,
      notificationOptions);

});


   //i got this in google cloud messaging push notification


self.addEventListener('notificationclick', function (event) {
  event.notification.close();

  var clickResponsePromise = Promise.resolve();
    clickResponsePromise = clients.openWindow(url);

  event.waitUntil(Promise.all([clickResponsePromise, self.analytics.trackEvent('notification-click')]));
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHariharan BView Question on Stackoverflow
Solution 1 - AndroidBozic NebojsaView Answer on Stackoverflow
Solution 2 - AndroidmaddesaView Answer on Stackoverflow
Solution 3 - AndroidMaxime AncelinView Answer on Stackoverflow
Solution 4 - AndroiddiiduView Answer on Stackoverflow
Solution 5 - Androidgagan bhutaniView Answer on Stackoverflow
Solution 6 - Androidchandan rajView Answer on Stackoverflow
Solution 7 - AndroidAL.View Answer on Stackoverflow
Solution 8 - AndroidAtenicaView Answer on Stackoverflow
Solution 9 - Androidإياد الفوازView Answer on Stackoverflow
Solution 10 - AndroidRobert BenyiView Answer on Stackoverflow
Solution 11 - Androidpavithra ramasamyView Answer on Stackoverflow
Solution 12 - AndroidOdin WagesView Answer on Stackoverflow