React-native-firebase: getInitialNotification not getting called when sending data message with app closed

Created on 1 Jul 2018  路  2Comments  路  Source: invertase/react-native-firebase

Issue

I have setup this package as per the instructions in the documentation for both android and ios. I am sending data messages to my app through Postman.

Here is the body for the postman request for sample data message being sent:

{
  "message": {
    "topic": "testing",
    "data": {
      "test-data-key": "test-data-value",
      "title": "Data Title",
      "body": "Data body",
      "click_action": "test.action.fcm",
      "display": "true"
    }
  }
}

For ios I am able to receive this message in the onMessage when the app is in foreground as well as in background. When I close my app and send some more messages I was expecting these messages to be delivered when the app is next opened and the getInitialNotification method will be called but it is not getting called.

Here is my AppContainer.js

class AppContainer extends Component {
componentDidMount() {
    createAndroidNotificationChannel()
    this.attachFirebaseListeners()
}

componentWillUnmount() {
    this.fcmMessageListener()
    this.notificationListener()
    this.notificationDisplayedListener()
    this.notificationOpenedListener()
    this.onTokenRefreshListener()
}

attachFirebaseListeners = async () => {
    try {
        const fcmToken = await firebase.messaging().getToken()
        if (fcmToken) {
            // user has a device token
            console.log('fcmToken', fcmToken)
        } else {
            // user doesn't have a device token yet
        }

        this.onTokenRefreshListener = firebase.messaging().onTokenRefresh(fcmToken => {
               // TODO: send the new token to server
         })

         // subscribe to a topic
        firebase.messaging().subscribeToTopic('testing')

            this.fcmMessageListener = firebase.messaging().onMessage(message => {
            console.log('onMessage:', message)
        })

        const notificationOpen = await firebase.notifications().getInitialNotification()
        if (notificationOpen) {
            console.log('getInitialNotification:', notificationOpen)
        }

        this.notificationListener = firebase.notifications().onNotification(notification => {
            console.log('onNotification:', notification)
        })

        this.notificationOpenedListener = firebase.notifications().onNotificationOpened(notificationOpen => {
            console.log('onNotificationOpened:', notificationOpen)
        })

        this.notificationDisplayedListener = firebase.notifications().onNotificationDisplayed(notification => {
            console.log('onNotificationDisplayed:', notification)
        })
    } catch (error) {
        console.log(error)
    }
}

render() {
    const signedIn = this.props.userSession && this.props.userSession.token && this.props.subdomainConfig.baseURL ? true : false
    const Layout = rootNavigator(signedIn)
         return <Layout />
    }
}

const mapDispatchToProps = dispatch => bindActionCreators(ActionCreators, dispatch)
const mapStateToProps = ({ userSession, subdomainConfig }) => ({ userSession, subdomainConfig})
export default connect(mapStateToProps,mapDispatchToProps)(AppContainer)

Here is my AppDelegate.m

#import "RNFirebaseNotifications.h"
#import "RNFirebaseMessaging.h"

#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

#import <BugsnagReactNative/BugsnagReactNative.h>

@import Firebase;
@import UserNotifications;

// Implement UNUserNotificationCenterDelegate to receive display notification via APNS for devices
// running iOS 10 and above.
@interface AppDelegate () <UNUserNotificationCenterDelegate>
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // [START configure_bugsnag_react_native]
  [BugsnagReactNative start];
  // [END configure_bugsnag_react_native]

  NSURL *jsCodeLocation;

  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];

  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"syooktnt"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];
  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];

  // [START configure_firebase]
  [FIRApp configure];
  [RNFirebaseNotifications configure];
  // [END configure_firebase]

  //  added
  [FIRMessaging messaging].shouldEstablishDirectChannel = YES;

  // [START set_messaging_delegate]
  [FIRMessaging messaging].delegate = self;
  // [END set_messaging_delegate]

  // Register for remote notifications. This shows a permission dialog on first run, to
  // show the dialog at a more appropriate time move this registration accordingly.
  // [START register_for_notifications]
  if ([UNUserNotificationCenter class] != nil) {
    // iOS 10 or later
    // For iOS 10 display notification (sent via APNS)
    [UNUserNotificationCenter currentNotificationCenter].delegate = self;
    UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
    [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) {
       // ...
     }];
  } else {
    // iOS 10 notifications aren't available; fall back to iOS 8-9 notifications.
    UIUserNotificationType allNotificationTypes = (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
    [application registerUserNotificationSettings:settings];
  }

  [application registerForRemoteNotifications];
  // [END register_for_notifications]

  return YES;
}

