flutterfire icon indicating copy to clipboard operation
flutterfire copied to clipboard

🐛 [firebase_messaging] Silent Notifications not working on iOS if app is terminated

Open iosephmagno opened this issue 3 years ago • 23 comments
trafficstars

Hello, We already discussed silent notifications on ios in foreground and background mode and I shared our working solution in #8277.

Now above thread is closed, so I’m forced to open this other one.

Situation is:

Android: silent notifications work in all scenarios: app in foreground, background and killed.

ios: silent notifications work in foreground and background mode, but dont work when app is killed IF app is not the last one opened.

iosephmagno avatar Aug 04 '22 19:08 iosephmagno

Hi @russellwheatley maybe you have more of a clue than me on that?

iosephmagno avatar Aug 04 '22 19:08 iosephmagno

I can add more details. After upgrading to 12.0.1 from 11.4.1, silent notifications on iOS work also when app is killed. Unfortunately, notifications stop working as soon as we open a different app. If we open our app back and kill it, notifications start working, and they stop working as soon as a different app is opened.

Setup is: iphone 13 iOS 15.5 Flutter 3.0.3

Video below: App is closed and messages are triggered. We open Rest app while keep sending messages, and notifications stop working.

https://user-images.githubusercontent.com/83366073/182945361-341889ed-ed44-4b4a-8c4f-721629938d86.MOV

iosephmagno avatar Aug 04 '22 20:08 iosephmagno

Hello @darshankawar, any idea about this?

iosephmagno avatar Aug 06 '22 19:08 iosephmagno

Its simply not ok. It seems like silent push is not working at all. They arrives when opening the app

DennisKragekjaer avatar Aug 07 '22 14:08 DennisKragekjaer

@iosephmagno For silent notifications + terminated state combination, according to this documentation section, the data notification in this case will be handled in onBackgroundMessage state, and, the function should be outside the main method to parse it. Also, see this link for your reference and check if it helps.

darshankawar avatar Aug 08 '22 07:08 darshankawar

Hello @darshankawar Yea our code is fine, in fact notifications work in all states: foreground, background and terminate. We noticed that in terminate mode, notifications stop being fired as soon as we open another app after we killed ours, see here https://github.com/firebase/flutterfire/issues/9300#issuecomment-1205724948

Basically, in above video we kill our app and start sending messages to demonstrate that we do receive and show incoming silent notifications when app is terminated. But at some point we open another app (Rest app) and this causes our terminated app not being able to show incoming silent notifications anymore.

This is why we think it might be a bug of firebase_messaging. Can you please try to reproduce the issue on your side?


Here is our setup:

firebase_messaging: 12.0.1 iphone 13 iOS: 15.5 and 15.6 Flutter: 3.0.3

