React-native-firebase: SetBackgroundHandler not working on ios.

Created on 24 Apr 2020  ·  79Comments  ·  Source: invertase/react-native-firebase


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`:

# N/A
#### `firebase.json` for react-native-firebase v6:
# N/A
### iOS
Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like:

# N/A
#### `AppDelegate.m`:
// 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`:

// N/A
#### `android/app/build.gradle`:
// N/A
#### `android/settings.gradle`:
// N/A
#### `MainApplication.java`:
// N/A
#### `AndroidManifest.xml`:
<!-- N/A -->


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




iOS Messaging >= 6

Most helpful comment

to ios background listen:

        firebase.messaging().onNotificationOpenedApp(remoteMessage => { 
            console.log('FIREBASE IOS Background', remoteMessage)

        });

All 79 comments

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

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

Can you post your App delegate file for iOS

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

Code please so we can copy bits

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

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

What data payloads are you sending over?

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
}

Oh interesting, what sdk are you using?

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);
    }
  }

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

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);

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.

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.

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.

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 :(

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

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

@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.

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

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.

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.

@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

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);
  1. 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.

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 ?

@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`: [...]

"@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:
# N/A
### iOS
Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like:

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`:
#import "AppDelegate.h"

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "RNBootSplash.h"
#import "RNQuickActionManager.h"
#import <Firebase.h>

#if DEBUG
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>

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<NSString *, id> *) 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`:

// N/A
#### `android/app/build.gradle`:
// N/A
#### `android/settings.gradle`:
// N/A
#### `MainApplication.java`:
// N/A
#### `AndroidManifest.xml`:
<!-- N/A -->


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`

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.

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 🤷

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

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.

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.

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.

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"

I found something concerns to this issue in flutter messaging
image

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

me too .. same problem here..

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.

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, }, }, }

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 :(

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

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!

Still not working on iOS.

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 ?

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

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.

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.

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:

  • When the app is running but minimised, the setBackgroundMessageHandler will fired when message arrived.
  • When the app is terminated, the setBackgroundMessageHandler will not fired even the message arrived.

Released Mode:

  • setBackgroundMessageHandler work on both Debug and 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);
  });

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

@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:

Hey folks! any news on this? I am not receiving notifications on iOS when the app is quit or background - following all the guide points, but nothing.

Hi @forbesgillikin,

same issue here as well,

packages' info:

dependencies:
"@react-native-firebase/analytics": "7.1.5",
"@react-native-firebase/app": "7.3.0",
"@react-native-firebase/crashlytics": "7.1.6",
"@react-native-firebase/messaging": "7.1.7",
"react": "16.9.0",
"react-native": "0.61.1",

devDependencies:
"@types/react-native": "0.60.23",

Others:
Xcode-11.2.1
node- v12.18.2
npm- 6.14.5

when using admin.messaging().sendToDevice and setBackgroundMessageHandler:
foreground & background works fine, but the quit state is not able to handle using setBackgroundMessageHandler
messaging().setBackgroundMessageHandler(async remoteMessage => {
try {
console.log(index.ios.js setBackgroundMessageHandler remoteMessage : ${JSON.stringify(remoteMessage)});
} catch (error) {
console.log(index.ios.js setBackgroundMessageHandler error : ${JSON.stringify(error)});
}
});
In order to handle the quit state, api & passed message got updated like below, here, admin.messaging().send is used instead of admin.messaging().sendToDevice

admin.messaging().send({
data: {
channelNumber: 'channel13'
},
apns: {
payload: {
aps: {
contentAvailable: true
}
},
headers: {
'apns-push-type': 'background',
'apns-priority': '5',
'apns-topic': "com.xyz.abc"//your app bundle identfier
}
},
fcmToken
}).then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});

