invertase / react-native-firebase

🔥 A well-tested feature-rich modular Firebase implementation for React Native. Supports both iOS & Android platforms for all Firebase services.
https://rnfirebase.io
Other
11.53k stars 2.18k forks source link

SetBackgroundHandler not working on ios. #3530

Closed tranty9597 closed 3 years ago

tranty9597 commented 4 years ago

SetBackgroundHandler not working on ios.

I've setup rnfirebase/message v6 for my project, and up to now it's work perfectlty on android. But on IOS SetBackgroundHandler dot not trigger any event.

I've try to debug on xcode at RNFBMessaging+AppDelegate.m and RNFBMessaging+UNUserNotificationCenter.m, and when app in background, didReceiveRemoteNotification delegate dont be fired while my notification still be presented.

Do I have to add content-available to my message payload to make it works?


Project Files

Javascript

Click To Expand

#### `package.json`: ```json # N/A ``` #### `firebase.json` for react-native-firebase v6: ```json # N/A ```

iOS

Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby # N/A ``` #### `AppDelegate.m`: ```objc // N/A ```


Android

Click To Expand

#### Have you converted to AndroidX? - [ ] my application is an AndroidX application? - [ ] I am using `android/gradle.settings` `jetifier=true` for Android compatibility? - [ ] I am using the NPM package `jetifier` for react-native compatibility? #### `android/build.gradle`: ```groovy // N/A ``` #### `android/app/build.gradle`: ```groovy // N/A ``` #### `android/settings.gradle`: ```groovy // N/A ``` #### `MainApplication.java`: ```java // N/A ``` #### `AndroidManifest.xml`: ```xml ```


Environment

Click To Expand

**`react-native info` output:** ``` OUTPUT GOES HERE ``` - **Platform that you're experiencing the issue on**: - [x] iOS - [ ] Android - [ ] **iOS** but have not tested behavior on Android - [ ] **Android** but have not tested behavior on iOS - [ ] Both - **`react-native-firebase` version you're using that has this issue:** - 6.7.1 - **`Firebase` module(s) you're using that has the issue:** - FirebaseMessaging - **Are you using `TypeScript`?** - Y


Ehesp commented 4 years ago

Can you post some code too? Have you followed https://rnfirebase.io/messaging/usage/ios-setup ?

tranty9597 commented 4 years ago

Can you post some code too? Have you followed https://rnfirebase.io/messaging/usage/ios-setup ? Yes, I do follow this. And I've already get notification present but the delegete is not getting called. This is my index.js Screen Shot 2020-04-24 at 15 45 28 And this works well on android. Screen Shot 2020-04-24 at 15 46 33

Ehesp commented 4 years ago

Can you post your App delegate file for iOS

tranty9597 commented 4 years ago

Can you post your App delegate file for iOS Yep, It has nothing. just [Firbase confiure] and default react native configuration

Screen Shot 2020-04-24 at 20 13 31
Ehesp commented 4 years ago

Code please so we can copy bits

tranty9597 commented 4 years ago

Yep, sorry about that

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import "AppDelegate.h"

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
// splashScreen 
#import "RNSplashScreen.h"
#import <Firebase.h>
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  if ([FIRApp defaultApp] == nil) {
    [FIRApp configure];
  }
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:@"dulich"
                                            initialProperties:nil];

  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  [RNSplashScreen show];
  return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

@end
giftset commented 4 years ago

Me, too. Even When the device get the silent push(data only),setBackgroundMessageHandler is not triggered on ios at the version of both of v6.4.0 and v6.7.1

Ehesp commented 4 years ago

What data payloads are you sending over?

giftset commented 4 years ago

I figured it out.

from doc, it says content_available property is placed in apns, but when we put it out of apns, it started to work

data: { to: notificationKey, content_available: true, <-- this is the key to wake up application priority: "high", data: payload.data }

Ehesp commented 4 years ago

Oh interesting, what sdk are you using?

robertqin86 commented 4 years ago

Hey guys, this is unfortunately a serious problem. I have followed everything judiciously but the background handler is just not working on iOS in 6.7.1 for "@react-native-firebase/messaging": "^6.7.1",. I am using notifee and so far, everything woks flawlessly for Android but not on iOS.

