162

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());
    }

}
marco
  • 3,193
  • 4
  • 28
  • 51
  • firebase has nothing to do with how YOU are creating the notification, please provide an image as to what you are seeing – tyczj May 19 '16 at 13:51
  • 1
    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 messages – marco May 19 '16 at 14:00
  • 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 FCM – tyczj May 19 '16 at 14:08
  • 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). – shinypenguin May 19 '16 at 18:40
  • @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. – marco May 19 '16 at 18:49
  • 1
    http://codingaffairs.blogspot.com/2016/06/firebase-cloud-messaging-push.html – Developine Jun 20 '16 at 08:08
  • 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? – superUser Jul 20 '16 at 01:24

10 Answers10

305

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.

Ian Barber
  • 19,765
  • 3
  • 58
  • 58
  • 2
    @Ian Barber: any plan at Google to change this behavior in the near future ? – skylve Jun 07 '16 at 17:15
  • 1
    The team is aware of the issue and is working on a fix. – Arthur Thompson Jun 08 '16 at 14:14
  • Its better to use OneSignal to send push notifications which is also free. – Passiondroid Jun 30 '16 at 18:07
  • 1
    any update on this? thought I'd ask because there have been circumstances when a Google engineer simply forgot to push the patch. – CQM Aug 17 '16 at 23:09
  • The legacy GCM library is having the same issue. Firebase just inherited it. – Gabor Aug 25 '16 at 19:31
  • @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? – Maverick283 Sep 24 '16 at 10:55
  • 1
    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. – Ian Barber Sep 26 '16 at 19:13
  • 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? – Groovee60 Oct 05 '16 at 19:58
  • 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? – X09 Oct 07 '16 at 10:31
  • @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. – Austyn Mahoney Oct 24 '16 at 22:15
  • 1
    Actually this was a good day to bug! The new SDK released today has an override, and I've updated my answer. – Ian Barber Oct 24 '16 at 22:59
  • @IanBarber Awesome, thanks! How do you customize the icon when sending from the APIs? Does that work before `v9.6.1`? – Austyn Mahoney Oct 25 '16 at 19:30
  • Gabor: best route might be to file a ticket with support with your app specific details: https://firebase.google.com/support/contact/troubleshooting/ – Ian Barber Oct 29 '16 at 00:40
  • 1
    Austyn: for the API see https://firebase.google.com/docs/cloud-messaging/http-server-ref "icon" parameter – Ian Barber Oct 29 '16 at 00:41
  • 1
    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? – parohy Nov 16 '16 at 08:45
  • 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. – zaifrun Nov 18 '16 at 16:13
  • 7
    Ah, I got it to work with 9.8.0. To help others, remember your status bar icon must live up to the requirements: https://developer.android.com/guide/practices/ui_guidelines/icon_design_status_bar.html. Mine did not and therefore firebase just defaults to the standard whitesquare instead of using the icon specified in the manifest. – zaifrun Nov 20 '16 at 11:46
  • 5
    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. – riper Dec 28 '16 at 17:12
  • 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. – Ebin Joy Apr 28 '17 at 07:31
  • 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. – fdermishin Feb 27 '18 at 09:21
  • see official documentation https://firebase.google.com/docs/cloud-messaging/android/topic-messaging#edit-the-app-manifest – Deni Erdyneev Apr 07 '18 at 13:14
  • @IanBarber, I am able to display the correct icon, but why is it in grayscale? – Bargain23 Apr 27 '18 at 15:11
  • I had to add tools:replace="android:resource" to notificaiton color meta data and xmlns:tools="http://schemas.android.com/tools" to manifest for this code to work – Necmettin Sargın Nov 11 '20 at 13:34
  • 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? – Karolina Hagegård Feb 11 '21 at 13:58
  • With @dmarquina's answer further down, I found that `` has to be a child of ``, not the root `` node. – kubi Jun 09 '22 at 07:33
44

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

geekoraul
  • 2,623
  • 2
  • 21
  • 33
  • 2
    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. – racs May 30 '16 at 04:25
  • 1
    yes agree. this should be marked as a correct answer. or my answer below :) – Developine Jun 24 '16 at 17:26
  • 4
    Nope, it is not feasible for people who need to maintain compatibility with other clients / legacy versions that expect a notification. – Gabor Aug 25 '16 at 19:36
  • 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. – Gabor Oct 11 '16 at 19:37
  • I was pointing out that your "solution" would require a backend change which is not an option sometimes. – Gabor Oct 26 '16 at 22:38
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"/>
Community
  • 1
  • 1
Jan Hartwig
  • 139
  • 4
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());
    }
}
Carlo Conserva
  • 273
  • 3
  • 8
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

brook
  • 83
  • 3
  • 14
4

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

rattisuk
  • 407
  • 5
  • 7
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.

ATom
  • 15,960
  • 6
  • 46
  • 50
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

dmarquina
  • 3,728
  • 1
  • 28
  • 28
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);
    }
Gonzalo
  • 468
  • 1
  • 7
  • 17
  • 1
    Got it! my tags are out of tag in AndroidManifest.xml Here i hot the answer http://stackoverflow.com/a/37352142/6366150 – Gonzalo May 24 '16 at 03:34
  • 1
    Only works with foreground app running... in background still getting the same previous behavior – Gonzalo May 24 '16 at 03:43
  • when app in forground that custome notification icon is coming nd working fine but in app background getting white square icon please help me – Harsha Nov 24 '16 at 11:45
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.

Charles A.
  • 10,685
  • 1
  • 42
  • 39
  • Same goes for the `default_notification_color` meta, it needs to be a `android:resource` - setting as `android:value` will not work – flochtililoch Jan 14 '20 at 15:58