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.61k stars 3.95k forks source link

πŸ› [firebase_messaging] Background handler never invoked on iOS #6290

Closed mikeroneer closed 2 years ago

mikeroneer commented 3 years ago

Bug report

Describe the bug According to https://firebase.flutter.dev/docs/messaging/usage/#message-types, the background handler should be invoked for notification messages, data messages or a combination of both when the app is in the background or terminated. In our project, it is not invoked in any of those cases. For the sake of completeness it is worth to mention that the onMessage stream fires properly when the app is in foreground and also the notification handled by the FCM-SDK is shown when the app is in background/terminated. It's just the onBackgroundMessage which is never invoked.

We are aware of the content_available flag, however, the issue does not just relate to silent (data only) messages.

Steps to reproduce

Steps to reproduce the behavior:

  1. run the simplified code snipped below
  2. (optional) add a breakpoint in the background handler
  3. put the app into background/terminate it
  4. send a notification/data message via FCM (Firebase console or API call)
  5. result: "Handling a background message..." is not printed in the console, nor does the debugger stop in the _firebaseMessagingBackgroundHandler

Expected behavior

onBackgroundMessage is invoked when the app is in background or terminated.

Sample project

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  print('Handling a background message: ${message.messageId}');
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  final token = await FirebaseMessaging.instance.getToken();
  print('Push notification token: $token');

  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    print('Got a message whilst in the foreground!');
    print('Message data: ${message.data}');

    if (message.notification != null) {
      print('Message also contained a notification: ${message.notification}');
    }
  });
}

Edit: Payload (suggested by @markusaksli-nc)

We have tried quite a lot of different payload combinations, with both, containing a data object only and a notification object respectively. We have also tried addressing the recipient via a topic (which is our intended use case) as well as with the unique device token. Background modes (Background fetch and Remote Notifications) are enabled too. On the server side, we are using the Java SDK, however, we have also tried sending a POST request directly via Google's OAuth 2.0 Playground.

The following indicates a sample payload:

{
   "topic": "test-topic",
   "message": {
      "data": {
         "data-item": "my-data-item"
      },
      "apns": {
         "payload": {
            "aps": {
               "content-available": 1
            },
         }
      },
   },
}

Additional context

Flutter doctor

Run flutter doctor and paste the output below:

Click To Expand ``` Doctor summary (to see all details, run flutter doctor -v): [βœ“] Flutter (Channel stable, 2.0.3, on macOS 11.3 20E232 darwin-x64, locale en-AT) [βœ“] Android toolchain - develop for Android devices (Android SDK version 30.0.3) [βœ“] Xcode - develop for iOS and macOS [βœ“] Chrome - develop for the web [βœ“] Android Studio (version 4.1) [βœ“] IntelliJ IDEA Ultimate Edition (version 2020.3.1) [βœ“] VS Code (version 1.56.2) [βœ“] Connected device (3 available) ```

Flutter dependencies

Run flutter pub deps -- --style=compact and paste the output below:

Click To Expand ``` Dart SDK 2.12.2 Flutter SDK 2.0.3 dependencies: - firebase_analytics 8.1.0 [firebase_analytics_platform_interface firebase_analytics_web firebase_core flutter meta] - firebase_core 1.2.0 [firebase_core_platform_interface firebase_core_web flutter meta] - firebase_crashlytics 2.0.4 [firebase_core firebase_core_platform_interface firebase_crashlytics_platform_interface flutter stack_trace] - firebase_messaging 10.0.0 [firebase_core firebase_core_platform_interface firebase_messaging_platform_interface firebase_messaging_web flutter meta] ... transitive dependencies: - firebase 9.0.1 [http http_parser js] - firebase_analytics_platform_interface 2.0.1 [flutter meta] - firebase_analytics_web 0.3.0+1 [firebase firebase_analytics_platform_interface flutter flutter_web_plugins meta] - firebase_core_platform_interface 4.0.1 [collection flutter meta plugin_platform_interface] - firebase_core_web 1.1.0 [firebase_core_platform_interface flutter flutter_web_plugins js meta] - firebase_crashlytics_platform_interface 3.0.4 [collection firebase_core flutter meta plugin_platform_interface] - firebase_messaging_platform_interface 3.0.0 [firebase_core flutter meta plugin_platform_interface] - firebase_messaging_web 2.0.0 [firebase_core firebase_core_web firebase_messaging_platform_interface flutter flutter_web_plugins js meta] ... ```

