React-native-firebase: APNS token is always null

Created on 11 Dec 2019  路  11Comments  路  Source: invertase/react-native-firebase

Issue

My apns token is always null (on device) and as a result I never receive notification while my app is in the background on iOS.

I'm migrating from react-native-fcm. setBadge works, getting an FCM token works, onMessage works, and everything works on Android.

I've tried every combination of registering, configuring, etc, based off of all of the other issues I've seen related to this. The capabilities are on, and I tried turning them off and on again as well. These issues do carry over to my new repo made for testing this issue.

What I'm experiencing instead is a null apns token. I believe that's the main reason I'm not receiving these notifications. I am registering first, then trying to get the token second, as I've seen in other people's issues.

When I try using postman to post to https://fcm.googleapis.com/fcm/send I get back a successful response. My project is configured on Firebase with an APNs Auth Key.

Yes, "FirebaseAppDelegateProxyEnabled" is not set to "NO" in my Info.plist
Yes, I'm not trying in the simulator.
Yes, the APNS keys appear active on Apple's developer site.
Yes, I am very up to date on all of my libraries.
Yes, I have tried react-native clean-project.
Yes, I am prompted if I want to receive notifications.
Yes, I accept it.
Yes, everything looks good from notification settings.


Project Files

https://github.com/theminery-hr4/firebasetest

I've excluded my GoogleService-Info.plist from this repo, but it exists during my testing.

Key files are Firebase.js, AppDelegate.m. Pretty much everything else is default react native.

AppDelegate.m:

@import Firebase;
#import "RNFirebaseNotifications.h"
#import "RNFirebaseMessaging.h"

#import "AppDelegate.h"

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

#if RCT_DEV
#import <React/RCTDevLoadingView.h>
#endif

@implementation AppDelegate

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

  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];

#if RCT_DEV
  [bridge moduleForClass:[RCTDevLoadingView class]];
#endif

  RCTRootView *rootView = [[RCTRootView alloc]  initWithBridge:bridge
                                                moduleName:@"FirebaseTest"
                                                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];

  return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

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

Firebase.js:

import React, { Component } from 'react'
import { SafeAreaView, Text, Alert, AppState } from 'react-native'
import firebase from 'react-native-firebase'

export default class Firebase extends Component {
  checkPermission = async () => {
    let enabled = false

    try {
      await firebase.messaging().requestPermission()
      enabled = await firebase.messaging().hasPermission()
      enabled && this.getFcmToken()
    } catch(error) {
      this.showAlert('checkPermission', 'checkPermission error')
    }
  }

  getFcmToken = async () => {
    const fcmToken = await firebase.messaging().getToken()
    if(fcmToken) {
    //this.showAlert('getFcmToken', 'fcmToken '+fcmToken)

      firebase.messaging().ios.registerForRemoteNotifications().then(() => {
        firebase.messaging().ios.getAPNSToken().then(apns => {
          this.showAlert('getFcmToken', 'apns: '+apns)
        }).catch((e) => {
          this.showAlert('getFcmToken', 'apns error')
        })
      })
    } else {
      this.showAlert('getFcmToken', 'fcm token is falsey')
    }
  }

  handleNotification = (notification) => {
    if(!notification) {
        return
    }

    if(notification.notification) {
        notification = notification.notification
    }

    const data = notification.data || notification
    const { type } = data

    if(!type) {
      return
    }

    this.showAlert('handleNotification', 'type: '+type)
  }

  componentDidMount() {
    this.showAlert('componentDidMount', 'didMount')

    this.checkPermission()

    firebase.notifications().getInitialNotification().then(this.handleNotification)
    firebase.notifications().onNotificationOpened(this.handleNotification)
    firebase.notifications().onNotification(this.handleNotification)
    firebase.messaging().onMessage(this.handleNotification)

    AppState.addEventListener('change', (appState) => {
      appState === 'active' && this.checkPermission()
    })
  }

  showAlert = (title, message) => {
    Alert.alert(
      title,
      message,
      [
        {text: 'OK', onPress: () => {}},
      ],
      {cancelable: false},
    );
  }

  render() {
    return (
      <SafeAreaView style={{flex: 1}}>
        <Text style={{flex: 1}}>Firebase Test</Text>
      </SafeAreaView>
    )
  }
}

ios/Podfile:

platform :ios, '9.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

target 'FirebaseTest' do
  # Pods for FirebaseTest
  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 'Firebase/Core'
  pod 'Firebase/Messaging'

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

  use_native_modules!
end

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

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

end

Environment

macOS 10.15.1
Xcode 11.2.1
Node 10.17.0
Yarn 1.19.1
React Native 0.61.5
React 16.9.0
React Native Firebase 5.6.0
Firebase Core 6.13.0
iPhone 5 running iOS 10.3.3

Most helpful comment

