firebase / flutterfire

🔥 A collection of Firebase plugins for Flutter apps.
https://firebase.google.com/docs/flutter/setup
BSD 3-Clause "New" or "Revised" License
8.63k stars 3.95k forks source link

[firebase_messaging] Notification banner not showing on Android #1327

Closed MichaelM97 closed 3 years ago

MichaelM97 commented 4 years ago

When receiving an FCM from cloud functions in a Flutter app, on iOS the notification appears with a banner and in the system tray as expected. However, on Android the notification appears straight in the system tray without displaying a banner.

Shouldn't the behaviour be the same for both platforms when sending the exact same FCM?

Here is the FCM:

const payload = {
          notification: {
            title: 'You have a new message!',
            body: 'Tap to reply'
          },
          data: {
            click_action: 'FLUTTER_NOTIFICATION_CLICK',
            uid: sendingUserID
          }
        };

const options = {
      priority: 'high'
    };

admin.messaging().sendToDevice(token, payload, options);

Is there additional flag that I can set in options or the payload?

iapicca commented 4 years ago

Hi @MichaelM97 could you please provide your flutter doctor -v and your flutter run --verbose. Thank you

MichaelM97 commented 4 years ago

For flutter run --verbose is there any specific information you're looking for? As the output for that is ~20000 lines. If it's dependency versions, they are as follows

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  firebase_core: ^0.4.0+9
  firebase_auth: ^0.14.0+5
  cloud_firestore: ^0.12.9+5
  cloud_functions: ^0.4.1+1
  firebase_storage: ^3.0.6
  geoflutterfire: ^2.0.3+5
  firebase_messaging: ^5.1.6

flutter doctor -v

[✓] Flutter (Channel stable, v1.9.1+hotfix.6, on Mac OS X 10.14.6 18G103, locale
    en-GB)
    • Flutter version 1.9.1+hotfix.6 at
      /Users/michaelmccormick/development/flutter
    • Framework revision 68587a0916 (8 weeks ago), 2019-09-13 19:46:58 -0700
    • Engine revision b863200c37
    • Dart version 2.5.0

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.0)
    • Android SDK at /Users/michaelmccormick/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-29, build-tools 29.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.0, Build version 11A420a
    • CocoaPods version 1.7.1

[✓] Android Studio (version 3.5)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 40.2.2
    • Dart plugin version 191.8593
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)

[!] Connected device
    ! No devices available

! Doctor found issues in 1 category.
nicolasvahidzein commented 4 years ago

Hello, i am getting this exact same problem. What gives?

lexyfeito commented 4 years ago

Any news on this? i am ran into the same problem.

Ehesp commented 4 years ago

FCM only displaying notifications when the app in the background or quit, not when in the foreground. You can use the https://pub.dev/packages/flutter_local_notifications to display a banner style notification - the channel must have a high priority.

Leaving open for documentation improvements.

nicolasvahidzein commented 4 years ago

I know all this @Ehesp Elliot. I cant even get it to show up high priority from the fcm console. Can you explain simply how to get it done with the least complication from fcm and ill get it working from whatever stack. Thanks.

Ehesp commented 4 years ago

I cant even get it to show up high priority from the fcm console.

What do you mean by show up high priority? Do you mean when on a different app on the device you want it to appear over the top (as a banner?)

nicolasvahidzein commented 4 years ago

Exactly. Trying for 3 weeks. Impossible.

nicolasvahidzein commented 4 years ago

@Ehesp Any way you can help me with this?

MichaelM97 commented 4 years ago

FCM only displaying notifications when the app in the background or quit, not when in the foreground. You can use the https://pub.dev/packages/flutter_local_notifications to display a banner style notification - the channel must have a high priority.

Leaving open for documentation improvements.

Hi @Ehesp, this issue was in relation to FCM not displaying notifications correctly even when the app is in the background or closed. The notification would appear in the notification tray, however, would not "pop down" or shown the notification banner on receiving the notification.

I haven't re-tested this since raising, so I'll give it another go across the coming week with the latest Flutter FCM package versions to see if it's fixed. If it isn't, I'll record the problem and attach it to this issue.

Ehesp commented 4 years ago

