Notification Icon with the new Firebase Cloud Messaging system
Asked Answered
T

11

163

Yesterday Google presented at Google I/O the new notification system based on the new Firebase. I tried this new FCM ( Firebase Cloud Messaging ) with the example on Github.

The icon of the notification is always the ic_launcher despite I have declared a specific drawable

Why ? Here below the official code for handling the message

public class AppFirebaseMessagingService extends FirebaseMessagingService {

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // If the application is in the foreground handle both data and notification messages here.
        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
        sendNotification(remoteMessage);
    }
    // [END receive_message]

    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param remoteMessage FCM RemoteMessage received.
     */
    private void sendNotification(RemoteMessage remoteMessage) {

        Intent intent = new Intent(this, MainActivity.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);

// this is a my insertion looking for a solution
        int icon = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? R.drawable.myicon: R.mipmap.myicon;
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(icon)
                .setContentTitle(remoteMessage.getFrom())
                .setContentText(remoteMessage.getNotification().getBody())
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

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

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

}
Trajectory answered 19/5, 2016 at 13:41 Comment(7)
firebase has nothing to do with how YOU are creating the notification, please provide an image as to what you are seeingLithesome
exact. this code comes straight from Firebase and sendNotification() method is exactly the same for any notification. This code works fine with GCM, but with FCM no. it always remains ic_launcher, using the new web interface to send messagesTrajectory
you set the small icon but not the large icon, unless you are sending a push with the notification tag in the push payload it has nothing to do with FCMLithesome
Does it show your custom notification icon when the app is in the foreground? That works for me. However, when the app is in the background it must use some kind of default FCM handler, since all notification settings are ignored (icon, sound, lights, vibrate, etc can't be customized).Locarno
@shinypenguin, you are right! I hadn't noticed that even other parameters cannot be customized. And yes, the icon works when then app is in the foreground as you said.Trajectory
codingaffairs.blogspot.com/2016/06/…Claro
This may be happening because the firebase console sends another structure notification instead of data which is the one people uses for manipulate the android notification...are you sending from console?Assoil
A
307

Unfortunately this was a limitation of Firebase Notifications in SDK 9.0.0-9.6.1. When the app is in the background the launcher icon is use from the manifest (with the requisite Android tinting) for messages sent from the console.

With SDK 9.8.0 however, you can override the default! In your AndroidManifest.xml you can set the following fields to customise the icon and color:

<meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/notification_icon" />
<meta-data android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/google_blue" />

Note that if the app is in the foreground (or a data message is sent) you can completely use your own logic to customise the display. You can also always customise the icon if sending the message from the HTTP/XMPP APIs.

Alcorn answered 19/5, 2016 at 19:34 Comment(25)
@Ian Barber: any plan at Google to change this behavior in the near future ?Shanika
The team is aware of the issue and is working on a fix.Maishamaisie
Its better to use OneSignal to send push notifications which is also free.Lillylillywhite
any update on this? thought I'd ask because there have been circumstances when a Google engineer simply forgot to push the patch.Rotunda
The legacy GCM library is having the same issue. Firebase just inherited it.Croom
@IanBarber so whats the status on the issue? I don't want to open up a new issue on github just for that question.... Anything to fix it insight yet?Coppersmith
Still going - sorry, the process has been quite convoluted for a variety of internal reasons. Hopefully we'll have an option in the next release.Alcorn
As of today, the current behavior (message from Firebase Console, application in background) is to show the application icon from the manifest. But now it retains its color instead of flattening it (perhaps to an illegible white square). I didn't know that was even possible. Is this as expected? While the icon may be more legible in the status bar, it is surely out of spec to be colored for this OS version. Why doesn't Firebase support the concept of a notification icon tag in the manifest like Parse does?Hostler
As at today, for apps in background, it shows an almost illegible version of the app icon (colored) in the status bar. When you slide down to click on the notification, what you see is an icon the shape of a donut. A white circle with a transparent hole in the center. I wonder how we are supposed to use this for production build. Since firebase can access the app icon why doesn't it allow us to declare our own notification icon in manifest like Groovee60 suggested?Shermy
@IanBarber Sorry to bug you more, but do you have a status on this fix? If not, we are going to change our notifications to always be data messages, which seems like a bad hack.Svensen
Actually this was a good day to bug! The new SDK released today has an override, and I've updated my answer.Alcorn
@IanBarber Awesome, thanks! How do you customize the icon when sending from the APIs? Does that work before v9.6.1?Svensen
Gabor: best route might be to file a ticket with support with your app specific details: firebase.google.com/support/contact/troubleshootingAlcorn
Austyn: for the API see firebase.google.com/docs/cloud-messaging/http-server-ref "icon" parameterAlcorn
This does not helped me. I still have the white square. Also, how can I override or set a large icon? What is the resource name for that one?Histone
Same as parohy here. Using 9.8.0 I still just get the white square, even though I have set the icon to my own in the manifest file.Hinder
Ah, I got it to work with 9.8.0. To help others, remember your status bar icon must live up to the requirements: developer.android.com/guide/practices/ui_guidelines/…. Mine did not and therefore firebase just defaults to the standard whitesquare instead of using the icon specified in the manifest.Hinder
If you happen to try this and find that the icon is smaller than other notifications, make sure you're using a vector drawable (and not a png). That solved it for me.Ceil
Default vibration and sound is also not working when App is on background since onMessageReceived(RemoteMessage remoteMessage) not called. Is there any similar way to integrate default notification sound and vibration while notification.Vino
I tried it and it works only on API 27 and higher. When I run my application on API 25, the default icon specified in manifest using android:icon is displayed.Peignoir
see official documentation firebase.google.com/docs/cloud-messaging/android/…Inexperience
@IanBarber, I am able to display the correct icon, but why is it in grayscale?Dunkle
I had to add tools:replace="android:resource" to notificaiton color meta data and xmlns:tools="schemas.android.com/tools" to manifest for this code to workLulululuabourg
The default_notification_icon meta-data worked fine, after I made my own Image Asset - Notification Icon in Android/app/src/main/res... But the "@color/google_blue" does not exist, according to Android Studio... Where do I specify that?Faldstool
With @dmarquina's answer further down, I found that <meta-data> has to be a child of <application>, not the root <manifest> node.Conceal
A
45

Use a server implementation to send messages to your client and use data type of messages rather than notification type of messages.

This will help you get a callback to onMessageReceived irrespective if your app is in background or foreground and you can generate your custom notification then

Abc answered 27/5, 2016 at 18:19 Comment(5)
This is the suggested solution in the Firebase docs too, you can show the notification in any way you prefer if you rely on the data push instead of the notification.Atmospherics
yes agree. this should be marked as a correct answer. or my answer below :)Claro
Nope, it is not feasible for people who need to maintain compatibility with other clients / legacy versions that expect a notification.Croom
We have apps in production that already expect a notification type of push and we have extended that (complex) backend component to add data for new clients. But we can't remove support for legacy versions of our app.Croom
I was pointing out that your "solution" would require a backend change which is not an option sometimes.Croom
J
13

