Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS Background Notification troubleshooting #3367

Closed
1 of 5 tasks
aslanon opened this issue Mar 29, 2020 · 214 comments
Closed
1 of 5 tasks

iOS Background Notification troubleshooting #3367

aslanon opened this issue Mar 29, 2020 · 214 comments
Labels
platform: ios plugin: messaging FCM only - ( messaging() ) - do not use for Notifications

Comments

@aslanon
Copy link

aslanon commented Mar 29, 2020

Issue

Hello, notifications run while the app is on the foregound, but I didn't receive any messages when the app is in the background or killed.

There are a lot of documentation but I can't solve this problem.
What am I doing wrong?


Project Files

Javascript

Click To Expand

package.json:

  "dependencies": {
    "@react-native-community/push-notification-ios": "^1.1.0",
    "@react-native-firebase/app": "^6.4.0-rc4",
    "@react-native-firebase/messaging": "^6.4.0-rc4",
    "react": "16.9.0",
    "react-native": "0.61.5",
    "react-native-push-notification": "^3.1.9",
  }

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • 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'

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 '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/jscallinvoker', :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'

  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'
  
  pod 'react-native-orientation', :path => '../node_modules/react-native-orientation'

  target 'MyappTests' do
    inherit! :search_paths
    # Pods for testing
  end

  use_native_modules!
end

target 'Myapp-tvOS' do
  # Pods for Myapp-tvOS

  target 'Myapp-tvOSTests' do
    inherit! :search_paths
    # Pods for testing
  end

end

AppDelegate.m:

/**
 * 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>

#import <Firebase.h>
#import <RNCPushNotificationIOS.h>
#import <UserNotifications/UserNotifications.h>

#import "Orientation.h" 

@implementation AppDelegate



// Required to register for notifications
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
 [RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
}
// Required for the register event.

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
 [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
  [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
 [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}
 
// Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
 [RNCPushNotificationIOS didReceiveLocalNotification:notification];
}




- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

 
   RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:@"Myapp"
                                            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];

  [FIRApp configure];

  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  center.delegate = self;

  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


Environment

Click To Expand

react-native info output:

info Fetching system and libraries information...
System:
    OS: macOS 10.15.1
    CPU: (4) x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
    Memory: 2.36 GB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 12.13.0 - /usr/local/bin/node
    Yarn: 1.19.1 - /usr/local/bin/yarn
    npm: 6.12.0 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
  IDEs:
    Xcode: 11.3.1/11C504 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.9.0 => 16.9.0
    react-native: 0.61.5 => 0.61.5
  npmGlobalPackages:
    react-native-cli: 2.0.1
  • Platform that you're experiencing the issue on:
    • [x ] iOS
    • Android
    • [ x] 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:
    • none // because I removed when I use to 6.4.0-rc4
  • Firebase module(s) you're using that has the issue:
    • e.g. Instance ID
  • Are you using TypeScript?
    • N


Think react-native-firebase is great? Please consider supporting all of the project maintainers and contributors by donating via our Open Collective where all contributors can submit expenses. [Learn More]

@Ehesp
Copy link
Member

Ehesp commented Mar 29, 2020

Can you show some code please?

@Salakar
Copy link
Member

Salakar commented Mar 29, 2020

Also are you testing on a real device, background/quit states only work on a real device and not on the simulator. @Ehesp do we actually mention this on the docs anywhere btw?

@Ehesp
Copy link
Member

Ehesp commented Mar 29, 2020

I think so, may need making more obvious...

@aslanon
Copy link
Author

aslanon commented Mar 29, 2020

I am testing on a real device.

App.js

import React, {useEffect, useState} from 'react';
import {Alert} from 'react-native';

import messaging from '@react-native-firebase/messaging';
import firebase from '@react-native-firebase/app';
import PushNotification from 'react-native-push-notification';
import PushNotificationIOS from '@react-native-community/push-notification-ios';


const App = () => {
  useEffect(() => {
    registerAppWithFCM();
    requestPermission();

    messaging().onNotificationOpenedApp(remoteMessage => {
      console.log(
        'Notification caused app to open from background state:',
        remoteMessage.notification,
      );
      Alert.alert(
        'Notification caused app to open from background state:',
        JSON.stringify(remoteMessage),
      );
    });

    // Check whether an initial notification is available
    messaging()
      .getInitialNotification()
      .then(remoteMessage => {
        if (remoteMessage) {
          console.log(
            'Notification caused app to open from quit state:',
            remoteMessage.notification,
          );
          Alert.alert(
            'Notification caused app to open from quit state:',
            JSON.stringify(remoteMessage),
          );
        }
      });

    const unsubscribe = messaging().onMessage(async remoteMessage => {
      Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));

      PushNotification.localNotification({
        title: 'notification.title',
        message: 'notification.body!',
      });
    });

    return unsubscribe;
  }, []);

  async function registerAppWithFCM() {
    await messaging().registerDeviceForRemoteMessages();
  }

  async function requestPermission() {
    const granted = await messaging().requestPermission({
      alert: true,
      announcement: false,
      badge: true,
      carPlay: true,
      provisional: false,
      sound: true,
    });
    if (granted) {
      const fcmToken = await messaging().getToken();
      console.log(fcmToken);
      console.log('User granted messaging permissions!');
    } else {
      console.log('User declined messaging permissions :(');
    }
  }

  return (
   <View></View>
  );
};

export default App;

index.js

/**
 * @format
 */