The notification would appear in the notification tray, however, would not "pop down" or shown the notification banner on receiving the notification.

This is because the channel it's using (defaulting to one FCM creates) has a "default" importance level. You need to create the channel with high importance via the local notifications plugin, then add the channel ID within the Android Manifest (see https://stackoverflow.com/questions/46047343/firebase-how-to-set-default-notification-channel-in-android-app).

That should then show it as a heads-up notification.

nicolasvahidzein commented 4 years ago

Will try it right now thank you so much.

nicolasvahidzein commented 4 years ago

@MichaelM97 Michael, why would we need a nother flutter package when this is not handle by flutter at all? What does this package do? The setup code from firebase cloud messaging already handles the bridging from android to the flutter portion of the app. Our problem is located between the phone os layer and app background which is not related to flutter. Please clarify. @Ehesp Elliot, what do you think about that reasoning?

nicolasvahidzein commented 4 years ago

What i don't understand here is that it seems a lot of this code is related to android channels which we can't easily do in flutter: https://medium.com/exploring-android/exploring-android-o-notification-channels-94cd274f604c in that android code i do see how we can create a notification channel and assign it a "high" priority.

int importance = NotificationManager.IMPORTANCE_LOW;

this is what i think we need but like i said this code is android code.

MichaelM97 commented 4 years ago

Okay, I've got this working. Thanks for the help @Ehesp

IMO the below steps should be added to the README (I've raised #2487 for this), as I presume most people will assume that heads up notifications are configured "out of the box" on Android as they are on iOS

  1. Add the following to your strings.xml. Of course you'll want to customise these for your own app, and be aware that the channel name and channel description are what the user will see in their notification settings.

    <string name="notification_channel_id" translatable="false">my_unique_fcm_id</string>
    <string name="notification_channel_name">The name of this notification</string>
    <string name="notification_channel_desc">A description of the notification.</string>
  2. Register the new notification channel by adding the following code to your app (Java version here). This should be done as early as possible, for example, after calling super.onCreate in MainActivity.kt (or .java).

    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is new and not in the support library
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
     val channelID = getString(R.string.notification_channel_id)
     val name = getString(R.string.notification_channel_name)
     val descriptionText = getString(R.string.notification_channel_desc)
     val importance = NotificationManager.IMPORTANCE_HIGH
     val channel = NotificationChannel(channelID, name, importance).apply {
          description = descriptionText
      }
      // Register the channel with the system
      val notificationManager: NotificationManager =
           getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
      notificationManager.createNotificationChannel(channel)
    }

Pay attention to the line which sets the importance, as this is what causes notifications sent on this channel to appear as a "Heads Up" notification. (See the docs here)

val importance = NotificationManager.IMPORTANCE_HIGH
  1. Add the following to your AndroidManifest.xml under the <application> tag. This will ensure that any FCM's sent without a notification channel set in their payload will use this one.
<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="@string/notification_channel_id" />
  1. Clean and rebuild

  2. Send a test FCM. It should use your newly created channel by default, and show up as a "Heads Up" notification.

AndroidHeadsUp

  1. (Optional) You can repeat these steps to set up more notification channels for each type of notification you plan on sending. Just make sure each has a unique ID, and that you bundle the channel ID with the notification payload when you send it.

The full docs are here.

nicolasvahidzein commented 4 years ago

Thank you @MichaelM97 I feel like i am very close but i keep getting an error. Also some of the code had to be a bit changed for me as it was throwing a bunch of errors concerning line termination (missing:)