elsystm commented 2 years ago

@HaveANiceDay33 We have ditched the idea of handling notifications on iOS silently and we made a native notification extension on iOS to handle rich notifications with mutable-content tag, everything is going smooth so far with notification localization and click handling on Flutter side.

Sadly this is the only way so far to be able to receive notifications reliably on iOS.

I know maintaining two code bases for the same scenario for different platforms is not the ideal solution especially if you have chosen Flutter in the first place, but I encourage everyone facing the same problem not to waste their time trying to fix it if they're tight on the delivery schedule.

Andreylk4774 commented 2 years ago

@elsystm

@HaveANiceDay33 We have ditched the idea of handling notifications on iOS silently and we made a native notification extension on iOS to handle rich notifications with mutable-content tag, everything is going smooth so far with notification localization and click handling on Flutter side.

Sadly this is the only way so far to be able to receive notifications reliably on iOS.

I know maintaining two code bases for the same scenario for different platforms is not the ideal solution especially if you have chosen Flutter in the first place, but I encourage everyone facing the same problem not to waste their time trying to fix it if they're tight on the delivery schedule.

Can you show the extension code? Now you can always run flutter code after receiving a FCM notification, even when the app is killed by the user?

sandeepv10494 commented 2 years ago

Can anyone please suggest to me any workaround solution specific to ios for this issue?

sp-sivaprasad commented 2 years ago

FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { Fluttertoast.showToast( msg: " from onMessageOpenedApp : " + message.data['screen'], ); }).onData((data) { print('NOTIFICATION MESSAGE TAPPED'); print('data from stream: ${data.data}'); Fluttertoast.showToast( msg: " from onMessageOpenedApp : data from stream: ${data.data}", ); });

FirebaseMessaging.instance.getInitialMessage().then((value) {
  Fluttertoast.showToast(
    msg: " from getInitialMessage : $value ",
  );
});

background handler doesn't executed for me else, but these codes does. Anyone can try these methods to get codes executed when app is terminated and / or background

waqadArshad commented 2 years ago

@HaveANiceDay33 We have ditched the idea of handling notifications on iOS silently and we made a native notification extension on iOS to handle rich notifications with mutable-content tag, everything is going smooth so far with notification localization and click handling on Flutter side.

Sadly this is the only way so far to be able to receive notifications reliably on iOS.

I know maintaining two code bases for the same scenario for different platforms is not the ideal solution especially if you have chosen Flutter in the first place, but I encourage everyone facing the same problem not to waste their time trying to fix it if they're tight on the delivery schedule.

@elsystm can you please help me with that native implementation? Can you at least share some code samples or some resources to help us with that?

Thanks by the way!

google-oss-bot commented 2 years ago

Hey @mikeroneer. We need more information to resolve this issue but there hasn't been an update in 7 weekdays. I'm marking the issue as stale and if there are no new updates in the next 7 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

benfgit commented 2 years ago

Issue continues on iOS 15.5. and firebase_messaging: 11.4.4. Works well on Android.

hatemragab commented 2 years ago

any updates about it?

Pelmeshka102 commented 2 years ago

FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { Fluttertoast.showToast( msg: " from onMessageOpenedApp : " + message.data['screen'], ); }).onData((data) { print('NOTIFICATION MESSAGE TAPPED'); print('data from stream: ${data.data}'); Fluttertoast.showToast( msg: " from onMessageOpenedApp : data from stream: ${data.data}", ); });

FirebaseMessaging.instance.getInitialMessage().then((value) {
  Fluttertoast.showToast(
    msg: " from getInitialMessage : $value ",
  );
});

background handler doesn't executed for me else, but these codes does. Anyone can try these methods to get codes executed when app is terminated and / or background

This answer helps me. Just use getInitialMessage

russellwheatley commented 2 years ago

Just to be clear on this issue; I have tested background message handling on iOS multiple times, and it hasn't failed to work. I've created a PR for updating the messaging example app with a set of instructions for you to follow. I would be grateful if you are experiencing an issue, if you could test the example app by following the instructions, and let me know if you're able to receive messages in your background handler.