Apologies for jumping on this closed ticket, but I'm having this issue on my devices. I have two iOS test devices I'm using. Yesterday, my primary device was working perfectly. It would give me the APNS token and notifications were appearing. Today, it's not giving me the token and notifications have stopped working on that device.

The _exact_ same code is running on my second test device and is working perfectly, as expected.

Why would it suddenly stop working on one device overnight?

If anyone out there can help, I'm running out of hair to pull out!


Update: after trying every trick under the sun that's been suggested, I finally gave up and followed the age-old IT support desk advice. I turned it off and turned it back on again.

Now it's working.

Slightly nervous that this is what fixed it, but will monitor if it happens again more closely.

All 11 comments

Interesting thread here with suggested workarounds: https://github.com/invertase/react-native-firebase/issues/2657#issuecomment-549181244 also a workaround mentioned is to do a wait for a couple seconds before fetching token to handle something inherently async/network-related about token generation

Despite having no luck on my device, I decided to push my latest code to TestFlight and it works for my coworker, so I think my issue is just device specific.

Thank you for the link. I hadn't seen this one, and while I think it's more specific to the version 6 plugin, it gave me some more things to try, none of which were able to help with my problem though.

For anyone that may be having the same issue. I went through a million fixes and realize finally that I did not have the aps-entitlements on for debug mode.

image

The Push Notifications were allowed in Release and not in Debug.

@theminerymike How did you fix it? I have a same issue. didRegisterForRemoteNotifications not called even call registerForRemoteNotifications. So cannot get APNS token and it cause remote notificatoin not work. I am testing in 6.4.0-rc4

It works after using cellular with usim. I checked https://support.apple.com/en-us/HT203609.

@JeffGuKang I also faced the same issue . After I switched to wifi connection it works

v6.7.1 Still get null when called getAPNSToken

I am experiencing this issue.

Me as well, v6.4.0 still get null on getAPNSToken.
On production build it works the first time. If you close the app however, and open it again, apns is null

  • registerForRemoteNotifications is not works on debug + Wi-Fi environment sometimes.
  • Using cellular data instead of WiFi can be the solution.
  • But production mostly works well.

I think it is a issue related to iOS. not react-native-firebase/messaging

We can check the codes through break point on XCode.

RNFBMessagingModule.m

RCT_EXPORT_METHOD(registerForRemoteNotifications:
  (RCTPromiseResolveBlock) resolve
    : (RCTPromiseRejectBlock) reject
) {
  #if TARGET_IPHONE_SIMULATOR
  resolve(@([RCTConvert BOOL:@(YES)]));
  return;
  #endif
  if (@available(iOS 10.0, *)) {
    if ([UIApplication sharedApplication].isRegisteredForRemoteNotifications == YES) {
      resolve(@([RCTConvert BOOL:@(YES)]));
    } else {
      [[RNFBMessagingAppDelegate sharedInstance] setPromiseResolve:resolve andPromiseReject:reject];
    }

    // Apple docs recommend that registerForRemoteNotifications is always called on app start regardless of current status
    dispatch_async(dispatch_get_main_queue(), ^{
      [[UIApplication sharedApplication] registerForRemoteNotifications]; // THIS
    });
  } else {
    [RNFBSharedUtils rejectPromiseWithUserInfo:reject userInfo:[@{
        @"code": @"unsupported-platform-version",
        @"message": @"registerDeviceForRemoteMessages call failed; minimum supported version requirement not met (iOS 10)."} mutableCopy]];
  }
}

RNFBMessaging+AppDelegata.m
Sometimes this code is never called.
And this makes APNSToken null.

// called when `registerForRemoteNotifications` completes successfully
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
#ifdef DEBUG
  [[FIRMessaging messaging] setAPNSToken:deviceToken type:FIRMessagingAPNSTokenTypeSandbox];
#else
  [[FIRMessaging messaging] setAPNSToken:deviceToken type:FIRMessagingAPNSTokenTypeProd];
#endif

  if (_registerPromiseResolver != nil) {
    _registerPromiseResolver(@([RCTConvert BOOL:@([UIApplication sharedApplication].isRegisteredForRemoteNotifications)]));
    _registerPromiseResolver = nil;
    _registerPromiseRejecter = nil;
  }
}

Apologies for jumping on this closed ticket, but I'm having this issue on my devices. I have two iOS test devices I'm using. Yesterday, my primary device was working perfectly. It would give me the APNS token and notifications were appearing. Today, it's not giving me the token and notifications have stopped working on that device.

The _exact_ same code is running on my second test device and is working perfectly, as expected.

Why would it suddenly stop working on one device overnight?

If anyone out there can help, I'm running out of hair to pull out!


Update: after trying every trick under the sun that's been suggested, I finally gave up and followed the age-old IT support desk advice. I turned it off and turned it back on again.

Now it's working.

Slightly nervous that this is what fixed it, but will monitor if it happens again more closely.

Was this page helpful?
0 / 5 - 0 ratings