Any idea what i am doing wrong here?

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            CharSequence channelID = getString(R.string.notification_channel_id);
            CharSequence name = getString(R.string.notification_channel_name);
            String descriptionText = getString(R.string.notification_channel_desc);
            int importance = NotificationManager.IMPORTANCE_HIGH;

            NotificationChannel channel = new NotificationChannel(channelID, name, importance);
            channel.setDescription(descriptionText);

            // Register the channel with the system

            //I TRIED ALL OF THESE WITH NO LUCK

            //THIS ONE HAD THE LEAST NUMBER OF ERRORS
            //1 error (missing ;)
            NotificationManager notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager;

            val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;

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

            //from instructions online https://developer.android.com/training/notify-user/channels#java
            NotificationManager notificationManager = getSystemService(NotificationManager.class);

            //added context
            NotificationManager notificationManager = getSystemService(Context.NotificationManager.class);

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

            val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;

            //6 errors
            NotificationManager notificationManager = getSystemService(NOTIFICATION_SERVICE);

            //7 errors
            NotificationManager notificationManager = getSystemService(Context.NOTIFICATION_SERVICE);

            //1 error still  (missing ;)
            // NotificationManager notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;

            // 1 error
            // NotificationManager notificationManager = context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager;

            // 6 errors
            NotificationManager notificationManager = getSystemService(NOTIFICATION_SERVICE);

            //1 error
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            notificationManager.createNotificationChannel(channel);

        }
MichaelM97 commented 4 years ago

@nicolasvahidzein The channel configuration code I posted was for Kotlin, if you are using Java you will need to do the following

// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    CharSequence channelID = getString(R.string.notification_channel_id);
    CharSequence name = getString(R.string.notification_channel_name);
    String description = getString(R.string.notification_channel_desc);
    int importance = NotificationManager.IMPORTANCE_HIGH;
    NotificationChannel channel = new NotificationChannel(channelID, name, importance);
    channel.setDescription(description);
    // Register the channel with the system; you can't change the importance
    // or other notification behaviors after this
    NotificationManager notificationManager = getSystemService(NotificationManager.class);
    notificationManager.createNotificationChannel(channel);
}

If you are still having issues, make sure that you are calling this code from somewhere with access to the Context, e.g. MainActivity.java. Let me know if this helps.

nicolasvahidzein commented 4 years ago

@MichaelM97 Please Michael, i need your help, i can't afford to spend another full week on this retarded problem. I can't figure it out. I'm no longer getting an error but i still get an error. Can i PM you?

nicolasvahidzein commented 4 years ago

I finally got it. God has a sense of humour. I was about to give up if it didn't work on this last try. Thanks you @MichaelM97 i owe you so much.

azheennn commented 4 years ago

Okay, I've got this working. Thanks for the help @Ehesp

IMO the below steps should be added to the README (I've raised #2487 for this), as I presume most people will assume that heads up notifications are configured "out of the box" on Android as they are on iOS

  1. Add the following to your strings.xml. Of course you'll want to customise these for your own app, and be aware that the channel name and channel description are what the user will see in their notification settings.
<string name="notification_channel_id" translatable="false">my_unique_fcm_id</string>
<string name="notification_channel_name">The name of this notification</string>
<string name="notification_channel_desc">A description of the notification.</string>
  1. Register the new notification channel by adding the following code to your app (Java version here). This should be done as early as possible, for example, after calling super.onCreate in MainActivity.kt (or .java).
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
     val channelID = getString(R.string.notification_channel_id)
     val name = getString(R.string.notification_channel_name)
     val descriptionText = getString(R.string.notification_channel_desc)
     val importance = NotificationManager.IMPORTANCE_HIGH
     val channel = NotificationChannel(channelID, name, importance).apply {
          description = descriptionText
      }
      // Register the channel with the system
      val notificationManager: NotificationManager =
           getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
      notificationManager.createNotificationChannel(channel)
}

Pay attention to the line which sets the importance, as this is what causes notifications sent on this channel to appear as a "Heads Up" notification. (See the docs here)

val importance = NotificationManager.IMPORTANCE_HIGH
  1. Add the following to your AndroidManifest.xml under the <application> tag. This will ensure that any FCM's sent without a notification channel set in their payload will use this one.
<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="@string/notification_channel_id" />
  1. Clean and rebuild
  2. Send a test FCM. It should use your newly created channel by default, and show up as a "Heads Up" notification.

AndroidHeadsUp

  1. (Optional) You can repeat these steps to set up more notification channels for each type of notification you plan on sending. Just make sure each has a unique ID, and that you bundle the channel ID with the notification payload when you send it.

The full docs are here.

where can i find the strings.xml file in my flutter project, also what do i give the ID? any srting?

MichaelM97 commented 4 years ago

where can i find the strings.xml file in my flutter project, also what do i give the ID? any srting?

