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.71k stars 2.22k forks source link

[🐛] 🔥 iOS background notification - iPhone vibration but no background handler execution #5421

Closed maximerenaud7 closed 3 years ago

maximerenaud7 commented 3 years ago

Issue

Hello 👋

I have issues receiving background silent push notification (push notification with data-only) on iOS.

To test it, I added console logs in all handlers and in setBackgroundMessageHandler, when I send the payload to firebase (using a ruby-on-rails backend), the iPhone vibrate but the handler is not executed.

The payload

{
  message: {
    android: {
      priority: 'high',
    },
    apns: {
      payload: {
        aps: {
          sound: 'default',
          'content-available': 1,
        },
      },
    },
    token: notification[:token],
    data: {
      topic: notification[:topic],
      body: notification[:message],
      redirect_to: notification[:redirect_to],
    },
  },
}

I want to use Notifee to show notifications (using only silent notifications and no longer rely on the default behavior of firebase)

Everything is working well on Android (quit, background & foreground notifications received and handlers executed) On iOS, I can receive foreground notifications (the messaging().onMessage is executed) but forced-quit & background are not received (just get a vibration and handler is not executed).


Project Files

Javascript

Click To Expand

#### `package.json`: ```json "@react-native-firebase/app": "^12.0.0", "@react-native-firebase/crashlytics": "^12.0.0", "@react-native-firebase/messaging": "^12.0.0", ``` #### `index.js` ```js import React from 'react' import { AppRegistry } from 'react-native' import notifee from '@notifee/react-native' import messaging from '@react-native-firebase/messaging' import { onMessageReceived, onNotificationEvent } from './notifications' import App from './App' import { name as appName } from './app.json' messaging().setBackgroundMessageHandler(async (message) => { console.log('messaging().setBackgroundMessageHandler', { message }) onMessageReceived(message) }) notifee.onBackgroundEvent(async (event) => { console.log('notifee.onBackgroundEvent', { event }) onNotificationEvent(event) }) const HeadlessCheck = ({ isHeadless }) => { console.log('HeadlessCheck', { isHeadless }) if (isHeadless) { // App has been launched in the background by iOS, ignore return null } return } AppRegistry.registerComponent(appName, () => HeadlessCheck) ``` #### App.js ```js messaging().onMessage((message) => { console.log('messaging().onMessage', { message }) }) notifee.onForegroundEvent((event) => { console.log('notifee.onForegroundEvent', { event }) }) notifee.getInitialNotification().then((initialNotificationEvent) => { console.log('notifee.getInitialNotification()', { initialNotificationEvent }) }) messaging().onNotificationOpenedApp((message) => { console.log('messaging().onNotificationOpenedApp', { message }) }) ```

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 /** * 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 "RNFBMessagingModule.h" #import "AppDelegate.h" #import #import #import #import #import #ifdef FB_SONARKIT_ENABLED #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 FB_SONARKIT_ENABLED && !__LP64__ InitializeFlipper(application); #endif [FIRApp configure]; [UNUserNotificationCenter currentNotificationCenter].delegate = self; NSString *userAgent = [NSString stringWithFormat:@"react-native/ios/%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]]; [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:userAgent, @"UserAgent", nil]]; RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; NSDictionary *appProperties = [RNFBMessagingModule addCustomPropsToUserProps:nil withLaunchOptions:launchOptions]; // In dev mode (RCT_DEV), React Native throws an internal warning because it loads the following module in an unsafe way. Here we preload it to prevent the warning RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"DoctolibDoctor" initialProperties:appProperties]; rootView.backgroundColor = [[UIColor alloc] initWithRed:6/255.0f green:150/255.0f blue:222/250.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]; [UIDevice currentDevice].batteryMonitoringEnabled = true; 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 *)application openURL:(NSURL *)url options:(NSDictionary *)options { return [RCTLinkingManager application:application openURL:url options:options]; } - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray> * _Nullable))restorationHandler { return [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler]; } @end ```


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:** ``` System: OS: macOS 11.4 CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz Memory: 26.36 MB / 16.00 GB Shell: 5.8 - /bin/zsh Binaries: Node: 14.16.1 - ~/.nvm/versions/node/v14.16.1/bin/node Yarn: 1.22.10 - ~/Sites///node_modules/.bin/yarn npm: 7.13.0 - ~/.nvm/versions/node/v14.16.1/bin/npm Watchman: Not Found Managers: CocoaPods: 1.10.1 - /Users//.rbenv/shims/pod SDKs: iOS SDK: Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4 Android SDK: Not Found IDEs: Android Studio: Not Found Xcode: 12.5/12E262 - /usr/bin/xcodebuild Languages: Java: 15.0.1 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 17.0.1 => 17.0.1 react-native: 0.64.0 => 0.64.0 react-native-macos: Not Found 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:** - `12.0.0` - **`Firebase` module(s) you're using that has the issue:** - `e.g. Instance ID` - **Are you using `TypeScript`?** - `N`


mikehardy commented 3 years ago

Just a comment on the design,

I want to use Notifee to show notifications (using only silent notifications and no longer rely on the default behavior of firebase)

This is likely not going to work out well. iOS does not guarantee delivery of data-only FCM payloads. There are quite a few cases where your messages will not be delivered.

What most people want, I think, is to send FCM with notification payloads (they'll be delivered where data-only won't) on iOS, but implement the notification extension handler that lets you manipulate the notification after firebase-ios-sdk receives it and requests it to post to the iOS notification center, but before it actually does so.

Given this is an architectural comment, and I'm fairly sure it addresses your use case and creates a design change, I'm not sure investigating this specific issue has value at the moment

maximerenaud7 commented 3 years ago

Hey, thanks for your answer, that's a good point about design ! But I can see data-only notification used in Notifee documentation (https://notifee.app/react-native/docs/integrations/fcm#server-creation) And the fact that the phone always vibrate when I send the payload tells me that the notification is received but there is something wrong with the background handler.

mikehardy commented 3 years ago

Your current testing (the fact that the phone *always* vibrate when I send the payload tells me that the notification is received) will not reflect reality once deployed, if you rely on data-only notifications. In practice you will find they are not delivered reliably. Persist with this design if you want but if I can't be more clear: data-only messages are not reliably delivered.

Regardless, if you are having trouble with the background message handler firing, this is not our experience, so your problem will be project specific. Debugging from snippets is ineffective (specifically: surely you have more modules than the ones you list, how can we reproduce without the real stack?), we need a complete reproduction, and we provide them in the form of our tests app (in react-native-firebase) and we have an example now for notifee https://github.com/notifee/react-native-notifee/tree/master/example

Work from those as a base (fork/clone) - the notifee one most likely as you mention that? - and make sure it works to start, then add in firebase/app+messaging and reproduce.

My guess is you have something else messing with the AppDelegate swizzling react-native-firebase attempts, so control flow is interrupted and handlers aren't called. A full reproduction will show that.

stale[bot] commented 3 years ago

Hello 👋, to help manage issues we automatically close stale issues. This issue has been automatically marked as stale because it has not had activity for quite some time. Has this issue been fixed, or does it still require the community's attention?

This issue will be closed in 15 days if no further activity occurs. Thank you for your contributions.

stale[bot] commented 3 years ago

Closing this issue after a prolonged period of inactivity. If this is still present in the latest release, please feel free to create a new issue with up-to-date information.

babyrusa commented 3 years ago

@maximerenaud7 Hi, Have you found a way to work around this issue?