Android Firebase notifications (FCM)

1.7k views Asked by At

I am using FCM in my app. I followed the Firebase documentation and all seems to be working as expected.

I am able to receive message notifications when the app is killed, in background and in foreground.

Now I want to give full control the user by adding some app preferences.

  • The user can disable all notification from the app settings
  • The user can change notification ringtone from the app settings

I have an idea on how to do it when the app is in killed or in the foreground. I am thinking of accessing the sharedprefs in my FirebaseMessagingService to see if the app should show the notification and check what ringtone to use. Unless there is a generic way to set those parameters, like "unsubscribing" from all notification or changing the app default notification ringtone which I am not aware of?

However I have no idea how i can do it for the notifications received when the app in is the background since the notifications are delivered to the device's system tray. Anyone has any idea or can point me to some documentation... I am not finding any info on this?

5

There are 5 answers

0
ianhanniballake On

By default, notifications affect every user. If you'd like to allow users to opt-out of all notifications (or certain subsets of notifications), you should use topic messaging: by default, you'd call subscribeToTopic() for all users and if they opt-out of notifications, you'd call unsubscribeToTopic().

By sending a notification to a topic, only the subscribed users will receive it.

The notification payload support documentation explains how to include a sound parameter to override the ringtone - on Android, that can be any sound bundled in the app's res/raw directory.

It should be noted that neither of these features are supported in the Console, but require that you create your own Firebase Cloud Messaging Server

0
Maddy On

As firebase notification service is having 2 object 1st is "data" and 2nd is "notification", when you are sending push from firebase console it sending data in "notification" object. When u handle the notification in FirebaseMessagingService.class you are creating a custom notification with NotificationBuilder. When App is in background you wont be able to create notification from "notification" object. so, your custom made notification wont be appear in notification tray, You need to push a notification from your backend and send notification contents in "data" object. You will be able to customise your notification every time. please refer this for more : https://firebase.google.com/docs/cloud-messaging/android/send-multiple

0
vishal-wadhwa On

The user can disable all notification from the app settings.

You can use shared preferences as you stated yourself. As far as a generic method is concerned you should look into @ianhanniballake 's answer.

The user can change notification ringtone from the app settings

For default ringtones refer to this link. The 3rd answer in this link also explains how to bring the sound selector from settings activity of your app. If you want custom sounds refer this.

Of course, you'll have to store user preferences so that you don't ask the user each time to select a sound.

And one more thing since you are using a service so you need not access shared preferences each and every time to find which sound to play, you can store the choice in any variable. Whenever there is a change of notif-sound by the user, you can either set a listener or {stop service -> update preferences -> restart service}. Make sure every time the service starts it reads the preferences.

0
Garg On

In this AndroidHive tutorials you can find how we change Ringtone for particular app and how to deal with notifications when app is in foreground and app is in background.

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
     ......

     // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.e(TAG, "Notification Body: " + remoteMessage.getNotification().getBody());
        handleNotification(remoteMessage.getNotification().getBody());
    }
}

When notification type message is sent, firebase automatically shows the notification when the app is in background. If the app is in foreground, handleNotification() method handles the notification message.

private void handleNotification(String message) {
    if (!NotificationUtils.isAppIsInBackground(getApplicationContext())) {
        // app is in foreground, broadcast the push message
        Intent pushNotification = new Intent(Config.PUSH_NOTIFICATION);
        pushNotification.putExtra("message", message);
        LocalBroadcastManager.getInstance(this).sendBroadcast(pushNotification);

        // play notification sound
        NotificationUtils notificationUtils = new NotificationUtils(getApplicationContext());
        notificationUtils.playNotificationSound();
    }else{
        // If the app is in background, firebase itself handles the notification
    }
}

Here you handle custom Notification Sound-

// Playing notification sound
public void playNotificationSound() {
    try {
        Uri alarmSound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE
                + "://" + mContext.getPackageName() + "/raw/notification");
        Ringtone r = RingtoneManager.getRingtone(mContext, alarmSound);
        r.play();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
1
rafsanahmad007 On

Firebase will not call your onMessageReceived when your app is in background or killed, and you can't customise your notification. System generated notification will show.

to make firebase library to call your onMessageReived in every cases

a) Foreground

b) Background

c) Killed

you must not put json key "notification" in your request to firebase api but instead use "data", see below.

For example following message will not call onMessagereceived()

  {
  "to": "/topics/test",
  "notification": {
    "title" : "title",
    "text": "data!",
    "icon": "ic_notification"
   }
}

but this will work

  {
  "to": "/topics/test",
   "data": {
       "text":"text",
       "title":"",
       "line1":"testline",
       "line2":"test"
   }
} 

see this link:https://firebase.google.com/docs/cloud-messaging/concept-options it has a detailed description of firebase message type For example:

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());
    }

    if(remoteMessage.getData().get("state").toString().equals("Request")){
        sendNotification(remoteMessage.getData().get("body").toString(), remoteMessage.getData().get("message").toString(), remoteMessage.getData().get("state").toString(),Activity_name.class);
    }
}

    private void sendNotification(String messageBody, String data, String state,Class<?> activityCompat) {
        int requestID = (int) System.currentTimeMillis();
        Intent intent = new Intent(this, activityCompat);
        Bundle bundle = new Bundle();
        bundle.putString("message", data);
        bundle.putString("state", state);
        intent.putExtras(bundle);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, requestID, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.small_logo)
                .setContentTitle("Title")
                .setContentText(messageBody).setContentIntent(pendingIntent)
                .setAutoCancel(true)
                .setStyle(new NotificationCompat.BigTextStyle()
                        .bigText(messageBody))
                .setTicker(messageBody);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationBuilder.getNotification().flags |= Notification.FLAG_AUTO_CANCEL;
        Notification notification = notificationBuilder.build();

        notificationManager.notify((int) Calendar.getInstance().getTimeInMillis(), notification);

    }