40

I am getting the notification when the app is in the foreground but not when the app in the background. Also, I have google-ed/StackOverflow-ed for like 2 hours or more but able to resolves this.

My Configurations are :

  firebase_auth: ^0.10.0
  firebase_messaging: ^5.0.0

The manifest is like this:

Manifest

The code is like this:

final notifications = new FirebaseMessaging();

class AppNotifications {
  static String fcmToken = '';

  static Future<Null> init() async {
    appLogs("AppNotifications init");

    notifications.requestNotificationPermissions(const IosNotificationSettings(sound: true, badge: true, alert: true));

    await configure();

    fcmToken = await notifications.getToken();
    appLogs("FCM TOKEN : " + fcmToken);

    notifications.onTokenRefresh.listen((newToken) {
      fcmToken = newToken;
      appLogs("FCM TOKEN onTokenRefresh: " + fcmToken);
    });

    await updateFCMToken();
  }

  static Future<Null> configure() async {
    appLogs("AppNotifications Configure");

    notifications.configure(onMessage: (msg) {
      appLogs('FCM onMessage: ' + msg.toString());
    }, onLaunch: (lun) {
      appLogs('FCM onLaunch: ' + lun.toString());
    }, onResume: (res) {
      appLogs('FCM onResume: ' + res.toString());
    });
  }

  static Future<Null> updateFCMToken() async {
    auth.currentUser.fcmToken = fcmToken;
    await updateUserInSharedPreference();
  }
}

I am calling the function like this:

class HomeScreenState extends State<HomeScreen> {