Notification Sample Payload: 
{ admin.messaging().send({ token: "device token", data: { 
"title": "Silent Notification", 
"body": "Hello World!", }, // Set Android priority to "high" android: { priority: "high", }, // Add APNS (Apple) config apns: { payload: { aps: { contentAvailable: true, }, }, headers: { "apns-push-type": "background", "apns-priority": "5", // Must be 5 when contentAvailable is set to true. "apns-topic": "com.******.presence", // bundle identifier }, }, });

ios/runner/AppDelegate.swift

import UIKit import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { if #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } }

ios/runner/Info.plist

<key*>FirebaseAppDelegateProxyEnabled</key*> <string*>NO</string*> <key*>UIBackgroundModes</key*> <array*> <string*>remote-notification</string*> </array*>

iosephmagno avatar Aug 08 '22 08:08 iosephmagno

@darshankawar @russellwheatley we did other tests today. Pretty sure we discovered a pesky bug.

It is pesky because it can go unnoticed during a test. In fact, if you close app and send some silent notifications, they will be shown as expected.

Unfortunately, they stop showing as soon as user opens different apps on the device. We think some conflicts arise and onBackgroundMessage is not longer triggered.

iosephmagno avatar Aug 08 '22 15:08 iosephmagno

I thought it best to also add a Feature Request #9317.

iosephmagno avatar Aug 08 '22 18:08 iosephmagno

Thanks for the update @iosephmagno Based on your comment here: https://github.com/firebase/flutterfire/pull/9292#issuecomment-1207883365, I verified using the changes being made as part of that PR and confirmed that the notifications works in all scenarios, including the one you mentioned, ie, when app is terminated -> notification is sent -> open another app, the notification is received properly. Please see below demo of it:

https://user-images.githubusercontent.com/67046386/183639414-1b985b4e-6187-492d-b0c9-9ab94c815f45.MP4

darshankawar avatar Aug 09 '22 11:08 darshankawar

Hello @darshankawar, what PR are you referring to?

As for your test, I see you are using firebase console to send notifications to your device. This means that maybe you are using “notification” in the payload, not “data-only” silent notifications. Can you double check it?

As mentioned, we have no issues with receiving notifications if we use “notification”. But in that case, we cannot modify payload (eg. decrypt body field) before displaying badge. This is why we asked for the new feature described in #9317.

To recap: silent notifications work in all app states (foreground, background and terminated) and let developers modify the content before displaying head ups. However, due to Apple restrictions, on iOS they might arrive late and are not displayed IF (app is terminated AND app is not the last one opened).

remote notifications work in all app states and always arrive with highest priority. They are the standard for sending sensitive high priority notifications. However, with this type of notification, there is currently no way to modify content before displaying head ups on iOS. To do that, firebase_messaging should support mutable-content and Service App Extension #9317

iosephmagno avatar Aug 09 '22 13:08 iosephmagno

Hello @darshankawar, what PR are you referring to?

I am referring to https://github.com/firebase/flutterfire/pull/9292 in which you also commented asking if example app is affected by your use case.

This means that maybe you are using “notification” in the payload, not “data-only” silent notifications. Can you double check it?

I also tried with data-only message as below:

[token],
    {
      data: {
        foo:'bar',
      },
    },
    {
      // Required for background/terminated app state messages on iOS
      contentAvailable: true,
      // Required for background/terminated app state messages on Android
      priority: 'high',
    }

With which it was received properly. The console log shows below:

flutter: A new onMessage event was published!
flutter: Handling a background message 1660117530686122
flutter: Handling a background message 1660117539038217
flutter: Handling a background message 1660117544211027

After terminating app and then sending data-only message:

flutter: A new onMessage event was published!
Lost connection to device.

Below is the video showing the same. You may not see anything happening in UI (except, the device vibrates after receiving data-only message) but the corresponding events are triggered as shown in console.

https://user-images.githubusercontent.com/67046386/183845984-0f094f88-d4b2-4b80-a5e2-75bd5f9fe97f.MP4

I suggest you to try the updated example app changes pushed yesterday to see silent notifications working properly on iOS.

darshankawar avatar Aug 10 '22 08:08 darshankawar

Thanks for the kind assistance!

Which iOS version are you using? Can you add title and body fields, and try to display headup content? Our payload here: https://github.com/firebase/flutterfire/issues/9300#issuecomment-1207826868

Because I already looked at the PR example and there is no difference with our code. Also, Apple confirmed we must use “notification” with “content-mutable” and a service app extention to bypass above restrictions for “data” notifications: “However, due to Apple restrictions, on iOS they might arrive late and are not displayed IF (app is terminated AND app is not the last one opened).”

They also said that, contrary to android, iOS silent notifications might be put on hold temporarily if traffic is huge, and hence are not to be used for instant messaging or apps which send encrypted data with high priority. In that case the solution on iOS is to use mutable-content and service app notifications. Mutable-content tells that notification must not be displayed untill content is passed to the service app notifications (which usually modify content by performing a body-field decryption). This is in the majority of cases the reason why developers want to modify notification content before head up is displayed.

Sample payload: "aps" : { "mutable-content" : 1, "alert" : { "title" : "Notification with encrypted body!", "body" : "(Encrypted)" }, },

https://developer.apple.com/documentation/usernotifications/modifying_content_in_newly_delivered_notifications

iosephmagno avatar Aug 10 '22 08:08 iosephmagno

For a full coverage of iOS notifications, firebase-mesaging should add support for mutable-content in notification payload and let developers modify notification’s fields before they show head ups through flutter_local_notification, just as we now do with data-only notifications.

iosephmagno avatar Aug 10 '22 08:08 iosephmagno

Which iOS version are you using?

I am on iOS 15.3.1.

Can you add title and body fields, and try to display headup content?

Yes, added as below:

admin
  .messaging()
  .sendToDevice(
    [token],
    {
      data: {
       title: "Silent Notification",
       body: "Hello World",
      },
    },
    {
      // Required for background/terminated app state messages on iOS
      contentAvailable: true,
      // Required for background/terminated app state messages on Android
      priority: 'high',
    }
  )

And then triggered the push event through nodejs which gave me success for each push, with below in console:

flutter: A new onMessage event was published!
flutter: A new onMessage event was published!

The log didn't print because it didn't record when app was terminated.

darshankawar avatar Aug 10 '22 11:08 darshankawar

IOS version is old. Can you use flutter local notifcation to show head up in your video?

Idk what to say, when (app is terminated AND not the last opened one) it doesnt work for us and our code is the same of Russell’s example. Also, it is expected that it doesnt work in such case, because it is Apple restriction. @russellwheatley can you please look into this and shed some light?

iosephmagno avatar Aug 10 '22 12:08 iosephmagno

Keeping it open and labeling for further insights from the team.

/cc @russellwheatley

darshankawar avatar Aug 11 '22 07:08 darshankawar

Hello, we also noticed the same behaviour

  • data only notification are not reliable on ios, 90% of the time it does not trigger background handler when switching app exactly like @iosephmagno mentioned. iOS is also very strict about usage of these silent notifications.
  • as silent notification are not reliable on ios, there should be a way to use "notification" in payload and change its layout. Else what's the point to use a third party local notification package with firebase_messaging on iOS if we get duplicates in background (notif+local)
  • on Android, everything always worked fine

scalz avatar Aug 17 '22 10:08 scalz

@scalz yes Apple confirmed that silent notifications are not meant to be used like on android.

To send high priority notifications, iOS requires “notification” and “mutable-content:1”. Firebase messaging should integrate a service app extention to let us modify content before displaying the head up.

https://github.com/firebase/flutterfire/issues/9300#issuecomment-1210349576

I think they are investigating this already.

iosephmagno avatar Aug 17 '22 11:08 iosephmagno

When will this nonsense end? As far as I understand, there is no solution for this problem for ios, so it is impossible. firebase_messaging is disappointing for me :(

m2sahin avatar Aug 20 '22 15:08 m2sahin

When will this nonsense end?

@m2sahin Please check github's code of conduct.

darshankawar avatar Aug 22 '22 06:08 darshankawar

So, when will this be resolved?

satoyan avatar Aug 29 '22 06:08 satoyan

i have good news it works in the native side there are bug with firebase_messageing package #9563

hatemragab avatar Sep 18 '22 17:09 hatemragab

@hatemragab 👏 Can you share your discovery in #9536 ?

iosephmagno avatar Sep 18 '22 18:09 iosephmagno

Hello everyone, we’ve reviewed the issues opened for iOS background messages and we want to make our position clear.

Android and iOS handle background messaging differently. The decision made by the iOS operating system whether messages reaches the relevant iOS event handler (and subsequently received by the Dart background messaging handler) is based on a number of criteria, such as: CPU usage, priority level (data-only messages are considered “low priority” by iOS, android does not), battery level, amount of messages being received by the app, background/terminated application state, etc. This is a fundamental difference between the platforms, and you need to be aware of them when designing your application.

One solution suggested for iOS data-only messages unreliability has been to add a NotificationExtension. But this will still not create parity with Android as you will still have to include a notification with your message (therefore not data-only). It will still render the original notification if you do not update/mutate the notification that comes through the system in a timely manner. We are not currently considering this as a solution due to these limitations.

We also will not support non-FCM messages from third party packages. We specifically only support messages received from the Firebase APIs since we cannot guarantee that messages received from third party packages will not have any unintended side-effects on other Firebase products such as messaging delivery reporting and Analytics data.

To help us triage and locate genuine issues that need to be addressed we have created a specific issue template for iOS background messages. If you believe you still have an issue that needs to be addressed, please create a new issue following this template.

I will be closing this issue in favor of raising a new issue with the new template above. This template will help you provide us with all the information we need to investigate a potential issue with background messaging on iOS.

russellwheatley avatar Sep 27 '22 10:09 russellwheatley