I have configured push notifications correctly and was previously on v5 and the notifications worked as expected. With this v6 upgrade, I am using FBRN messaging to receive data messages and notifee to trigger local notifications. Notifee is working as expected but the background handler is not being triggered at all for iOS, so there's nothing I can do with notifee.

I'm using iPhone 8 plus on 13.3.1

GCF Function:

await messaging.sendToDevice(
      [iosToken],
    {
      data: {
        title: 'Title',
        body: 'Body'
      },
    },
    {
      // Required for background/quit data-only messages on iOS
      contentAvailable: true,
      // Required for background/quit data-only messages on Android
      priority: 'high',
    }
  );

// index.js background listener

messaging.setBackgroundMessageHandler(async (remoteMessage) => {
 // this is NEVER CALLED on iOS 
  console.log("Message handled in the background!", remoteMessage);
  await displayNotification(remoteMessage.data);
});

function HeadlessCheck({ isHeadless }) {
  if (isHeadless) {
    // App has been launched in the background by iOS, ignore
    return null;
  }

  return <App />;
}

// Current main application
AppRegistry.registerComponent(appName, () => HeadlessCheck);

App.js

async componentDidMount() {
    try {
      await messaging.registerDeviceForRemoteMessages();

      notifee?.onForegroundEvent(({ type, detail }) => {
        switch (type) {
          case EventType.DISMISSED:
            console.log("User dismissed notification", detail.notification);
            break;
          case EventType.PRESS:
            console.log("User pressed notification", detail.notification);
            break;
        }
      });

      notifee?.onBackgroundEvent(async ({ type, detail }) => {
        const { notification, pressAction } = detail;
        // Check if the user pressed the "Mark as read" action
        if (type === EventType.ACTION_PRESS && pressAction.id === "default") {
          // Remove the notification
          await notifee.cancelNotification(notification.id);
        }
      });

      const authorizationStatus = await messaging.requestPermission();
      if (
        authorizationStatus ===
          messagingStatics.AuthorizationStatus.AUTHORIZED ||
        authorizationStatus === messagingStatics.AuthorizationStatus.PROVISIONAL
      ) {
        const fcmToken = await messaging.getToken();
        store.dispatch(setFCMToken(fcmToken));
        // This is called on both iOS and Android in foreground
        this.unsubscribe = messaging.onMessage(async (remoteMessage) => {
          console.log("FCM Message Data:", remoteMessage);
          await displayNotification(remoteMessage.data);
        });
      }
    } catch (err) {
      // handle request errors
      console.log("token related errors", err);
    }
  }
Ehesp commented 4 years ago

Can check native logs for any messages? And when you say background do you mean no events for any type of message?

robertqin86 commented 4 years ago

Hey @Ehesp ! Thanks for your reply! I was following https://github.com/invertase/react-native-firebase/issues/3367 too and used the console app to find any logs from my iphone device but I did not find any push notification specific logs.

To clarify, when I say background, what I meant was, on iOS, the firebase messaging setBackgroundMessageHandler callback is never called after sending FCM message when the app is in the background. Only when I launch the app in the foreground, the onMessage containing the fcm message is triggered.

On Android, everything works as expected for both callbacks. I have also added priority high and content available true to my payload.

await messaging.sendToDevice(
      [iosToken],
    {
      data: {
        title: 'Title',
        body: 'Body'
      },
    },
    {
      // Required for background/quit data-only messages on iOS
      contentAvailable: true,
      // Required for background/quit data-only messages on Android
      priority: 'high',
    }
  );

This also does not work

const messageIOS = {
    data: {
      title: 'Title',
      body:
        'body',
    },
    android: {
      priority: 'high',
    },
    apns: {
      headers: {
        // 'apns-priority': '5',
        'apns-push-type': 'background',
        'apns-topic': '<my bundle id>'
      },
      payload: {
        aps: {
          'content-available': 1,
          // contentAvailable: true
        },
      },
    },
    token: iosToken,
  };

using messaging().send(messageIOS);

tranty9597 commented 4 years ago

I figured it out.

from doc, it says content_available property is placed in apns, but when we put it out of apns, it started to work