import React from 'react';
import {AppRegistry, Alert} from 'react-native';
import App from './App';
import {name as appName} from './app.json';

import messaging from '@react-native-firebase/messaging';

messaging().setBackgroundMessageHandler(async remoteMessage => {
  console.log('Message handled in the background!', remoteMessage);
  Alert.alert('BACKGROUND', JSON.stringify(remoteMessage));
});

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

AppRegistry.registerComponent(appName, () => HeadlessCheck);

@Ehesp
Copy link
Member

Ehesp commented Mar 29, 2020

How are you checking whether the background events are working? You're doing an alert, however there's no app to trigger an alert in the background?

@gmertk
Copy link

gmertk commented Mar 29, 2020

Just passing by as I was looking through notification issues.

Correct me if I'm wrong but this looks sketchy:

    registerAppWithFCM();
    requestPermission();

According to docs, requestPermission must be called once the the app has registered with FCM. Since both of your functions are async, you might ask for permissions before registerAppWithFCM resolves.

Not sure if this would break anything. Maybe others shed some light on this.

@ixuz
Copy link

ixuz commented Mar 30, 2020

I experience similar issue after upgrading to this version 6.4.0-rc4, somehow my App successfully obtains an FCM token from the Firebase Messaging SDK, but the application itself is not visible in the iOS Notification settings page.

My hunch is that the Firebase Messaging SDK somehow fails to register the App for push notifications, but returns an fcm token anyway. 😕

@ngregrichardson
Copy link

I'm having the same issue. I receive notifications in the foreground, but the code from onMessage isn't called until the app is brought to the foreground again after receiving a notification in the background. I am on the same version numbers and am also on a real device. I am following this order:

  1. await registerDeviceForRemoteMessages
  2. hasPermission/requestPermission
  3. setup onTokenRefresh
  4. setBackgroundMessageHandler

@Ehesp
Copy link
Member

Ehesp commented Mar 30, 2020

@aslanon looking at your AppDelegate file, you've got loads of other methods which are calling RNCPushNotificationIOS. I suspect this will be causing some problems. Try to remove these and see if things work.

Also as @gmertk pointed out, your code is going to be subject to race conditions, and also you're not catching any errors.

@ixuz Is the request for permissions popup showing? No notifications option is nothing to do with whether remote ones can be received, that means the permissions request was never triggered.

@ixuz
Copy link

ixuz commented Mar 30, 2020

@aslanon looking at your AppDelegate file, you've got loads of other methods which are calling RNCPushNotificationIOS. I suspect this will be causing some problems. Try to remove these and see if things work.

Also as @gmertk pointed out, your code is going to be subject to race conditions, and also you're not catching any errors.