but facing the below error, due to this, no data message is passed
node_modules/firebase-admin/lib/messaging/messaging-types.js:46
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Exactly one of topic, token or condition is required');
^
FirebaseMessagingError: Exactly one of topic, token or condition is required
at FirebaseMessagingError.FirebaseError [as constructor] (/Users/user/fcm-data-messages/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseMessagingError.PrefixedFirebaseError [as constructor] (/Users/user/fcm-data-messages/node_modules/firebase-admin/lib/utils/error.js:88:28)
at new FirebaseMessagingError (/Users/user/fcm-data-messages/node_modules/firebase-admin/lib/utils/error.js:254:16)
at Object.validateMessage (/Users/user/fcm-data-messages/node_modules/firebase-admin/lib/messaging/messaging-types.js:46:15)
at Messaging.send (/Users/user/fcm-data-messages/node_modules/firebase-admin/lib/messaging/messaging.js:208:27)
at buildDataMessageAndSend (/Users/user/fcm-data-messages/index.js:156:21)
at Object. (/Users/user/fcm-data-messages/index.js:267:21)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32) {
errorInfo: {
code: 'messaging/invalid-payload',
message: 'Exactly one of topic, token or condition is required'
},
codePrefix: 'messaging'
}

Please help me
Thanks In Advance

I have a similar issue.
It would not work on iOS but then I added content_avaible = true to my FCM-message and it seemed to work.
Now after release it only works on some devices. The notification is received but the SetBackgroundHandler is not firing. The older TestFlight-versions that I tested does not seem to work any longer either.
Im on v6.7.1.
Anyone else faced similar issues?
Thanks in advance.

@GustafLevinsson iOS may decide your app, on a specific device, is not worthy of the power budget to wake up and receive the message, so it simply won't. You can't see this unless you have the device logs (like the device is connected via cable with app launched via xcode or similar). User interaction, speed of device, cost of app init, all can factor in. It's maddening.

@mikehardy Is there any other function which could be firing when we click on a notification when the app is on background ?

to ios background listen:

        firebase.messaging().onNotificationOpenedApp(remoteMessage => { 
            console.log('FIREBASE IOS Background', remoteMessage)

        });

thanks @israelouteiro - that worked for me when the app was in background, but not when it was closed.

Edit: to get the notification when the app was closed you have to use firebase.messaging.getInitialNotification() method.
between these three methods (onMessage, onNotificationOpenedApp and getInitialNotification) it seems that it covers all use cases.

As part of the work on #4104 several PRs have been merged, including one just merged and released now as @react-native-firebase/7.8.4

We believe FCM messages will be handled now:

  • if you set content-available and priority headers correctly in your JSON payload
  • if you are on a real device
  • if the app is not running and your javascript bundle boots within 8 seconds (careful, redux-saga users! from a patch a few days ago)
  • if the app is in the background (with the most recent patch)

We are no longer aware of cases that don't have known solutions.

If you can reproduce a case after updating to the latest code and running npx react-native-clean-project to make sure you have a clean build, please open a new issue post an App.js that demonstrates the problem.

In iOS How to catch a push notification in background without user interaction? android working fine getting response at setBackgroundMessageHandler.

@kunalword using exactly the information in the comment I posted above yours, in combination with the documents for the background message handler in the messaging section of rnfirebase.io

So essentially we need to set the 'apns' property as part of the payload to trigger the functionality when the app is closed?

I have tried that from my backend and the result is the same ( app doesn't trigger the setBackgroundMessageHandler() functionality in the background)

@hasansultan92 Launch on a real device and watch console. Yes, send content-available in apns or it will not work with data only messages. If the user has swiped your app away your app is dead until a new user interaction, that's operating system policy. If you have been spending the power of the device too heavily iOS will throttle you. If your code and config isn't correct nothing will work. It is not easy but it does work when done correctly.

Hey so yes I have been using a real device and I used Xcode to build the app on the device. I can see the logs when the app is in background state(minimized) but obviously once I close the app on the device, the logs and connection to Xcode gets terminated so I can't really see what's happening when a message is being sent while the app is closed. The library/modules are working just fine on android.

I am sending notification plus data using my backend with the Admin SDK and whichever device I send it to, the notification pops up right away (including iOS even when in quit state) but just the background processes aren't being triggered for iOS. I did check my app power usage and it was high on a iPhone 6 however(that's probably because of the enormous number of console logs I was working with earlier). Please note I tried to check if the functionality was working in production env by uploading the app to TestFlight but yea that didn't work either. Im doubting my appdelegate.m config since I don't understand objective C so maybe if you have the simplest form of appdelegate.m that works could you share that? I also noticed iOS enabled some keys in info.plist and Id like to confirm if that's normal cause I have not seen any information about them so far.

Use Console.app
If you send notification in the payload, not data only, your messages receive different handling
AppDelegate shouldn't need anything i RNFBv6, just follow the rnfirebase.io docs

@mikehardy not sure what you mean by Console.app, is it the remote debugger using chrome?

As far as the docs show on firebase.io the handlers handling the messages with notification+ data are onMessage() - this works for sure - and setBackgroundMessageHandler()- doesn't work when app is quit in iOS.

Also Im not using RNFBv6, my packages are "@react-native-firebase/app": "^8.4.2", "@react-native-firebase/messaging": "^7.8.6", in package.json and I believe the corresponding numbers in the pod file.

If your sure this issue isn't a problem anymore on v6 I don't mind setting up the older version to be honest.

Definitely not the remote debugger with chrome. I believe that might even confound some of the functionality, I do not develop the debugger turned on, myself, as it executes the bundle off device and can have incorrectness side effects that are not expected.

Console.app is literally Console.app on your mac machine, while the real ios device is plugged in you may follow the devices logs.

Sorry the use of the phrase "v6" is imprecise and I should not have used it. There was a big break between V5 and V6 and we used to use "V6" as shorthand for "most current / modern". All of the versions are higher now of course, current stable is what I really intend.

setBackgroundMessageHandler does work when app is quit but not force closed / swiped away if that makes sense - the wording needs to be accurate/precise here. quit is the state when the app has been stopped by the OS in the background to preserve resources but the user did not actually kill the thing. In those cases, data only will work.

@mikehardy yea so I checked console.app from Xcode etc and yea indeed the device isn't registering the notification that came when the app has been killed/swiped off from the app drawer. I can see a log for the speaker to make a sound when the message comes in but nothing else no errors either. I however, can see the logs for a notification when the app is in background(minimized) and in foreground. To eliminate the CPU throttling fact that has been mentioned in several docs, I do not see any logs for cpu usage being high or anything when the app is in background or foreground but I do see an instruction when the device is sitting idle doing nothing to reduce cpu power.

As for the following - 'setBackgroundMessageHandler does work when app is quit but not force closed / swiped away if that makes sense - the wording needs to be accurate/precise here.' - I am guessing when the message comes in and the app was swiped away it takes the app to a background only mode? This however is not working for me on iOS. I have been debugging this app for the past 1 week just so I can save the message being sent from another user but I guess Ill have to now try another push notification service as this headache Is beyond my knowledge. PS, I did try data only and no that did not work either.

If there is anyone who actually got this library to work please please dm me

@hasansultan92 - "app swiped" == your app is dead. You will never get logical control back until a user taps on a visible notification or launches your app.

@mikehardy so essentially are u saying this is an iOS problem or something the library is not able to achieve? clearly when the app is swiped in android I can still perform the tasks I want using set backgroundHandler so Im gonna goes iOS on this. Ill tell you what I am trying to achieve and maybe you can tell me back if its impossible with this library or even push notifications in general. I am basically making a chat app and every time the receiving user is offline I want the push notifications to carry the data to the device and perform the actions to update local storage. Essentially if the user doesn't have my app running in the background or foreground on iOS he will never be able to see the new messages in the chat area. I obviously don't want to load all the messages from the db- it'll keep my server load busy and consumption of bandwidth will be high- so what other way can I solve this task of saving texts that were sent to the user when they were offline?

Yes, I am aware your a contributor to the library but you know, you might know the answer I am looking for

If the app is swiped the app is dead via ios policy. Iron law with the only exception being a notification may be posted to the notification center. You will need to do your own research and testing, my answers are brief but complete

...at least to the extent that I am not going to design your app architecture. That's on you of course, no offense

@mikehardy none taken. Its just the docs stated that the app is allowed to run headless/in the background and the handler is going to be the same as the background state for the quit state. If I knew that this functionality is limited by either the library itself or how react-native works I wouldn't have spent nearly a week into this you know. its alright thank you for your feedback. back to the drawing board it is for me