  @override
  void initState() {
    super.initState();

    Future.delayed(Duration(milliseconds: 100), () async {
      await AppNotifications.init();
    });
  }

..... ....

I am using postman for sending the notification :

Postman

My logs :

**(App is Foreground)**  I/flutter (31888): APPLOGS : FCM onMessage: {notification: {title: Test notification title, body: Test notification body}, data: {status: done, id: 1, foo: bar, click_action: FLUTTER_NOTIFICATION_CLICK}}
  **(App is Background)**  W/FirebaseMessaging(31888): Missing Default Notification Channel metadata in AndroidManifest. Default value will be used.

Flutter doctor :

[✓] Flutter (Channel stable, v1.2.1, on Mac OS X 10.14.4 18E226, locale en-GB)
    • Flutter version 1.2.1 at /Users/Ajay/SDK/flutter
    • Framework revision 8661d8aecd (3 months ago), 2019-02-14 19:19:53 -0800
    • Engine revision 3757390fa4
    • Dart version 2.1.2 (build 2.1.2-dev.0.0 0a7dcf17eb)

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

[✓] iOS toolchain - develop for iOS devices (Xcode 10.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 10.2.1, Build version 10E1001
    • ios-deploy 1.9.4
    • CocoaPods version 1.6.0

[✓] Android Studio (version 3.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 34.0.1
    • Dart plugin version 182.5215
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)

[!] VS Code (version 1.33.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    ✗ Flutter extension not installed; install from
      https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (1 available)
    • ONEPLUS A5000 • b47e8396 • android-arm64 • Android 9 (API 28)
6
  • I'm struggling with notifications support on Android too. Except that I don't get notifications while the app is in foreground. But even with 'background-arrived' notifications, data payload is lost on app launch. iOS works perfectly fine though.
    – Egor
    Commented May 12, 2019 at 8:16
  • I finally solved my Firebase Messaging issues by initializing Firebase inside of runApp(MyApp()). Since you already seem to do that, the only difference between your code flow & mine is that you use version 5.0.0. Did you try downgrading? E.g. I use 4.0.0+4.
    – Egor
    Commented May 14, 2019 at 9:54
  • 1
    @George Is click_action param is must when push notification is received from API.onLaunch & onResume is not called.
    – Shangari C
    Commented Jul 31, 2019 at 8:24
  • @AjayKumar Did you resolved the issue?
    – Shangari C
    Commented Jul 31, 2019 at 8:27
  • 2
    @ShangariC click_action is recommended if you target Android devices. Otherwise onLaunch / onResume won't be called when user clicks on a notification in the tray. For more info check out Sending Messages in the docs.
    – Egor
    Commented Jul 31, 2019 at 8:37

10 Answers 10

66

lost my 2 days to fix this issue, it may helpful for you. notification tag only for showing notification. you can access only data content on onResume/onLaunch.

If you want handle notification message inside onResume/onLaunch add those messages in data tag also, Then you can do what ever you want.

refer more detail on this link

send this notification message

{
       "notification": {
          "body": "body",
          "title": "title"
       },
       "priority": "high",
       "data": {
        "body": "body",
          "title": "title"
          "click_action": "FLUTTER_NOTIFICATION_CLICK",
          "id": "1",
          "status": "done",
          "image": "https://ibin.co/2t1lLdpfS06F.png",
       },
       "to": <your token>
    }

you will receive below information onResume or onLaunch, your notification tag will be empty here

{notification: {}, data: {image: https://ibin.co/2t1lLdpfS06F.png, google.original_priority: high, google.sent_time: 1560858283888, google.delivered_priority: high, body: body , title: title, click_action: FLUTTER_NOTIFICATION_CLICK, google.message_id: 0:1560858283908500%eefdc741eefdc741, collapse_key: <package>, google.ttl: 2419200, from: <from>, id: 1, status: done}}

you can use title and body which is added in data tag.

12
  • 22
    This is the right answer! The click_action key needs to be inside the data object. Firebase is spectacularly undocumented. Commented Jul 24, 2019 at 12:04
  • it is working when click_action is n notification not data?
    – Aya Elsisy
    Commented Nov 24, 2019 at 0:29
  • totally agreed with Anand Saga ,
    – M David
    Commented Feb 25, 2020 at 19:22
  • 1
    In some tutorials they mention "clickAction" that poses this problem
    – Kourosh
    Commented Mar 27, 2020 at 5:48
  • 1
    @MDavid can you please tell me which route I put code of firebase init? I have add this but still not wroking. notifications are showing in background but onResume is not working..
    – Naeem
    Commented May 8, 2020 at 15:20
31

In my case, onResume and onLoad were not firing because I was missing click_action: 'FLUTTER_NOTIFICATION_CLICK' under the notification property, not the data property.

Once I changed my payload to be in the following format, onResume and onLoad started firing for me.

{
    notification: {
        title: 'Title',
        body: 'Body',
        click_action: 'FLUTTER_NOTIFICATION_CLICK'
    }
}

I found this documented here.

If you are setting this in TypeScript (possibly others), it will be necessary to set this via the message's android.notification.clickAction property. Otherwise, you may receive errors about the property being invalid. An example of this with a MulticastMessage is as follows. Note that it doesn't show message construction from start to finish; only enough to show the context for setting clickAction.

// Initialize the notification
const notification: admin.messaging.Notification = {
    title: 'Hello',
    // Though the "clickAction" property is available here, it throws an error about
    // having an invalid property when actually trying to send the notification.
    // Instead, the "clickAction" property is set further downstream under the
    // MulticastMessage.android.notification object.
    // clickAction: 'FLUTTER_NOTIFICATION_CLICK'
};

// Do other things to build your notification

const message: admin.messaging.MulticastMessage = {
    tokens: [],
    notification: notification
};

// Do other things to build your message

// If a notification is being sent then set the click_action
if (message.notification) {
    // Combine with the existing message.android object, if one exists
    message.android = message.android || {};
    message.android.notification = Object.assign(message.android.notification || {}, {
        clickAction: 'FLUTTER_NOTIFICATION_CLICK'
    });
}
4
  • 1
    its launching my activity if place inside data tag. but onResume and onLoad not working.
    – Anand saga
    Commented Jun 18, 2019 at 11:19
  • 1
    I am getting this error if I add it in the notification payload: Invalid JSON payload received. Unknown name "click_action" at \'message.notification\': Cannot find field. Commented Jul 2, 2020 at 19:27
  • I updated my answer to show an example of how we're setting it in code.
    – cokeman19
    Commented Jul 5, 2020 at 3:40
  • this has to be placed in the android.notification object, not the regular notification object!!!!!!!!!!!!!
    – giorgio79
    Commented Mar 12, 2023 at 5:45
4

On the documentation of the firebase_messaging package in this section link to plugin docs they say you need to include click_action: FLUTTER_NOTIFICATION_CLICK as a "Custom data" key-value-pair in your server-side post request for your onResume and Onlaunch methods to be called.

For example here am using the php firebase admin sdk to send notifications to the FCM here is a code sample for sending a notification:

        $factory = (new Factory)->withServiceAccount('path to firebase keys json file');
                $messaging = $factory->createMessaging();

                $deviceToken = $user->deviceToken;
    $message = CloudMessage::withTarget('token', $deviceToken)
                        ->withNotification(Messaging\Notification::create('title', 'body'))
                        ->withData(['custom-data-key1' => 'custom-data-value1', 'custom-data-key2' => 'custom-data-value2', 'click_action'=>'FLUTTER_NOTIFICATION_CLICK']);
$messaging->send($message);
2

Your are probably missing some metadata in AndroidManifest (as your log tells you). You need to add the following to your manifest:

<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="@string/default_notification_channel_id"/>

It seems like a duplicate

0
2

The answer posted by Anand saga is correct

You need to add title and body in data section.Notification payload will be blank onResume and onLaunch although it was sent from backend nodejs API.

Below is the sample payload flutter is resolving to onResume:

on resume {notification: {}, data: {image: https://ibin.co/2t1lLdpfS06F.png, google.original_priority: normal, google.sent_time: 1577389234347, google.delivered_priority: normal, body: "Custom Body", type: OrderDetail, title: "Custom title", click_action: FLUTTER_NOTIFICATION_CLICK, google.message_id: 0:1577389234352165%dfef845edfef845e, collapse_key: <<App NAme>>, google.ttl: 2419200, from: 790713779055, id: "5e050c04c308f6abb5a60b2e"}}

Typical dart config will look like this.

firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print('on message ${json.encode(message['data']['title'])}');
        redirectScreenOnLoad(message);
      },

      onResume: (Map<String, dynamic> message) async {
        firebaseMessaging.onTokenRefresh;
        print('on resume $message');
        redirectScreenOnLoad(message);

      },

      onLaunch: (Map<String, dynamic> message) async {
        firebaseMessaging.onTokenRefresh;
//        await API.updateUserApiToGetFCMKey();
        print('on launch $message');
        redirectScreenOnLoad(message);
      },
    );

in redirectScreenOnLoad(String message) i am checking the input payload and redirecting to different screen

6
  • 1
    this is over Android, but in iOS [data] does not exist in the json, did you fix this also for iOS i have been with this for the last week works in onResume but fails on onLaunch Commented Jan 6, 2020 at 15:47
  • I didn't test this in iOS. Can you post the response you are getting in iOS from firebase messaging?
    – downlz
    Commented Jan 7, 2020 at 12:19
  • just make it work i needs to be call from initiState to work Commented Jan 7, 2020 at 18:40
  • Where is redirectScreenOnLoad() function? Commented May 21, 2020 at 5:08
  • it was a matter of configurations you need to do the steps in documentation completely and it gonna work Commented Jun 24, 2020 at 16:48
2

Another thing to add for the troubleshooting with FCM is within your onMessage handling.

First, in onMessage, print the output to see if your device is receiving the message. Notifications can fail beyond this point and not show, so it's good to know if it's getting it at all. If it is, then you know you have configured FCM correctly and that your problem lies within your UI handling.

Next, inspect the onMessage print statement and ensure your handling of that data after is correct. I noticed that the Android data was in a different structure pattern than the iOS type -- so this can lead you to parsing the data incorrectly, which may not show the notification and will not throw an error either.

Here's an example of what I mean:

    _fcm.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
        String sender;
        String parsedMessage;

        if (Platform.isAndroid) {
          sender = message['notification']['title'];
          parsedMessage = message['notification']['body'];
        }
        if (Platform.isIOS) {
          sender = message['aps']['alert']['title'];
          parsedMessage = message['aps']['alert']['body'];
        }
      },
    );

You can see that I parse the same data differently depending on the platform. Without doing this, the notification never appeared and no failure was ever indicated.

Again, this is just something to try before you tear apart your .ts/.js cloud functions.

1

Complete guide to handle firebase messaging:

handleMessaging() {
  _firebaseMessaging.configure(
    onMessage: (Map<String, dynamic> message) async {
      // showNotification(
      //     message['notification']['title'], message['notification']['body']);
      print("onMessage: $message");

      print('Data is: '+ message['data']['screen'].toString());

    },
    onLaunch: (Map<String, dynamic> msg) {
      print("Called onLaunch");
      print(msg);
      print('Data is: '+ msg['data']['screen'].toString());

      if(msg['data']['screen'].toString() == 'Chat Screen') {
        return //Navigate to chatApp();
      }
      return null;
    },
    onResume: (Map<String, dynamic> msg) {
      //(App in background)
      // From Notification bar when user click notification we get this event.
      // on this event navigate to a particular page.
      print(msg);

      // // Assuming you will create classes to handle JSON data. :)
      // Notification ns = Notification(title: msg['title'], body: msg['body']);
      //        
      return null;
    },
    // onMessage: (Map<String, dynamic> msg) {
    // // (App in foreground)
    // // on this event add new message in notification collection and hightlight the count on bell icon.
    // // Add notificaion add in local storage and show in a list.
  );
}
0

if your android app is in kotlin you should add this as your application activity

import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService

class Application : FlutterApplication(), PluginRegistrantCallback {

    override fun onCreate() {
        super.onCreate()
        FlutterFirebaseMessagingService.setPluginRegistrant(this);
    }

    override fun registerWith(registry: PluginRegistry?) {
        io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin.registerWith(registry?.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
    }
}

and don't forget to add it your Manifist android:name=".Application"

0
onLaunch: (Map<String, dynamic> msg) {
    print("Called onLaunch");
    print(msg);
    if(msg['data']['screen'].toString() == 'chat') {
        //Navigate to chat screen
    }
    return null;
},
0

Important note that the new version of FirebaseMessaging is a big change so all of the above will not work if you discover this thread.

Configure is gone, as with other Flutter 2 updates things are through .listen methods. There is a thread on this: How to configure Firebase Messaging with latest version in Flutter?

Not the answer you're looking for? Browse other questions tagged or ask your own question.