@ixuz Is the request for permissions popup showing? No notifications option is nothing to do with whether remote ones can be received, that means the permissions request was never triggered.

The permission request pop-up does not automatically show up, however I still get the fcm token in return.

await firebase.messaging().requestPermission({
      alert: true,
      announcement: false,
      badge: true,
      carPlay: false,
      provisional: false,
      sound: true
    }

@Ehesp
Copy link
Member

Ehesp commented Mar 30, 2020

Yeah they're not related. Permissions is a local device thing which iOS reads when it needs to display a notification (if it doesn't have permission, it won't show).

The FCM token is requested when you register the device.

@ixuz
Copy link

ixuz commented Mar 30, 2020

@Ehesp I've adjusted my code slightly, and found the reason why I did not receive any push notification permission request pop-up. I didn't evaluate the hasPermission against the AuthorizationStatus keys.

So now the request permission popup is showing up, and upon acceptance, the app shows up in the iOS Settings/Alarms screen(all permissions granted). All good! 👍

Except for one thing, whenever I try to send a push notification to the obtained fcm token, it never shows up on the device.

Here's a complete sample of how I'm obtaining the fcm token.

if (!firebase.messaging().isDeviceRegisteredForRemoteMessages) {
  await firebase.messaging().registerDeviceForRemoteMessages();
}

let authStatus = await firebase.messaging().hasPermission();

if (authStatus !== firebase.messaging.AuthorizationStatus.AUTHORIZED) {
  authStatus = await firebase.messaging().requestPermission({
    alert: true,
    announcement: false,
    badge: true,
    carPlay: false,
    provisional: false,
    sound: true
  });
}

if (authStatus === firebase.messaging.AuthorizationStatus.AUTHORIZED) {
  const token = await firebase.messaging().getToken();
  if (token) {
    // Here the "token" is defined, but push notifications never arrive using this fcm token...
  }
}

I'm sending my test push notification via the Firebase project page "Compose notification">"Send test message".

Any advice?

@Salakar
Copy link
Member

Salakar commented Mar 30, 2020

Details

@ixuz Can you confirm:

  • this is on a real device
  • PushNotifications capability added to your Xcode project
  • if data messages & for background/quit states;
    • Background Modes -> Remote Notifications is added to your Xcode project capabilities.
    • APNS content-available is set on message payload & priority is high

@ixuz
Copy link

ixuz commented Mar 30, 2020

@Salakar I confirm:

  • Real device "iPhone 5c", not a simulator.
  • Confirms PushNotifications capability is added to Xcode project, also our push notifications worked with the prior version: 6.3.4.
  • Confirms Background Modes -> Remove Notification is added and checked.

@Salakar
Copy link
Member

Salakar commented Mar 30, 2020

@ixuz uninstall and re-install the app on your device once you've made that change. Note after doing this you will have a new token though

@ixuz
Copy link

ixuz commented Mar 30, 2020

@Salakar Alright, I've followed your advice, see my steps below:

  1. Completely uninstalled app from device.
  2. I've omitted the if condition
//if (!firebase.messaging().isDeviceRegisteredForRemoteMessages) {
await firebase.messaging().registerDeviceForRemoteMessages();
//}
  1. Xcode Clean -> Build (Release version + signing) -> Run (on real device: Iphone 5c)
  2. App launches, prompt appears asks me to accept push notification. I click agree. (at this point I can see that a new token was obtained and sent to our api)
  3. Now I close our App on the device again(fully terminated app process). And I also verify that all permissions are granted in iOS settings/alarms/Our app. Confirm all sliders are active.
  4. I let the device go to lockscreen/sleep.
  5. Finally, I try send a test push notification via the Firebase project page "Compose notification">"Send test message" (of course using that newly obtained token).

No dice, the push notification does not appear on my device. 😖

Anything else I could be missing? Thank you so far!

@aslanon
Copy link
Author

aslanon commented Mar 30, 2020

I used console.log and local UI notification for background notifications but I deleted these codes when copy to here. @Ehesp .

I tried different things, but my problem is not solved. While the application is foreground, notifications are coming from the remote server. I also send notifications through the Firebase Cloud Messaging interface. @gmertk

resim

onMessage response:

A new FCM message arrived! {"data":{"title":"Başlık","notification":{"title":"Başlık","e":"1","body":"mesaj"},"content_available":"true","body":"mesaj"},"collapseKey":"com.mobile.Hybrone","from":"1041079541037"}

@aslanon looking at your AppDelegate file, you've got loads of other methods which are calling RNCPushNotificationIOS. I suspect this will be causing some problems. Try to remove these and see if things work.

Also as @gmertk pointed out, your code is going to be subject to race conditions, and also you're not catching any errors.

The push-notification-ios library was running until I installed @react-native-firebase/app and @react-native-firebase/messaging. But now, it is not working. I removed this package after your comment.

Right now, I choose this option from the menu and the app goes to the background. Then I send the notification. But I can't see an output at the terminal. But when I get back to the application, the notification comes to the terminal.

resim

How do you suggest testing background notifications? @Ehesp

Thank you for your help. @Ehesp @Salakar @gmertk

@Ehesp
Copy link
Member

Ehesp commented Mar 30, 2020

Hmm, everything looks as it should be to be honest.

When writing the new version, we hit an issue on older iOS devices where an incoming message was being ignored because the device did not have enough resource to handle it. We only found this out by looking in the iOS logs.

@Salakar is there anyway to easily access those logs apart from digging into XCode?

@thehappydinoa
Copy link

@Ehesp We tried using @aslanon 's Simulate Background Fetch option and had notifications come through fine, but otherwise it is broken. Is there anything I can help debug or try?

@Ehesp
Copy link
Member

Ehesp commented Mar 31, 2020

Interesting... Let me look into what that is actually doing and I'll take a look. On the face of it, it'd seem a background fetch on the device is not happening. Can you show a screenshot of your XCode capabilities?

@aslanon
Copy link
Author

aslanon commented Mar 31, 2020

Have you tried with the latest version of React Native (ios)? Can you share a example app project? @Ehesp
Screenshot 2020-03-31 at 13 07 43

@Salakar Salakar added plugin: messaging FCM only - ( messaging() ) - do not use for Notifications and removed plugin: in_app_messaging Firebase In-App Messaging (FIAM) labels Mar 31, 2020
@embpdaniel
Copy link
Contributor

I'm also having similar issues as has been mentioned. I've tested building with my previous app version (same project, which used v5.2.2) vs 6.4.0-rc4. 5.2.2 works without issues.

@aslanon
Copy link
Author

aslanon commented Apr 1, 2020

What is your react-native version working with v5.2.2? @embpdaniel

@Ehesp
Copy link
Member

Ehesp commented Apr 1, 2020

@embpdaniel What device are you trying it with (and what iOS version)? When we were testing, old devices were struggling to handle a background payload fetch due to a lack of system resource available.

@embpdaniel
Copy link
Contributor

@aslanon The react native version for v5.2.2 is 0.57.8

@Ehesp I am testing on an iPhone X with ios version 13.3.1. The device is not old and pretty bare (I just use it to test apps) so it should be able to handle it.

@mikehardy
Copy link
Collaborator

@gev that will be something different. If it works at all then all of the programmatic hooks are working. If the device (or APNS) refuses to send or receive messages over cell networks is not related to this library, it does not differentiate at all between network types

@gev
Copy link

gev commented Sep 10, 2020

@mikehardy I'm not alone. First reference the problem was here #3367 (comment)
PS Push notification in the cellular network received as well

@mikehardy
Copy link
Collaborator

@gev so how are your background data settings for the app? power savings settings for the app etc? What's it looks like when you run it via Xcode so you can see debug logging?

@gev
Copy link

gev commented Sep 11, 2020

@mikehardy @buchgv I'm sorry for the offtopic. Think this could be useful to somebody else: https://stackoverflow.com/questions/26959472/silent-push-notifications-only-delivered-if-device-is-charging-and-or-app-is-for
About handling messages in cellular networks

@mikehardy
Copy link
Collaborator

Great link! That's what I was hinting (but not specifically) at with regard to power savings and Xcode debug logging - you will see when your app is getting throttled, and it's possible to happen even for thermal management reasons! iOS power miser machine learning is quite stingy, and your app needs interaction and needs to behave well to be woken up reliably.

@axeljeremy7
Copy link

axeljeremy7 commented Sep 30, 2020

[FIRMessaging messaging].autoInitEnabled = YES;

is this neccesary? and where do you insert it?

@axeljeremy7
Copy link

Just a quick aside, there are a couple of troubleshooting steps everyone should probably go through if this isn't working for them.

1. Make sure you are testing on a real device. It will not work on simulator.

2. Make sure your payload to the FB SDK includes a notification parameter or it will not show a notification.

3. Check that you have asked for and got permission from the user to show notifications in Settings -> My App -> Notifications. If there is no item for notifications, you haven't asked for permission in your app and configured that.

There is a post above with a load of stuff for you AppDelegate.m to get this working. The only part of that I have included is a single line.

[FIRMessaging messaging].autoInitEnabled = YES;

All the other stuff wasn't required to get them working. I think a lot of the code above will achieve some of the steps you can do on the JS side really easily.

where do you insert it?

@mikehardy
Copy link
Collaborator

@axeljeremy7 that shouldn't be necessary. If you just install the messaging module with the most basic integration and you have user permission on ios for notifications, and you send a notification payload it should work. It depends on all the configs being right everywhere though (apple developer console, firebase config console on the web, etc) which is of course challenging

@axeljeremy7
Copy link

axeljeremy7 commented Oct 1, 2020

@axeljeremy7 that shouldn't be necessary. If you just install the messaging module with the most basic integration and you have user permission on ios for notifications, and you send a notification payload it should work. It depends on all the configs being right everywhere though (apple developer console, firebase config console on the web, etc) which is of course challenging

I get background and remote notifications using react-native-community / push-notification-ios but not with firebase, any of the functions of the messaging module are not working, I am able to get the device token APN, and check that if the same for both libraries but when to check onMessage for instance or other functions, no response at all.

https://gist.github.com/axeljeremy7/d61ca69d69989eff79938882932bd835
https://gist.github.com/a8c8c42ad20e66d71c53125acfc121fa

@mikehardy
Copy link
Collaborator

So, you have two push messaging packages hooked up in your project, and one of them isn't firing, is that accurate? 🤔 - perhaps they are not chained together well? I think you should you only hook up one set of cloud message handlers in your project or this might happen, that's where I'd look - AppDelegate message handlers and all the associated method swizzling that react-native-firebase and firebase-ios-sdk does

@hamyhya
Copy link

hamyhya commented Oct 7, 2020

I can't receive background notifications untill I add permission request. And here is my line of code, hope can help someone.

requestUserPermission = async () => {
const authorizationStatus = await messaging().requestPermission();

if (authorizationStatus) {
  console.log('Permission status:', authorizationStatus);
}

};
componentDidMount() {
messaging()
.subscribeToTopic('gmi')
.then(() => console.log('Subscribed to topic!'));
this.requestUserPermission(); // reuest permission for background notifications
messaging().onMessage(async remoteMessage => {
Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
});
}

@ShivangiAgrawal
Copy link

ShivangiAgrawal commented Dec 16, 2020

@mikehardy I am still facing the issue when the app is in background or closed state. The notifications are shown in the notification center in all cases but the messaging().setBackgroundMessageHandler doesn't get called every time but only some times while checked rigorously on the app. Followed the official documentation for cloud messaging, upgraded to version 10.2.0 for @react-native-firebase/messaging and @react-native-firebase/app. All the states callbacks are working fine in Android and obtained perfectly every time, the issues exist only for iOS and not sure what is causing all this mess.

Adding here code for ref that I am using.
In the entry file i.e. index.js

messaging().setBackgroundMessageHandler(async (remoteMessage) => {
  console.log("Message handled in the background! 1", remoteMessage);
});

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

AppRegistry.registerComponent(appName, () => HeadlessCheck);

In App.js:

const App = () => {
  var notif = new NotifService();
  useEffect(() => {
    requestUserPermission()
    checkPermission()
    console.log("checkPermission")

    const unsubscribe = messaging().onMessage(async remoteMessage => {
      console.log("A new FCM message arrived!: foreground: ", remoteMessage)
      console.log("A new FCM message arrived!: foreground: ", remoteMessage.messageId)
      // Alert.alert('A new FCM message arrived!: foreground: ', JSON.stringify(remoteMessage));
      notif.localNotif();
    });
  
    return unsubscribe;
  }, []);

  useEffect(() => {
    messaging().onNotificationOpenedApp(remoteMessage => {
      console.log(
        'Notification caused app to open from background state:',
        remoteMessage.notification,
      );
      Alert.alert('Message handled in the background state!', JSON.stringify(remoteMessage));
      // navigation.navigate(remoteMessage.data.type);
    });
  
    // Check whether an initial notification is available
    messaging()
      .getInitialNotification()
      .then(remoteMessage => {
        if (remoteMessage) {
          console.log(
            'Notification caused app to open from quit state:',
            remoteMessage.notification,
          );
          Alert.alert('Message handled in the quit state!', JSON.stringify(remoteMessage));
          // setInitialRoute(remoteMessage.data.type); // e.g. "Settings"
        }
        // setLoading(false);
      });
  }, []);

  async function requestUserPermission() {
    const authStatus = await messaging().requestPermission();
    const enabled =
      authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
      authStatus === messaging.AuthorizationStatus.PROVISIONAL;
  
    if (enabled) {
      console.log('Authorization status:', authStatus);
    }
  }

    // 1
    async function checkPermission() {
      const enabled = await messaging().hasPermission();
      console.log("checkPermission: enabled: ", enabled)
      if (enabled) {
        getToken();
      } else {
        requestPermission();
      }
    }
  
    // 3
    async function getToken() {
      let fcmToken = await AsyncStorage.getItem('fcmToken');
      console.log('fcmToken @@1:', fcmToken);
      if (!fcmToken) {
        fcmToken = await messaging().getToken();
        console.log('fcmToken @@2:', fcmToken);
        if (fcmToken) {
          // user has a device token
          await AsyncStorage.setItem('fcmToken', fcmToken);
        }
      }
    }
  
    // 2
    async function requestPermission() {
      console.log("requestPermission:")
      try {
        await messaging().requestPermission();
        // User has authorised
        getToken();
      } catch (error) {
        // User has rejected permissions
        console.log('permission rejected');
      }
    }
}

Payload that I tested using firebase rest API:
{ "to": "TOKEN_HERE", "data": { "notification": { "title": "ABC1", "body": "xyz1" }, "Name": "121" }, "notification": { "title": "ABC1", "body": "xyz1" }, "priority": "high", "content_available": true }

Please paste here if anybody faced same issue and resolved that. Stuck for days with this now! Thanks.

@mikehardy
Copy link
Collaborator

mikehardy commented Dec 16, 2020

I don't believe your payload is correct. Multiple notification chunks? content available not in the right spot?

The API ref is here https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#Message

Let me be clear on this point: the module works, you are having a project-specific problem. I say that because I may not have time to help further. Triple-check your JSON. If you don't want it to go to the notification tray do not include notification anywhere as only data-only trigger the background handler. This is all covered in the docs so there is not much we can do: you need to implement it correctly https://rnfirebase.io/messaging/usage#data-only-messages

@navaighani
Copy link

navaighani commented Dec 27, 2020

I have the same issue with the different json object and the same code as other guys have.
every thing is ok in Android. But iOS in background (app is alive in app switcher) receives the push message and shows notification on notification center, but will not wake up my app to process RemoteMessage . I mean setBackgroundMessageHandler() is not called.

would you please help me?

{
  "to": "my_device_token",
  "priority": "high",
  "contentAvailable": true,
  "notification": {
    "title": "test",
    "body": "test"
  },
  "data": {
    "title": "test",
    "body": "test",
  },
  "apns": {
    "payload": {
      "aps": {
        "contentAvailable": true
      }
    },
    "headers": {
      "apns-push-type": "background",
      "apns-priority": 5,
      "apns-topic": "my_bundle_identifier"
    }
  }
}

@mikehardy
Copy link
Collaborator

mikehardy commented Dec 27, 2020

@navaighani I don't believe the handler is called until the user interacts with the notification when you send a mixed payload

https://firebase.google.com/docs/cloud-messaging/concept-options#notification-messages-with-optional-data-payload

When in the background, apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification.

@j-cheung
Copy link

j-cheung commented Mar 4, 2021

Hi all,
Recently ran into this issue with invoking the function within setBackgroundMessageHandler() while the iOS app is in the background. Not sure which exactly resolved the issue, but tried a few changes and got it working.

  1. Updated to latest react-native-firebase version (10.8.1 at the time)
  2. Updated the server sending notifications to use HTTP API v1 instead of Legacy API
    • this enables the correct headers mentioned above i believe.
{
    token: (token),
    notification: {
      title: (title),
      body: (message)
    },
    data:{
      (your data)
    },
    apns: {
      # "headers": {
      #   "apns-push-type": "background",
      #   "apns-priority": "10",
      #   "apns-topic": (bundle identifier)
      # },
      payload: {
        aps: {
          "content-available": 1,
        },
      }
    },

not sure why it works with the apns headers commented out... but hope it helps!

@surferxo3
Copy link

Hi all,
Recently ran into this issue with invoking the function within setBackgroundMessageHandler() while the iOS app is in the background. Not sure which exactly resolved the issue, but tried a few changes and got it working.

  1. Updated to latest react-native-firebase version (10.8.1 at the time)

  2. Updated the server sending notifications to use HTTP API v1 instead of Legacy API

    • this enables the correct headers mentioned above i believe.
{
    token: (token),
    notification: {
      title: (title),
      body: (message)
    },
    data:{
      (your data)
    },
    apns: {
      # "headers": {
      #   "apns-push-type": "background",
      #   "apns-priority": "10",
      #   "apns-topic": (bundle identifier)
      # },
      payload: {
        aps: {
          "content-available": 1,
        },
      }
    },

not sure why it works with the apns headers commented out... but hope it helps!

Your solution solved the issue where we needed to show alert push update data when ios app in background state. Many thanks for sharing it.

@gogulnathv
Copy link

@Ehesp I've adjusted my code slightly, and found the reason why I did not receive any push notification permission request pop-up. I didn't evaluate the hasPermission against the AuthorizationStatus keys.

So now the request permission popup is showing up, and upon acceptance, the app shows up in the iOS Settings/Alarms screen(all permissions granted). All good! 👍

Except for one thing, whenever I try to send a push notification to the obtained fcm token, it never shows up on the device.

Here's a complete sample of how I'm obtaining the fcm token.

if (!firebase.messaging().isDeviceRegisteredForRemoteMessages) {
  await firebase.messaging().registerDeviceForRemoteMessages();
}

let authStatus = await firebase.messaging().hasPermission();

if (authStatus !== firebase.messaging.AuthorizationStatus.AUTHORIZED) {
  authStatus = await firebase.messaging().requestPermission({
    alert: true,
    announcement: false,
    badge: true,
    carPlay: false,
    provisional: false,
    sound: true
  });
}

if (authStatus === firebase.messaging.AuthorizationStatus.AUTHORIZED) {
  const token = await firebase.messaging().getToken();
  if (token) {
    // Here the "token" is defined, but push notifications never arrive using this fcm token...
  }
}

I'm sending my test push notification via the Firebase project page "Compose notification">"Send test message".

Any advice?

This saved my day

@gezichenshan
Copy link

gezichenshan commented Jun 10, 2022

I have some success - have background message handler called in background state of app. For this was just need to set content-available flag in message. Here in documentation said that it is need only for "data-only" messages, but it is not. My messages was have notification, that was always shown in notification center, but not calling didReceiveRemoteNotification. It started work as expected only after I have added content-available flag to messages.

Although I still have problem with background message handler in app quit state - by logs in console I see that app started in background when message received, but handler not called. But possibly this problem with my app - I will search more.

Update (about quit state): It just work in release build configuration. I have spend few more hours trying to understand how native part works. I found that in my case, when using debug build configuration, when app in quit state, notification successfully processed on native side. But then it sent to javascript side with event messaging_message_received_background here but event listener here not called. Although event not fired, same time I see that app launched on background when notification received.

Thank @Zaporozhec7 It is correct!

I added the apns payload into my message json and the background message got by the listener.

const message = {
  notification: {
    title: 'test',
    body: 'body',
  },
  data: {
    alarm: JSON.stringify({
        person_id: '48',
      },
      person: {
        id: '48',
      },
    }),
  },
  apns: {
    payload: {
      aps: {
        contentAvailable: true,
      },
    },
  },
  token:token
};

admin
  .messaging()
  .send(message)
  .then(response => {
    console.log('Successfully sent message:', response);
  })
  .catch(error => {
    console.log('Error sending message:', error);
  });

@AlixH
Copy link

AlixH commented Nov 16, 2022

Have spent the day testing this again; here's my findings:

iPhone 5s - iOS 12.4.5

Foreground

Foreground = App is visible & open

Notification+Data: ✅

Notification not shown to user, only event received (correct behaviour) image

Notification only: ✅

Notification not shown to user, only event received (correct behaviour) image

Data only: ✅

image

Background

Background = App is not visible, but still running in background (can see it on App Switcher still)

Notification+Data: ✅

Notification is shown to user and event received (correct behaviour). Event is only received if content-available is set, notification will display with or without content-available.

image

Notification only: ✅

Notification is shown to user and event received (correct behaviour). Event is only received if content-available is set, notification will display with or without content-available.

image

Data only: ✅

Event is received (correct behaviour). Event is only received if content-available is set.

image

App Closed / Swiped away

App Closed = App is not visible and has been dismissed from App Switcher (and no longer visible there either).

Notification+Data: 🔶

Notification is shown to user (correct) but event not received (incorrect if content-available is set).

Notification only: 🔶

Notification is shown to user (correct) but event not received (incorrect if content-available is set).

Data only: 🔶

Event is not received (incorrect). content-available is set

For these App Closed ones on iPhone 5s/iOS 12 - the system is receiving the messages but the system service responsible for launching the app in the background is refusing to launch the application (without a reason specified, it will normally give you a reason why it's refusing to launch, e.g. battery status or high CPU usage on the device):

image

Don't think there is anything we can do about this one - it does look like an iOS issue but good luck getting Apple to look at it 😅;

iPhone 7 - iOS 13.3.1

Foreground

Foreground = App is visible & open

Same behaviour as iPhone 5s above.

Background

Background = App is not visible, but still running in background (can see it on App Switcher still)

Same behaviour as iPhone 5s above.

App Closed / Swiped away

App Closed = App is not visible and has been dismissed from App Switcher (and no longer visible there either).

Notification+Data: ✅

Notification is shown to user (correct). Event is received if content-available is set (correct). App is launched silently with isHeadless react prop.

image

Notification only: ✅

Notification is shown to user (correct). Event is received if content-available is set (correct). App is launched silently with isHeadless react prop.

image

Data only: ✅

Event is received if content-available is set (correct). App is launched silently with isHeadless react prop.

image

I have a very weird behavior.
I have set contentAvailable to true server-side. The event is received by the handler in setBackgroundMessageHandler but no notification is shown
I have only tested background state for now.

Any hint on this ?

@dkahdwk
Copy link

dkahdwk commented Jul 25, 2023

@AlixH same issue...

@josurene
Copy link

any update?

@tigerjiang
Copy link

Why did you close these issues without solving them?

@kulak91
Copy link

kulak91 commented Apr 2, 2024

For someone who is trying to test it via postman instead of contentAvailable: true i added:

"apns": {
    "payload": {
      "aps": {
        "content-available": 1
      }
    }
  },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform: ios plugin: messaging FCM only - ( messaging() ) - do not use for Notifications
Projects
None yet
Development

No branches or pull requests