headless is a complicated topic
In general it is android-specific / android only, it is a separate execution mode that bears examination on it's own, there are documents on react-native dev site about it

However, there is the case where your app on ios is fully launched (there is no true headless mode in ios), and there is a way to inject a property into the launch sequence simply so you can see if that is how you were launched in ios. This can happen if your app is allowed to start in response to a data-only cloud message, but is different than the "pure headless" mode that android has

You are implementing a pretty complicated system, in the exact areas that the operating systems protect the most (app starts, remote programming that requires permissions, energy usage etc). There's no avoiding the difficulty unfortunately. Make tiny example prototypes and test them is my advice. When I was developing this area of my app I just had a separate dev-only screen with buttons for each thing I wanted, and lots of logging and tested away until I found a mix of things that worked.

I believe the how is UIApplicationLaunchOptionsRemoteNotificationKey and I don't know Objective-C/Swift so yea right now Im looking for some objective c developers who can help me. Since this is more of a react-native headache I am going to assume that apps like Airbnb, FB, etc use the native part to handle the notification data and save it etc because so far I don't see any other way that user messages can come to devices and be saved. Thank you for your help though @mikehardy .

I believe they fetch state from server on app startup when user interacts with notification. Have you ever gotten a new message notification from facebook but then interacted with it while in airplane mode? That will show more how other apps do this

Ok. So. I have seen a lot of these threads over the last 2 months since I implemented Notifications in my app. The issue here is the RN Firebase Docs and the terminology used for different app states, coupled with a fundamental misunderstanding of how notifications work on iOS, and developers not doing their own docs research on the Apple Developer resources.

RN FIREBASE WORKS AS EXPECTED. YOU MUST UNDERSTAND THAT IF YOUR APP HAS BEEN CLOSED OR KILLED, BACKGROUND NOTIFICATIONS WILL NOT BE DELIVERED. THERE ARE NO PROBLEMS WITH THE RN FIREBASE CODE.

READ THE DOCUMENTATION FROM APPLE

https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app

Pushing Background Updates to Your App

Deliver _notifications that wake your app_ and update it in the background.

IMPORTANT: Notifications that WAKE your app. If your app is closed, nothing will happen.

Background notifications are not useful in most common app frameworks. Stick to _alert_ style notifications.

I had made a Firebase Push notification tutorial video hope it will help those who faced problem.

https://www.youtube.com/watch?v=wC3N-hxkWbk

Guys use below payload while sending data only notifications(remove title and body from notification) or data plus notifications

{
"registration_ids": [""],
"message" : "You Got A Call",
"priority": "high",
"notification": { "title": "msg for topic", "body": "bodytext", "content_available": "true" },
"data": {
"priority": "high",
"callType": "audio",
}
}

Index.js should be
messaging().setBackgroundMessageHandler(async remoteMessage => {
// your logic or put alert
});
function HeadlessCheck({ isHeadless }) {
if (isHeadless) {
// App has been launched in the background by iOS, ignore
return null;
}
return ;
}

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

setBackgroundMessageHandler works on both iOS and Android when app is minimized:)

Guys use below payload while sending data only notifications(remove title and body from notification) or data plus notifications

{
"registration_ids": [""],
"message" : "You Got A Call",
"priority": "high",
"notification": { "title": "msg for topic", "body": "bodytext", "content_available": "true" },
"data": {
"priority": "high",
"callType": "audio",
}
}

Index.js should be
messaging().setBackgroundMessageHandler(async remoteMessage => {
// your logic or put alert
});
function HeadlessCheck({ isHeadless }) {
if (isHeadless) {
// App has been launched in the background by iOS, ignore
return null;
}
return ;
}

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

setBackgroundMessageHandler works on both iOS and Android when app is minimized:)

Hi @ch3tan03 .

I saw you mentioned tha "sending data only notifications(remove title and body from notification) or data plus notifications",but in your notification tag , there are title and body? Can you elaborate more?

Thanks

Was this page helpful?
0 / 5 - 0 ratings