I will ultimately be closing this issue as it doesn't serve any purpose except to confuse users about the state of onBackgroundMessage for iOS.

kmvignesh commented 2 years ago

Me also faced the same issue. To fix this did the following changes. Step 1 In info.plist file we have added following configuration

<key>GoogleUtilitiesAppDelegateProxyEnabled</key>
<false/>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>

Step 2 Extra keys in the payload also causing issue. so removed unnecessary keys from payload. eg: apns-push-type,apns-topic

var message = new MulticastMessage()
{
    Tokens = deviceTokens.ToList(),
    Data = new Dictionary<string, string>()
{
    {"entity_name", notificationEntityName}
},

    Apns = new ApnsConfig
    {
        Aps = new Aps { ContentAvailable = true },
        Headers = new Dictionary<string, string>
        {
            { "apns-priority", "5" }
        }
    }
};

Now able to receive data only notification and onBackgroundMessage is getting called.

DennisKragekjaer commented 2 years ago

+1

rulefahd commented 2 years ago

It doesnt work on termination mode all the time, it might work for 1-2 hours, then it will stop completely

waqadArshad commented 2 years ago

@rulefahd if you are talking about iOS, I agree that data-only messages would stop getting received. but for the android part, you have to follow a specific payload structure to be able to keep receiving the notifications in the terminated state even.

Here is an example that is working for me on android. I have tested it myself.

 let payload;
 var options;

payload = {
      notification: {},
     // the data in the data field is my custom data and you can put whatever you want, here.
      data: { 
        imageUrl: requesterImageUrl,
        chatRoomId: chatRoomId,
        screenName: "voiceScreen",
        voiceCall: "voiceCall",
        callerName: requesterName,
        callsDocId: callsDocId,
        senderId: requesterId,
        receiverId: requestedId,
        callInitTime: callInitTime,
      },
    };

    options = {
      priority: "high",
      contentAvailable: true,
    };
    await admin
      .messaging()
      .sendToDevice(token_o, payload, options)
      .then((value) => {
        functions.logger.log(
          "Notification for AudioCall is sent to the Receiver"
        );
      })
      .catch((e) => {
        functions.logger.log(e.toString());
      });
waqadArshad commented 2 years ago

@rulefahd as for iOS, there is no easy way of doing this. The bottom line is that you cannot achieve an always working terminated state notification using FCM. You would have to use a native Swift or Objective-C implementation to be able to do that. I implemented that using PushKit as I was doing this for call implementation. if you need anything else, please feel free to ask.

arthas1888 commented 2 years ago

At last it works with the last release, I tested successfully with next json body

               {
                  "priority": "high",
                  "data": {
                      "key": "value"
                  },                     
                  "content_available": true,
                  "apns": {
                      "headers": {
                          "apns-priority": "5"
                      }
                  },
                  "to": "firebase_token_xxxxx"
              }
m2sahin commented 2 years ago

{ "priority": "high", "data": { "key": "value" },
"content_available": true, "apns": { "headers": { "apns-priority": "5" } }, "to": "firebase_token_xxxxx" }

It works when you throw it down, yes, but when the application is completely closed, the notification does not come at all.

hatemragab commented 2 years ago

I see PR #9292 fix the problem is it available in pub dev or not yet?

m2sahin commented 2 years ago

I see PR #9292 fix the problem is it available in pub dev or not yet?

firebase_messaging 12.0.2 is the latest version but now I'm getting the same error. I hope the problem is fixed soon, it's very annoying.

hatemragab commented 2 years ago

I see PR #9292 fix the problem is it available in pub dev or not yet?

firebase_messaging 12.0.2 is the latest version but now I'm getting the same error. I hope the problem is fixed soon, it's very annoying.

Yes i don't this bug fixed in change log Can any one send how to import the package from the GitHub master branch?

darshankawar commented 2 years ago

Yes i don't this bug fixed in change log Can any one send how to import the package from the GitHub master branch?

@hatemragab the PR is just an update to the example app to show the background handlers work as intended. There’s nothing to release. The example app is updated so users can see that the API works and if there is a problem, it is something wrong with their setup.

If you look at the PR, all the files updated are in the example/ directory and also a documentation update.

sameer320 commented 2 years ago

I also facing this issue.