// react native firebase methods from documentation
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
  [[RNFirebaseMessaging instance] didRegisterUserNotificationSettings:notificationSettings];
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
  [[RNFirebaseNotifications instance] didReceiveLocalNotification:notification];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
  NSLog(@"info %@", userInfo); // added
  [[FIRMessaging messaging] appDidReceiveMessage:userInfo]; // added
  [[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  NSLog(@"Remote notification device token: %@", deviceToken);
}

- (void) application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  NSLog(@"PUSH ERROR: %@", error);
}

// *************************** not sure if these are needed ***********************************
// [START receive_message]
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
  [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
  [[RNFirebaseMessaging instance] didReceiveRemoteNotification:userInfo];
}
//// [END receive_message]

@end

For android I am able to handle the background message using the HeadlessJS background handler as described in the documentation (app in background or closed).

Can someone tell me if there is something wrong here and why is getInitialNotification not getting called.

Environment

  1. Application Target Platform: iOS
  2. Development Operating System: macOS High Seirra
  3. Build Tools: XCode 9.4
  4. React Native version: 0.54.2
  5. React Native Firebase Version: 4.2.0
  6. Firebase Module: Messaging and Notifications
  7. Are you using typescript? No
Notifications iOS Messaging

Most helpful comment

sending content_available: true is throwing an error.

this was the payload sent

{ 
    message:  { 
        topic: 'testing',
        content_available: true,
        data:  { 
            title: 'Data Title',
            body: 'Data body',
            display: 'true',
            click_action: 'testing.action.fcm',
            dataKey: 'dataValue' 
        }
     }
 }

response from googleapis
```{
"error": {
"code": 400,
"message": "Invalid JSON payload received. Unknown name \"content_available\" at 'message': Cannot find field.",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "message",
"description": "Invalid JSON payload received. Unknown name \"content_available\" at 'message': Cannot find field."
}
]
}
]
}
}

modified the message like this and it works:

{
message: {
topic: 'testing',
data: {
title: 'Data Title',
body: 'Data body',
display: 'true',
click_action: 'testing.action.fcm',
dataKey: 'dataValue'
},
apns: {
payload: {
aps: {
'content-available': 1
}
}
}
}
}
```

All 2 comments

@amanthegreatone These are data-only messages so they will never get passed to the notifications module so won't trigger getInitialNotification. You should find that messages you send whilst the app is in the background or closed will trigger messaging().onMessage the next time the app is in the foreground.

If you wish to receive these whilst the app is in the background or closed, then you need to set content_available to true (https://firebase.google.com/docs/cloud-messaging/http-server-ref).

Just to be aware, there is an outstanding issue that needs to be completed to provider more advanced configurability of this behaviour: https://github.com/invertase/react-native-firebase/issues/971

sending content_available: true is throwing an error.

this was the payload sent

{ 
    message:  { 
        topic: 'testing',
        content_available: true,
        data:  { 
            title: 'Data Title',
            body: 'Data body',
            display: 'true',
            click_action: 'testing.action.fcm',
            dataKey: 'dataValue' 
        }
     }
 }

response from googleapis
```{
"error": {
"code": 400,
"message": "Invalid JSON payload received. Unknown name \"content_available\" at 'message': Cannot find field.",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "message",
"description": "Invalid JSON payload received. Unknown name \"content_available\" at 'message': Cannot find field."
}
]
}
]
}
}

modified the message like this and it works:

{
message: {
topic: 'testing',
data: {
title: 'Data Title',
body: 'Data body',
display: 'true',
click_action: 'testing.action.fcm',
dataKey: 'dataValue'
},
apns: {
payload: {
aps: {
'content-available': 1
}
}
}
}
}
```

Was this page helpful?
0 / 5 - 0 ratings

Related issues

joecaraccio picture joecaraccio  路  3Comments

mahyarr picture mahyarr  路  3Comments

ODelibalta picture ODelibalta  路  3Comments

n-scope picture n-scope  路  3Comments

csumrell picture csumrell  路  3Comments