The strings.xml is located in the Android portion of your app, i.e.

{yourFlutterProject}/android/app/src/main/res/values/strings.xml

The default ID can be any string that you want :)

azheennn commented 4 years ago

where can i find the strings.xml file in my flutter project, also what do i give the ID? any srting?

The strings.xml is located in the Android portion of your app, i.e.

{yourFlutterProject}/android/app/src/main/res/values/strings.xml

The default ID can be any string that you want :)

thankyou so much, the MainActivity is giving me errors, i havent imported the strings so it doesnt read get string or the channel ID etc.. how do i import it?

MichaelM97 commented 4 years ago

thankyou so much, the MainActivity is giving me errors, i havent imported the strings so it doesnt read get string or the channel ID etc.. how do i import it?

When in MainActivity, click "Open for Editing in Android Studio". Then use Alt + Enter (or Option + Enter on Mac) to see what imports the IDE suggests

azheennn commented 4 years ago

thankyou so much, the MainActivity is giving me errors, i havent imported the strings so it doesnt read get string or the channel ID etc.. how do i import it?

When in MainActivity, click "Open for Editing in Android Studio". Then use Alt + Enter (or Option + Enter on Mac) to see what imports the IDE suggests

thankyou so much, but my channel id and description and name are still red and not recognized altho i initialized it in strings.xml, what do i do ?

nicolasvahidzein commented 4 years ago

@azheennn contact me directly on skype ill help you. “Nzein19” is my handle

azheennn commented 4 years ago

I solved my problem with the help of @nicolasvahidzein and by following the steps that @MichaelM97 mentioned. I just didnt have the full code for my MainActivity thats why i was having problems. so for everyone whos looking for the missing piece.. here you go:

[package com.tamataonline.tamatafresh;

import android.app.NotificationChannel; import android.app.NotificationManager; import android.os.Build; import android.os.Bundle; import io.flutter.embedding.android.FlutterActivity; import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is new and not in the support library
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        String channelID = getString(R.string.notification_channel_id);
        CharSequence name = getString(R.string.notification_channel_name);
        String descriptionText = getString(R.string.notification_channel_desc);
        int importance = NotificationManager.IMPORTANCE_HIGH;

        NotificationChannel channel = new NotificationChannel(channelID, name, importance);
        channel.setDescription(descriptionText);

        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this
        NotificationManager notificationManager = getSystemService(NotificationManager.class);

        notificationManager.createNotificationChannel(channel);

    }

    //////////////////GeneratedPluginRegistrant.registerWith(this);
    // FlutterFirebaseMessagingService.setPluginRegistrant(this);

}

} ](url)

chinthu commented 4 years ago

i am getting (18, 43): Unresolved reference: R error when running any idea ?

omishah commented 4 years ago

It's been almost a year since this issue was opened and still, it's open !! Sometimes, I hate using Flutter.

nicolasvahidzein commented 4 years ago

@omishah it's not a bug it's just a documentation problem. Read the different comments here and pay close attention. If you can't fix it contact me on skype i'll help you. nzein19 is my skype handle.

nicolasvahidzein commented 4 years ago

i am getting (18, 43): Unresolved reference: R error when running any idea ?

no idea, sorry.

MichaelM97 commented 4 years ago

i am getting (18, 43): Unresolved reference: R error when running any idea ?

Sounds like you’re missing imports, open the android portion of your application in Android Studio and check the recommended imports

omishah commented 4 years ago

@omishah it's not a bug it's just a documentation problem. Read the different comments here and pay close attention. If you can't fix it contact me on skype i'll help you. nzein19 is my skype handle.

Ahh I see. Thanks but I don't need a help at the moment. 🚀☺️

Salakar commented 3 years ago

Hey all 👋

As part of our roadmap (#2582) we've just shipped a complete rework of the firebase_messaging plugin that aims to solve this and many other issues. We've added a ton of documentation as well as an example for a high priority channel in the example app.

If you can, please try out the dev release (see the migration guide for upgrading and for changes) and if you have any feedback then join in the discussion here.

Given the scope of the rework I'm going to go ahead and close this issue in favor of trying out the latest plugin.

Thanks everyone.