atm they are working on that issue https://github.com/firebase/quickstart-android/issues/4

when you send a notification from the Firebase console is uses your app icon by default, and the Android system will turn that icon solid white when in the notification bar.

If you are unhappy with that result you should implement FirebaseMessagingService and create the notifications manually when you receive a message. We are working on a way to improve this but for now that's the only way.

edit: with SDK 9.8.0 add to AndroidManifest.xml

<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/my_favorite_pic"/>
Jankey answered 26/5, 2016 at 13:57 Comment(1)
how to display customized icon notification tray in marshmallowHazeghi
E
6

My solution is similar to ATom's one, but easier to implement. You don't need to create a class that shadows FirebaseMessagingService completely, you can just override the method that receives the Intent (which is public, at least in version 9.6.1) and take the information to be displayed from the extras. The "hacky" part is that the method name is indeed obfuscated and is gonna change every time you update the Firebase sdk to a new version, but you can look it up quickly by inspecting FirebaseMessagingService with Android Studio and looking for a public method that takes an Intent as the only parameter. In version 9.6.1 it's called zzm. Here's how my service looks like:

public class MyNotificationService extends FirebaseMessagingService {

    public void onMessageReceived(RemoteMessage remoteMessage) {
        // do nothing
    }

    @Override
    public void zzm(Intent intent) {
        Intent launchIntent = new Intent(this, SplashScreenActivity.class);
        launchIntent.setAction(Intent.ACTION_MAIN);
        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* R    equest code */, launchIntent,
                PendingIntent.FLAG_ONE_SHOT);
        Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(),
                R.mipmap.ic_launcher);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_notification)
                .setLargeIcon(rawBitmap)
                .setContentTitle(intent.getStringExtra("gcm.notification.title"))
                .setContentText(intent.getStringExtra("gcm.notification.body"))
                .setAutoCancel(true)
                .setContentIntent(pendingIntent);

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

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}
Emmenagogue answered 17/10, 2016 at 15:26 Comment(1)
gcm.notification.title for key name is 100% safe for all versions?Hyo
A
5

