Replace FCM Notification With Programmatically Created Notification

Viewed 842

I have switched over to using FCM for my application. When my app is open, I handle the messages manually and if the Fragment which contains the message list isn't displayed, then I have the code display a Notification. To display the Notification I use the function:

public void notify(int id, Notification notification)

The problem I am encountering is if my application is in the background, FCM displays a Notification. I even set the tag parameter on the server so only one Notification will be displayed for the application. If the user opens the application without clicking on the Notification, and then received a message, a separate Notification is displayed, which is not what I want. I switched to using the function:

public void notify(String tag, int id, Notification notification)

And using the same tag as the server uses for the FCM message still produces a second notification. Is there a way the Notification I create programmatically can replace the Notification created by FCM?

2 Answers

Please be aware that FCM handles messages with pure Notification or Data payloads differently. Please check your message to see which kind you are sending and check Firebase documentation.

I had the issue of when I had a certain Activity running that I did not want to receive a Notification. So I created a static utility class that kept a boolean property indicating if that Activity was active. In my Notification receiver I check this value and either issued the notification or not. Like this:

My static utility class:

public class MyRunningActivity {

    private static boolean isActivityRunning = false;

    public static void setIsRunningActivity(boolean isRunning){
        isActivityRunning = isRunning;
    }

    public static boolean getIsRunningActivity(){
        return isActivityRunning;
    }
}

Within the class that receives the onMessageReceived:

   @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        String notification = "";
        String title = "";
        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            title = getDataWithKey(remoteMessage.getData(), "title");
            notification = getDataWithKey(remoteMessage.getData(), "body");
        }

        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            notification = remoteMessage.getNotification().getBody();
            title = remoteMessage.getNotification().getTitle();
        }

        sendNotification(title, notification);
    }


private void sendNotification(String notificationTitle, String notificationBody) {
    try{

        Intent intent = new Intent(this, MyActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NO_ANIMATION);

        //Generate a new 'unique' request code -- this helps to refresh the activity if it is already active
        int requestCode = CodeGenerator.getRandomNumber(10, 10000);

        PendingIntent pendingIntent = null;

        // If the Activity is active then this will keep the notification from being sent
        // But the intent Extras will be delivered to the OnNewIntent method and handled there.
        // I had to put the singleTop flag in the Manifest, otherwise this will cause the
        // activity to close and reopen....
        try {
            if(MyRunningActivityUtility.getIsRunningActivity()) {
                    intent.putExtra("add_ring_tone","true");
                    pendingIntent = PendingIntent.getActivity(this,
                                              requestCode,
                                              intent,
                                              PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT
                    );

                    pendingIntent.send();
                    \\ !!! Notice that return here prevents the Notification from being sent !!!
                    return;
                }
            }
        }
        catch (Exception ex1){
            Log.e(TAG, ex1.getMessage());
        }

        pendingIntent = PendingIntent.getActivity(this,
                                  requestCode,
                                  intent,
                                  PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT
        );


        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = (android.support.v7.app.NotificationCompat.Builder)
                new NotificationCompat.Builder(this)
                        .setSmallIcon(R.mipmap.your_custom_icon)
                        .setContentTitle(notificationTitle)
                        .setContentText(notificationBody)
                        .setAutoCancel(true)
                        .setSound(defaultSoundUri)
                        .setContentIntent(pendingIntent)

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

        int idNot = CodeGenerator.getRandomNumber(10, 10000);
        notificationManager.notify(idNot, notificationBuilder.build());
    }
    catch (Exception ex){
        Log.e(TAG, ex.getMessage());
    }
}

There might be some things in this example you don't need.

That's because you are receiving FCM Notification messages:

Notification messages are delivered to the notification tray when the app is in the background. For apps in the foreground, messages are handled by these callbacks:

didReceiveRemoteNotification: on iOS
onMessageReceived() on Android.

You should receive FCM Data messages instead and create the notification programatically:

Client app is responsible for processing data messages.

Documentation

Related