data: { to: notificationKey, content_available: true, <-- this is the key to wake up application priority: "high", data: payload.data }

Yep, as I mentioned on this issue's description, I have to put content_available into message payload to make it work on background and teminated state, and maybe It's a mandatory and importance field that not be in the document.

We use UNUserNotificationCenter for listen event when notification change but I dont see any delegate listen to background event from this framework. (willPresentNotification: foreground notification, willReceiveNotificationResponse: for notification interaction)

RNFirebaseMessage fires background_message_received in AppDelegate.didReceiveRemoteNotification only, and this delegate is not be fired while notificaion has comming and presenting.

robertqin86 commented 4 years ago

Update: I tried the payload recommended by others in this thread. Instead of using the firebase node library, I did a call to FCM (https://fcm.googleapis.com/fcm/send) using postman.

// Headers omitted for brevity...

{ "data": {
    "title": "5x1",
    "body": "15:10"
  },
  "content_available": true,
  "priority": "high",
  "to" : "<device token>"
}

Same scenario observed. Messages are only received when the app is in the foreground and not in the background handler.

VictorKolb commented 4 years ago

It is very strange. Half hour ago notifications is not received notification when app is quit or background. Foreground messaging is always received. Now on IOS all worked well even though I haven't changed the code.

But on android don't work when app is quit :(

"@react-native-firebase/messaging": "^6.7.1" – package version.

Ehesp commented 4 years ago

iOS block messages quite heavily if you've been spamming them - that could be a reason. Unfortunately things are just overall a problem for devs, if you google iOS messaging issues it's a minefield :(

VictorKolb commented 4 years ago

@Ehesp No, I didn't send spam. Only debug messages every 10 minutes to one token... but there is no other explanation.

mikehardy commented 4 years ago

One person's definition of spam doesn't fit anothers. I believe that's too much for iOS even

Ehesp commented 4 years ago

@Ehesp No, I didn't send spam. Only debug messages every 10 minutes to one token... but there is no other explanation.

Sending a content-available message at a rate of once per 10 minutes could well be deemed as spam, since you'd be waking the app up every 10 minutes.

I'm not sure what else to say really - it's a very frustrating issue which is hard to replicate.

VictorKolb commented 4 years ago

But in this moment on android not working only when app is quit. When app foreground or background is worked. Oh guys, complicated situation 😆

Ehesp commented 4 years ago

Android should be much easier to debug and see what's going on. If you open Logcat and send a message, you should get some messages with what is happening behind the scenes.

dcloux commented 4 years ago

We have the same problem (all the tests are done with physical devices). On Android, it works without any problem. On iOS, it worked for about 15 minutes, then nothing on a device. While on a second device it continued to work. The result also depends if the application is closed or in the background or if the iPhone is locked or not. It's as if it doesn't depend on the code itself, but rather of iOS itself.

mikehardy commented 4 years ago

@dcloux For a fun read, go down the internet rabbit hole of searching for something like "inconsistent ios push message delivery" and read everything you can :-). APNS and iOS both are unreliable and lossy, and documented as such according to my read. APNS might throttle you for whatever metrics they decide on, but are documented vaguely as "sending too many messages", and iOS might throttle you for things vaguely documented as "consuming too much energy" and their AI gives you an energy budget based on app interaction etc.

As a developer that wants consistent behavior to understand implementation correctness, it's terrible

robertqin86 commented 4 years ago

Hi @mikehardy I understand APNS might be unreliable, but I was still receiving pushing notifications on my iOS device previously on v5 of the RNFB messaging library. Since the upgrade to v6, I have not been receiving a single silent notification in the setBackgroundHandler on my iPhone device. I think it comes down to the following scenarios:

  1. Firebase Configuration issues (unlikely since I received the notifications on v5 of the RNFB library and I'm also receiving the message when the app is in the foreground in the onMessage handler of v6)
  2. My backend data payload issue. It's possible, but I can't see where I've gone wrong below. I've tried every possible key combinations, including those that are commented out.
    const messageIOS = {
    data: {
      title: 'Title',
      body:
        'body',
    },
    android: {
      priority: 'high',
    },
    apns: {
      headers: {
        // 'apns-priority': '5',
        'apns-push-type': 'background',
        // 'apns-topic': '<my bundle id>'
      },
      payload: {
        aps: {
          'content-available': 1,
          // contentAvailable: true
        },
      },
    },
    token: iosToken,
    };
    messaging().send(messageIOS);
  3. setBackgroundHandler doesn't work properly for iOS on v6. This was previously available on Android only, and was only recently made available for iOS devices with 6.4.0-rc2: See https://github.com/invertase/react-native-firebase/pull/3339. My gut feeling is the setBackgroundHandler isn't implemented properly on the native layer on iOS. I've tried debugging FIRMessagingRemoteNotificationsProxy.m and other relevant files but for some reason, didReceiveRemoteNotification was never called.
#pragma mark - GULApplicationDelegate
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
- (void)application:(GULApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
  [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
}

I'll continue to debug 2 and 3. I don't think its a simple trottle issue on Apple's side. It's probably something relating to silent push notifications restrictions on iOS 13 devices. Because I'm using notifee, based on the documentation, I have to schedule a silent data notification to activate setBackgroundHandler when the device is in the quit or inactive state, then use notifee to trigger a local notification. Its working beautifully on Android, but not on iOS, purely because setBackgroundHandler is never triggered for my iOS device running 13.3.1.

mikehardy commented 4 years ago

Okay @dcloux when you say "same problem" then, it's important to note that you aren't the original poster, so we can't verify your assertion of sameness. Can you verify you are running the latest versions (RNFB 6.7.1 I think?) so you definitely have the benefit of #3339 ?

dcloux commented 4 years ago

@robertqin86 We have the impression that on iOS 13.4.1 it works more or less. On the other hand, on iOS 13.3.1 we have the impression that setBackgroundHandler is not called.

@mikehardy this is our setup:


Project Files

Javascript

Click To Expand

#### `package.json`: [...] ```json "@notifee/react-native": "^0.4.0", "@react-native-firebase/app": "^6.7.1", "@react-native-firebase/messaging": "^6.7.1", "react": "16.11.0", "react-native": "0.62.0", ``` [...] #### `firebase.json` for react-native-firebase v6: ```json # N/A ```

iOS

Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby platform :ios, '10.0' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' def add_flipper_pods! version = '~> 0.33.1' pod 'FlipperKit', version, :configuration => 'Debug' pod 'FlipperKit/FlipperKitLayoutPlugin', version, :configuration => 'Debug' pod 'FlipperKit/SKIOSNetworkPlugin', version, :configuration => 'Debug' pod 'FlipperKit/FlipperKitUserDefaultsPlugin', version, :configuration => 'Debug' pod 'FlipperKit/FlipperKitReactPlugin', version, :configuration => 'Debug' end # Post Install processing for Flipper def flipper_post_install(installer) installer.pods_project.targets.each do |target| if target.name == 'YogaKit' target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '4.1' end end end end target 'myApp' do # Pods for myApp pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" pod 'React', :path => '../node_modules/react-native/' pod 'React-Core', :path => '../node_modules/react-native/' pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons' pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon" pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' target 'myAppTests' do inherit! :complete # Pods for testing end use_native_modules! # Enables Flipper. # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable these next few lines. add_flipper_pods! post_install do |installer| flipper_post_install(installer) end end target 'myApp-tvOS' do # Pods for CoronaScience-tvOS target 'myApp-tvOSTests' do inherit! :search_paths # Pods for testing end end ``` #### `AppDelegate.m`: ```objc #import "AppDelegate.h" #import #import #import #import "RNBootSplash.h" #import "RNQuickActionManager.h" #import #if DEBUG #import #import #import #import #import #import static void InitializeFlipper(UIApplication *application) { FlipperClient *client = [FlipperClient sharedClient]; SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; [client addPlugin:[FlipperKitReactPlugin new]]; [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; [client start]; } #endif @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { #if DEBUG InitializeFlipper(application); #endif RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"CoronaScience" initialProperties:nil]; [RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; if ([FIRApp defaultApp] == nil) { [FIRApp configure]; } rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; return YES; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *) options { return [self.authorizationFlowManagerDelegate resumeExternalUserAgentFlowWithURL:url]; } // @implementation AppDelegate - (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded)) completionHandler { [RNQuickActionManager onQuickActionPress:shortcutItem completionHandler:completionHandler]; } // @end @end ```


Android

Click To Expand

#### Have you converted to AndroidX? - [x] my application is an AndroidX application? - [x] I am using `android/gradle.properties` `android.enableJetifier=true` for Android compatibility? - [ ] I am using the NPM package `jetifier` for react-native compatibility? #### `android/build.gradle`: ```groovy // N/A ``` #### `android/app/build.gradle`: ```groovy // N/A ``` #### `android/settings.gradle`: ```groovy // N/A ``` #### `MainApplication.java`: ```java // N/A ``` #### `AndroidManifest.xml`: ```xml ```


Environment

Click To Expand

**`react-native info` output:** ``` System: OS: macOS 10.15.4 CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz Memory: 6.17 GB / 64.00 GB Shell: 5.7.1 - /bin/zsh Binaries: Node: 13.5.0 - /usr/local/bin/node Yarn: Not Found npm: 6.14.4 - /usr/local/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman Managers: CocoaPods: 1.9.1 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: iOS 13.4, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2 Android SDK: Not Found IDEs: Android Studio: 3.6 AI-192.7142.36.36.6241897 Xcode: 11.4.1/11E503a - /usr/bin/xcodebuild Languages: Python: 2.7.16 - /usr/bin/python npmPackages: @react-native-community/cli: Not Found react: 16.11.0 => 16.11.0 react-native: 0.62.0 => 0.62.0 npmGlobalPackages: *react-native*: Not Found ``` - **Platform that you're experiencing the issue on**: - [x] iOS - [ ] Android - [ ] **iOS** but have not tested behavior on Android - [ ] **Android** but have not tested behavior on iOS - [ ] Both - **`react-native-firebase` version you're using that has this issue:** - `6.7.1` - **`Firebase` module(s) you're using that has the issue:** - `messaging` - **Are you using `TypeScript`?** - `Y` & `3.8.3`

TusharSharma651 commented 4 years ago

Please review below links. It might be helpful. Clearly mentioned: The system treats background notifications as a low priority: you can use them to refresh your app’s content, but the system doesn’t guarantee their delivery. In addition, the system may throttle the delivery of background notifications if the total number becomes excessive. The number of background notifications allowed by the system depends on current conditions, but don’t try to send more than two or three per hour.

https://stackoverflow.com/questions/57871677/ios-13-silent-push-notifications-are-no-longer-reliable https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app

https://github.com/firebase/firebase-ios-sdk/issues/4605

https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns?language=objc

This is how onesignal handled it: https://onesignal.com/blog/ios-13-introduces-4-breaking-changes-to-notifications/

I hope it will help.

Ehesp commented 4 years ago

Just an FYI:

Its working beautifully on Android, but not on iOS, purely because setBackgroundHandler is never triggered for my iOS device running 13.3.1.

Android/RN has built in support for running things in the background via Headless Tasks. Unfortunately this isn't available for iOS so the implementation is custom (launches your app in background mode, hence why we suggest the isHeadless check).

With it not working anymore from v5 -> v6, I'd guess this is heavily down to the SDK upgrades. We have spent many hours painfully testing all scenarios we can, buying multiple devices. iOS messages & notifications is just a terrible experience for developers.

My suggestion would be to put breakpoints absolutely everywhere possible in the code base (e.g. your own AppDelegate, our library & any other libraries which hook onto the delegate events). Background/Quit the application, and then attach it again via XCode. Send your message and check where the debuggers stop and step through them all so see when the flow is lost.

It is unbelievably frustrating for us too, and it's so flakey it makes testing and debugging a nightmare, plus the fact you need to buy at least 4 devices to check it works on various iOS versions and hardware 👎

@TusharSharma651 but don’t try to send more than two or three per hour.

We hit this problem many times whilst testing - all of a sudden everything would just fail with no explanation. Come back a few hours later and it'd be working 🤷

Mavenic commented 4 years ago

Any workaround exists for this, facing exactly the same issue, no notification in the background on IOS.

aecorredor commented 4 years ago

I'm running into the same issue, and one weird thing I noticed is that if I enable the iOS badge, it does trigger it and updates the app badge, but the background handler still does not trigger. I'm migrating from v5, and everything was working fine there.

aecorredor commented 4 years ago

Make sure you are requesting permissions correctly. That was the issue for me. When I migrated from v5 to v6 my hasPermission check broke because now it returns a number (-1, 0, or 1) instead of a boolean to signify the permission status.

tranty9597 commented 4 years ago

Any workaround exists for this, facing exactly the same issue, no notification in the background on IOS.

In my case, notification still be prensented but setBackgroundHandler is not fired, if your nofication is not present and you don't use @notifee, check your setting and implementation.

DanijelBojcic commented 4 years ago

I've got the same problem. Everything works perfectly on Android, on IOS I receive onMessage in foreground, but in background setBackgroundMessageHandler doesn't work unfortunately. I receive the push notifications, but the handler doesn't triggers. On Data-only messages nothing happens.

IOS: 13.4.1 "react-native": "0.60.5", "@react-native-firebase/messaging": "^6.7.1"

tranty9597 commented 4 years ago

I found something concerns to this issue in flutter messaging image

Ehesp commented 4 years ago

@tranty9597 the implementations are totally different, I'm going to hide that to avoid confusion.

ShimTeacher commented 4 years ago

me too .. same problem here..

TusharSharma651 commented 4 years ago

Fixed it by sending content-available and mutable-content both true and sound as 'default'. We are using FCM for sending notifications. FCM Library provides you with an option to set these variables.

HarshRajat commented 4 years ago

For me after trying everything, the fix was not using firebase admin console to test background notification out. As soon as I moved it to nodeJS with additional payload: data: { ..... } ,apns: { payload: { aps : { "content-available": 1, }, }, }

VictorKolb commented 4 years ago

Android should be much easier to debug and see what's going on. If you open Logcat and send a message, you should get some messages with what is happening behind the scenes.

yep, I did it, and this one get:

05-14 14:13:25.685   895   952 D PowerManagerNotifier: onWakeLockAcquired: flags=1, tag="GOOGLE_C2DM", packageName=com.google.android.gms, ownerUid=10029, ownerPid=10978, workSource=WorkSource{10231 ru.litres.stories}
05-14 14:13:25.690   895  1966 V ActivityManager: Broadcast: Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000010 pkg=ru.litres.stories (has extras) } ordered=true userid=0 callerApp=ProcessRecord{7d5e1f9 10978:com.google.android.gms.persistent/u0a29}
05-14 14:13:25.691   895   957 W BroadcastQueue: Reject to launch app ru.litres.stories/10231 for broadcast: App Op 69
05-14 14:13:25.691   895   957 W BroadcastQueue: Reject to launch app ru.litres.stories/10231 for broadcast: App Op 69
05-14 14:13:25.693 10978 10978 W GCM     : broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000000 pkg=ru.litres.stories (has extras) }
05-14 14:14:44.903   895  1511 D PowerManagerNotifier: onWakeLockReleased: flags=1, tag="GOOGLE_C2DM", packageName=com.google.android.gms, ownerUid=10029, ownerPid=10978, workSource=WorkSource{10231 ru.litres.stories}

Fast google-search did`t get a result :(

mikehardy commented 4 years ago

for android probably something like https://dontkillmyapp.com

VictorKolb commented 4 years ago

for android probably something like https://dontkillmyapp.com

Yep. Remove all "power master optimisations" on my phone and now all work like a charm. Thank you!

amorino commented 4 years ago

Still not working on iOS.

BadClyx commented 4 years ago

Still have the issue on iOS, But only when app is in quit state, background state seems to correctly trigger setBackgroundMessageHandler. The FCM message I'm sending is data-only, with contentAvailaible: true.
Any idea on why it could not work on quitted state? Btw i'm using react-native-push-notification to handle notifications. I noticed that react-native-push-notification is also capable to listen for remote notification on iOS. At least, if for some reason the v6 does not work well on iOS (Android is fine) can you guarantee us that if we move back to v5 we won't have this issue any longer ?

mikehardy commented 4 years ago

working on quit but not background is usually an indication that your config is wrong, specifically that something about FCM to APNs or APNs to device isn't working, I think in quit it can still use direct channel to FCM so it teases you into thinking everything is working, while APNs is actually a complete fail. I think in the code you can disable direct channel in order to rely on APNs for everything (which will be the default going forward anyway)

Just a hypothesis, but easy to test at least. This change specifically is what would test the hypothesis, you'd see no FCM at all if you had been quietly relying on direct channel and had an APNs config issue https://github.com/invertase/react-native-firebase/pull/3733/files#diff-4066bdda3c755788f48ed77c5dfd65d2R43

mikehardy commented 4 years ago

Also test on real device, launched from Xcode so you can see the console. The device might just be power-throttling you and refusing to wake your app.

BadClyx commented 4 years ago

working on quit but not background is usually an indication that your config is wrong, specifically that something about FCM to APNs or APNs to device isn't working, I think in quit it can still use direct channel to FCM so it teases you into thinking everything is working, while APNs is actually a complete fail. I think in the code you can disable direct channel in order to rely on APNs for everything (which will be the default going forward anyway)

Just a hypothesis, but easy to test at least. This change specifically is what would test the hypothesis, you'd see no FCM at all if you had been quietly relying on direct channel and had an APNs config issue https://github.com/invertase/react-native-firebase/pull/3733/files#diff-4066bdda3c755788f48ed77c5dfd65d2R43

Hi @mikehardy, First of all, what do you mean by 'working on quit but not background is usually an indication that you config is wrong' ? - What could be wrong ? Then I tried to disable direct channel as you recommended me to test, the result is exactly the same( receiving in foreground/background, receiving on quit state but only native notif - JS does not get triggered) . Btw I directly edit the file RNFBMessaging/RNFBMessaging+FIRMessagingDelegate.m in the Development Pods, then clean build, and build again. Hopefully I tested it correctly I'm not really familiar with xCode.

justcodejs commented 4 years ago

I am using Firebase Admin SDK as the server side app and React Native for the client side app. I also faced the same issue in iOS that setBackgroundMessageHandler is not fired when the message reached the device. I tried both the debug and release mode in the RN client app and to no avail.

After I added content-available in the message payload it work but it behave differently in debug and released mode of the client app.

Debug Mode:

Released Mode:

Below is the message payload I used to send the message via FCM admin SDK.

var message = {
  notification: {
    title: 'Test Notification',
    body: 'Test message'
  },
  data: {
    data1: 'Some data'
  },
  android: {
    notification: {
      sound: 'default',
    }
  },
  apns: {
    payload: {
      aps: {
        sound: 'default',
        "content-available": 1
      }
    },
    headers:{
      "apns-priority":"5"
    }
  },
  topic: topic
};

// Send a message to devices subscribed to the provided topic.
admin.messaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });
forbesgillikin commented 4 years ago

I solved this issue by adding custom headers in the Firebase Admin SDK. The RNFirebase docs say to use

admin.messaging().sendToDevice(
  [], // device fcm tokens...
  {
    data: {
      owner: JSON.stringify(owner),
      user: JSON.stringify(user),
      picture: JSON.stringify(picture),
    },
  },
  {
    // Required for background/quit data-only messages on iOS
    contentAvailable: true,
    // Required for background/quit data-only messages on Android
    priority: 'high',
  },
);

sendToDevice() only allows for a payload and predefined messaging options. It does not allow for the latest APNS headers that need to be sent to the device in order for the device to receive the message in the background. https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns/

I solved this by using the block below, including the correct apns-headers

admin
    .messaging()
    .send({
      data: {
        title: 'title in data',
        body: 'body in data'
      },
      apns: {
        payload: {
          aps: {
            contentAvailable: true
          }
        },
        headers: {
          'apns-push-type': 'background',
          'apns-priority': '5',
          'apns-topic': //your app bundle identfier
        }
      },
      token: //device token
    })

Please update the documentation to support the latest iOS

mikehardy commented 4 years ago

@forbesgillikin that looks fantastic! There is an edit button at the top right of every documentation page, and the GitHub UI makes PRs to docs super easy, docs are maintained almost 100% by the community as the package is entirely too big to be handled otherwise - could you please post a PR :pray: