ewizard
ewizard

Reputation: 2872

React Native / Firebase Messaging - messages/notifications are never sent

I am trying to get push notifications / firebase messaging to work with react native - I have gotten as far as checking / requesting permission, and I implemented onMessage, but I don't get any of my test messages (sent from the firebase developer console online, in the cloud messaging section). One thing that is odd is when I check the status of a completed message, it says no messages were sent (0 sent), so I don't even know if my app is getting the chance to receive a test message. Here is my code:

HomeScreen.js (the default route of the root navigator)

export default class HomeScreen extends React.Component {

  ....

  componentDidMount() {

    firebase.messaging()
      .hasPermission()
      .then(enabled => {
        if (!enabled) {
          this._getPermission();
        }

        firebase.messaging().getToken()
          .then(fcmToken => {
            if (fcmToken) {
              // user has a device token
            } else {
              alert("User doesn't have a token yet");
            } 
          }).catch((error) => {
            alert(error);
          });

        firebase.messaging().subscribeToTopic('all').catch((error) => {alert(error)});

        this.onTokenRefreshListener = firebase.messaging().onTokenRefresh(fcmToken => {
            // Process your token as required

        });

        this.messageListener = firebase.messaging().onMessage((message: RemoteMessage) => {
            // Process your message as required
            alert(message);
        });

      }).catch((error) => {alert(error)});
  }

  _getPermission = () => {
    firebase.messaging()
      .requestPermission()
      .catch(error => {
        // User has rejected permissions
        this._getPermission();
      });
  };

  ....

  componentWillUnmount() {
    this.onTokenRefreshListener();
    this.messageListener();
    firebase.messaging().unsubscribeFromTopic('all');
  }

  ....

AppDelegate.h

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

#import <UIKit/UIKit.h>
@import UserNotifications;

@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>

@property (nonatomic, strong) UIWindow *window;

@end

AppDelegate.m

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * 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/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "RNFirebaseNotifications.h"
#import "RNFirebaseMessaging.h"
#import <Firebase.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [FIRApp configure];
  [RNFirebaseNotifications configure];

  NSURL *jsCodeLocation;

  for (NSString* family in [UIFont familyNames])
  {
    NSLog(@"%@", family);
    for (NSString* name in [UIFont fontNamesForFamilyName: family])
    {
      NSLog(@" %@", name);
    }
  }

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

  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"snagit"
                                               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];
  [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];

  return YES;
}

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
  [[RNFirebaseNotifications instance] didReceiveLocalNotification:notification];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
  [[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
  [[RNFirebaseMessaging instance] didRegisterUserNotificationSettings:notificationSettings];
}

@end

My BUNDLE_ID's all appear to be correct. Why aren't the messages being sent in the first place and/or, why am I not receiving them?

UPDATE

Would trying FCM help? https://github.com/evollu/react-native-fcm

UPDATE

My request was bad, I got a curl try to work with:

curl -i -H 'Content-type: application/json' -H 'Authorization: key=server-key' -XPOST https://fcm.googleapis.com/fcm/send -d '{"to": "/topics/all","data": {"message": "This is a Firebase Cloud Messaging Topic Message!"}}'

I received:

HTTP/2 200 
content-type: application/json; charset=UTF-8
date: Tue, 18 Sep 2018 21:38:21 GMT
expires: Tue, 18 Sep 2018 21:38:21 GMT
cache-control: private, max-age=0
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
server: GSE
alt-svc: quic=":443"; ma=2592000; v="44,43,39,35"
accept-ranges: none
vary: Accept-Encoding

{"message_id":5323681878653027379}

So why doesn't it work coming from the firebase web console? Could this be an issue that needs to be resolved by firebase?

UPDATE

To further test whether or not this is on the firebase side of things I wrote a cloud function that should send a notification when a certain document is updated/created/deleted:

exports.sendMessageNotification = functions.firestore().document('conversations/{conversationID}/messages/{messageID}').onWrite((change, context) => {

        // Get an object representing the document
        // e.g. {'name': 'Marie', 'age': 66}
        const newValue = change.after.data();

        // ...or the previous value before this update
        const previousValue = change.before.data();

        // access a particular field as you would any JS property
        //const name = newValue.name;

        var topic = 'all';
        var payload = {
          notification: {
            title: "You got a new Message",
            body: newValue.notification.body,
          }
        };

        admin.messaging().sendToTopic(topic, payload)
            .then(function(response) {
              console.log("Successfully sent message:", response);
            })
            .catch(function(error) {
              console.log("Error sending message:", error);
            });
      });

Here is my code which successfully writes an object to the above firestore location:

....

constructor() {
    super();

    this.onTokenRefreshListener = firebase.messaging().onTokenRefresh(fcmToken => {
        // Process your token as required

    });

    this.messageListener = firebase.messaging().onMessage((message: RemoteMessage) => {
        // Process your message as required
        alert(message);
    });
    //this.ref = firebase.firestore().collection('items');
    //this.authSubscription = null;

}

....

componentDidMount() {

    firebase.messaging().getToken()
          .then(fcmToken => {
            if (fcmToken) {
              console.log(fcmToken);
              // Add a new document with a generated id.
              const addMessage = firebase.firestore().collection('conversations').doc('1234567').collection('messages').doc('1234567');

              data = {
                  notification: {
                    title: "You got a new Message",
                    body: "You got a new message",
                  }
              }
              // Set the 'capital' field of the city
              const updateMessage = addMessage.update(data).catch((error) => {
                alert(error);
                addMessage.set(data).catch((error) => {
                  alert(error);
                });
              });
            } else {
              alert("User doesn't have a token yet");
            } 

          }).catch((error) => {
            alert(error);
          });

    ....

}

For output I see the console.log(fcmToken) message. When I check the firebase functions log, I see Successfully sent message: { messageId: 6994722519047563000 }. When I check firestore, the document was created (or updated) correctly and it is in the correct place to be noticed (and it is on the firebase side according to the firebase function logs) - but I still never receive an actual notification on my iPhone.

Why am I not receiving the message if it is being sent?

UPDATE

I am now receiving notifications from the logic I created with firebase functions, the firebase web console just seems like it isn't working - the notifications still never get sent.

Upvotes: 0

Views: 3919

Answers (1)

Jeff Gu Kang
Jeff Gu Kang

Reputation: 4889

Solution

First of all, you need to get push notification in your device (not simulators). I recommend to test with iOS and Android devices from firebase web console first. This process is not required codes on your delegate files handling push notifications except checking permission.

Anyway, suppose you do not have any android device and it is not working on your iOS device,

  1. check bundle ids and GoogleService-Info.plist in firebase and XCode.
  2. check your target capabilities on XCode. Push Notifications and Background Mode enter image description here

  3. Check app's permission of notification on iOS's setting

Why?

I am not sure how you set your firebase and XCode, but problems of push notifications from firebase web console are related in permissions, XCode setting and other settings normally.

In my case, typos of the bundle id in firebase settings was the problem.

If you can, you would test on Android also.

Upvotes: 1

Related Questions