if your app is in background the notification icon will be set onMessage Receive method but if you app is in foreground the notification icon will be the one you defined on manifest

enter image description here

Allhallowmas answered 16/12, 2017 at 13:24 Comment(0)
S
4

Just set targetSdkVersion to 19. The notification icon will be colored. Then wait for Firebase to fix this issue.

Stagemanage answered 20/6, 2016 at 17:55 Comment(2)
:D Wow, so where's the list of side effects?Scherman
@EugenPechanec yes, the trade off is that you may not be able to use some API which available on 20+Ship
S
3

There is also one ugly but working way. Decompile FirebaseMessagingService.class and modify it's behavior. Then just put the class to the right package in yout app and dex use it instead of the class in the messaging lib itself. It is quite easy and working.

There is method:

private void zzo(Intent intent) {
    Bundle bundle = intent.getExtras();
    bundle.remove("android.support.content.wakelockid");
    if (zza.zzac(bundle)) {  // true if msg is notification sent from FirebaseConsole
        if (!zza.zzdc((Context)this)) { // true if app is on foreground
            zza.zzer((Context)this).zzas(bundle); // create notification
            return;
        }
        // parse notification data to allow use it in onMessageReceived whe app is on foreground
        if (FirebaseMessagingService.zzav(bundle)) {
            zzb.zzo((Context)this, intent);
        }
    }
    this.onMessageReceived(new RemoteMessage(bundle));
}

This code is from version 9.4.0, method will have different names in different version because of obfuscation.

Subcritical answered 4/9, 2016 at 18:46 Comment(0)
A
3

write this

<meta-data 
         android:name="com.google.firebase.messaging.default_notification_icon"
         android:resource="@drawable/ic_notification" />

right down <application.....>

enter image description here

Aesthetic answered 11/6, 2019 at 16:51 Comment(1)
doesn't work for meScavenge
E
2

I'm triggering my notifications from FCM console and through HTTP/JSON ... with the same result.

I can handle the title, full message, but the icon is always a default white circle:

Notification screenshot

Instead of my custom icon in the code (setSmallIcon or setSmallIcon) or default icon from the app:

 Intent intent = new Intent(this, MainActivity.class);
    // use System.currentTimeMillis() to have a unique ID for the pending intent
    PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);

    if (Build.VERSION.SDK_INT < 16) {
        Notification n  = new Notification.Builder(this)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pIntent)
                .setAutoCancel(true).getNotification();
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //notificationManager.notify(0, n);
        notificationManager.notify(id, n);
    } else {
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

        Notification n  = new Notification.Builder(this)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setSmallIcon(R.drawable.ic_stat_ic_notification)
                .setLargeIcon(bm)
                .setContentIntent(pIntent)
                .setAutoCancel(true).build();

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //notificationManager.notify(0, n);
        notificationManager.notify(id, n);
    }
Estaestablish answered 22/5, 2016 at 0:55 Comment(3)
Got it! my <service> tags are out of <application> tag in AndroidManifest.xml Here i hot the answer https://mcmap.net/q/151741/-firebase-cloud-messaging-notification-not-received-by-deviceEstaestablish
Only works with foreground app running... in background still getting the same previous behaviorEstaestablish
when app in forground that custome notification icon is coming nd working fine but in app background getting white square icon please help meHazeghi
N
1

add this outside the activity tag inside the application tag :

<meta-data
   android:name="com.google.firebase.messaging.default_notification_icon"
   android:resource="@mipmap/notification"
/>

and make sure you copy the notification file into all directories mipmap-* with your custom resolution.

Nighthawk answered 1/10, 2023 at 15:52 Comment(0)
D
0

Thought I would add an answer to this one, since my problem was simple but hard to notice. In particular I had copy/pasted an existing meta-data element when creating my com.google.firebase.messaging.default_notification_icon, which used an android:value tag to specify its value. This will not work for the notification icon, and once I changed it to android:resource everything worked as expected.

Danforth answered 13/6, 2019 at 19:40 Comment(1)
Same goes for the default_notification_color meta, it needs to be a android:resource - setting as android:value will not workScholastic

© 2022 - 2024 — McMap. All rights reserved.