react-native-firebase icon indicating copy to clipboard operation
react-native-firebase copied to clipboard

[šŸ›] The operation couldnā€™t be completed. No APNS token specified before fetching FCM Token

Open k2xl opened this issue 2 years ago ā€¢ 111 comments

Issue

Trying to get token from user.

import messaging from '@react-native-firebase/messaging';
import { registerRootComponent } from 'expo';
import React, { useEffect } from 'react';
import {
  Text
} from 'react-native';

async function onAppBootstrap() {
  // Register the device with FCM
  console.log('A');
  await messaging().registerDeviceForRemoteMessages();
  console.log('B');
  // Get the token
  const token = await messaging().getToken();

  // Save the token
  console.log('TOKEN ' + token);
}

function App() {
  useEffect(() => {
    onAppBootstrap();
  }, []);

  return (
    <Text>Hi</Text>
  );
}

console.log('Registering root component');
registerRootComponent(App);
export default App;

~~When running this on iOS simulator, I get A on the console but it never reaches B. On further debugging just calling await messaging() seems to do enough to hang.~~

I see now after adding initializeApp() with credentials from firebase the following error

The operation couldnā€™t be completed. No APNS token specified before fetching FCM Token

Project Files

Javascript

Click To Expand

package.json:



"@react-native-firebase/app": "^17.0.0",
    "@react-native-firebase/messaging": "^17.0.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:
# 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

System: OS: macOS 12.5 CPU: (10) arm64 Apple M1 Pro Memory: 227.88 MB / 16.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 19.5.0 - /opt/homebrew/bin/node Yarn: Not Found npm: 9.3.1 - /opt/homebrew/bin/npm Watchman: Not Found Managers: CocoaPods: 1.11.3 - /opt/homebrew/bin/pod SDKs: iOS SDK: Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1 Android SDK: Not Found IDEs: Android Studio: 2022.1 AI-221.6008.13.2211.9477386 Xcode: 14.2/14C18 - /usr/bin/xcodebuild Languages: Java: 17.0.6 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 18.1.0 => 18.1.0 react-native: 0.70.5 => 0.70.5 react-native-macos: Not Found npmGlobalPackages: react-native: Not Found

 OUTPUT GOES HERE
  • Platform that you're experiencing the issue on:
    • [ ] 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:
    • `"@react-native-firebase/app": "^17.0.0",
  • "@react-native-firebase/messaging": "^17.0.0",`
    
  • Firebase module(s) you're using that has the issue:
    • e.g. Instance ID
  • Are you using TypeScript?
    • Y

k2xl avatar Feb 07 '23 21:02 k2xl

After adding initializeApp() with credentials from new firebase app it stopped hanging. However, now encountering:

The operation couldnā€™t be completed. No APNS token specified before fetching FCM Token

So trying to debug this now

k2xl avatar Feb 07 '23 21:02 k2xl

with the latest firebase-ios-sdk (v10.4.0+) an APNS token is strictly required as a prerequisite to get an FCM token The SDKs try to handle this for you by swizzling in AppDelegate methods that register an APNS token if one comes, but if you disable swizzling, or you do not register for remote notifications prior to calling getToken, you'll never get one

  • do not disable swizzling
  • make sure you call registerForRemoteNotifications

mikehardy avatar Feb 07 '23 23:02 mikehardy

Hi @mikehardy thanks for the response. I'm very confused. Apologies as I'm still relatively new to react-native. Note that I'm also using Expo.

In my example above, I am calling registerForRemoteNotifications before calling getToken.

k2xl avatar Feb 07 '23 23:02 k2xl

I'm not sure why, but the FCM system does not have an APNS token set for your app before you request an FCM token. There can be a few reasons why, as mentioned above it could be that swizzling is disabled in your AppDelegate such that the FCM callback which would normally listen for / register the APNS token with FCM when it comes in is not hooked up. It could be that you do not have remote messaging set up as an entitlement for your app. It could be lots of things.

One thing that might be uncomfortable to hear but is nevertheless important: others have this working. The code works in the module. Why is that important but maybe uncomfortable? Because it implies (though no, it does not quite prove...) that the problem is specific to your app and your configuration. You should triple check everything with the assumption the problem is in your app and no one will be able to help you find it - you will likely find the problem yourself in your app upon further careful inspection.

There is still of course the possibility the problem is in this module, but no one else is experiencing it so I am operating on the assumption the problem is project-specific

mikehardy avatar Feb 08 '23 16:02 mikehardy

Thank you for your respectful response! Definitely appreciate this input.

I think part of the reason I raised this issue is that I did see some other threads for a few weeks ago related to this issue. So I thought just getting the minimal example to reproduce the issue could cause an issue - so in case anyone else encounters and has found a solution they may stumble upon this ticket.

The fact that this sounds like only affecting me indicates it is indeed a problem with my configuration - I guess the tough part I'll need to figure out is what is the issue with my configuration:).

Anyway best regards, and thanks again for the pointers

k2xl avatar Feb 08 '23 16:02 k2xl

The new strict requirement for an APNS token prior to an FCM one is bound to turn up issues like this so I will be very curious to hear what you turn up. Right now the entitlements idea is my best one for you but maybe it's something else? There was a lot of traffic about this recently because they added this requirement first on the backend without warning which exposed lots of people getting FCM tokens with no corresponding APNS token and broke their apps.

Of course those non-APNS FCM tokens are useless, but breaking the misconfigured apps unexpectedly was bad and generated all the traffic. They relaxed the backend change but left the SDK change in for firebase-ios-sdk 10.4.0 release so it is now only seen by folks as they upgrade, which is you now. It's a valid change (the APNS token should be required...) but forces everyone to find their corner cases where it fails now. And here we are...

Anyway, definitely report back if you find anything, and I hope you do + quickly. Cheers

mikehardy avatar Feb 08 '23 16:02 mikehardy

also running into this issue today. not sure right now why that is.

it's not a minimal example, but issue can be seen by cloning this repo: https://github.com/GaloyMoney/galoy-mobile

nicolasburtey avatar Feb 08 '23 21:02 nicolasburtey

@k2xl I had the same issue minutes before.

I solved it by checking in signing & capabilities. Inside "Background modes", I selected "Background check" and "Remote notifications". I hope this helps you.

farojos avatar Feb 09 '23 16:02 farojos

@k2xl I had the same issue minutes before.

I solved it by checking in signing & capabilities. Inside "Background modes", I selected "Background check" and "Remote notifications". I hope this helps you.

just tried that and had no effect on my end.

I realized I had not set use_frameworks! :linkage => :static in the Podfile even thought it was necessary from a recent update, but it doesn't seem to remove the error message.

nicolasburtey avatar Feb 09 '23 20:02 nicolasburtey

I have been digging into this problem the whole evening. In my case the problem was that in firebase.json property registerDeviceForRemoteMessages was set to false. This caused getAPNSToken to return null and also triggered this error in case getToken was called.

I don't remember why did I set registerDeviceForRemoteMessages to false earlier before. But this still looks like firebase bug. Because I did call registerDeviceForRemoteMessages in my JS code, but for some reason that did not perform the registration fully. One interesting behaviour that I noticed was that APNSToken was not not null only in the case when app was launched first time after install (with registerDeviceForRemoteMessages=false setup) .

tautvilas avatar Feb 09 '23 23:02 tautvilas

on my end, solving by doing a full re-install off the app. don't know how it got corrupted in the first place but anyway, no longer seen the error message.

nicolasburtey avatar Feb 10 '23 11:02 nicolasburtey

I fixed this by changing firebase.json

From

{
  "react-native": {
    "analytics_auto_collection_enabled": false,
    "messaging_auto_init_enabled": false,
    "messaging_ios_auto_register_for_remote_messages": false
  }
}

To

{
  "react-native": {
    "analytics_auto_collection_enabled": false,
    "messaging_auto_init_enabled": false,
    "messaging_ios_auto_register_for_remote_messages": true
  }
}

And deleted call

await messaging().registerDeviceForRemoteMessages()

kesha-antonov avatar Feb 13 '23 14:02 kesha-antonov

Thanks for the responses. I am on an expo managed app so didn't have a firebase.json file...

I tried adding a firebase.json to the root of the folder and removed the await messaging().registerDeviceForRemoteMessages() (since it was showing that it was unneeded).

However await messaging().getToken(); hangs... and I still get The operation couldnā€™t be completed. No APNS token specified before fetching FCM Token

k2xl avatar Feb 13 '23 19:02 k2xl

Thanks for the responses. I am on an expo managed app so didn't have a firebase.json file...

I tried adding a firebase.json to the root of the folder and removed the await messaging().registerDeviceForRemoteMessages() (since it was showing that it was unneeded).

However await messaging().getToken(); hangs... and I still get The operation couldnā€™t be completed. No APNS token specified before fetching FCM Token

Hey, i just stumbled upon this issue, got a solution? According to the docs setAPNS needs to be called, just not sure how or where

Spxc avatar Feb 16 '23 16:02 Spxc

According to the docs setAPNS needs to be called,

I don't believe this statement is true? The docs should say (and I think they say?) that you must call setAPNS *if you have disabled method swizzling or for some other reason have disabled the automatic firebase APNS token handling on remote message registration

In almost all cases, certainly the "default integration" cases, if you call the API to register for remote notifications, and have @react-native-firebase/messaging installed in the default manner with correct entitlements on your iOS project to allow them, the SDK will request an APNS token from Apple and set it into the SDK for you fully automated.

You only want or need to use setAPNS token if you really want to manage APNS tokens yourself (for automated testing on non-Apple-Silicon emulators, perhaps, or if you have some brownfield app where you manage APNS tokens yourself, etc)

mikehardy avatar Feb 16 '23 17:02 mikehardy

We appear to have an issue in the reference API docs where line breaks in our method docs stop the rest of the doc from rendering but the whole doc is as such:

https://github.com/invertase/react-native-firebase/blob/2e51817c937247ffe51fb6234c164744c2a71693/packages/messaging/lib/index.d.ts#L888-L906

I'll see what I can about getting the rest of the info to actually show up on the reference site as it should.

mikehardy avatar Feb 16 '23 17:02 mikehardy

According to the docs setAPNS needs to be called,

I don't believe this statement is true? The docs should say (and I think they say?) that you must call setAPNS *if you have disabled method swizzling or for some other reason have disabled the automatic firebase APNS token handling on remote message registration

In almost all cases, certainly the "default integration" cases, if you call the API to register for remote notifications, and have @react-native-firebase/messaging installed in the default manner with correct entitlements on your iOS project to allow them, the SDK will request an APNS token from Apple and set it into the SDK for you fully automated.

You only want or need to use setAPNS token if you really want to manage APNS tokens yourself (for automated testing on non-Apple-Silicon emulators, perhaps, or if you have some brownfield app where you manage APNS tokens yourself, etc)

Hi Mike, Thanks for the reply!

According to the changelog there were some breaking changes:

[17.0.0](2023-02-02)
āš  BREAKING CHANGES
app, ios: You must have an APNS token before calling getToken to get an FCM token on iOS. Previously it was not required. See documentation for setAPNSToken if you are using getToken in testing or have disabled FCM Swizzling, and use setAPNSToken to set a token before using getToken

EDIT: Saw your reply, i'll have a read through. The thing is, nothing changed in our code, we just updated the package, then it started throwing the APNS error. Been working flawlessly prior to this :)

How i noticed it; the entire app hung on the splash screen (both simulator and device - iOS). Moving the getToken() function to after the app checks for permissions, fixed the freeze. However it's throwing the error: Failed to fetch FCM: Error: [messaging/unknown] The operation couldnā€™t be completed. No APNS token specified before fetching FCM Token

Spxc avatar Feb 16 '23 17:02 Spxc

Yes, as you quote, I quote the important bit:

See documentation for setAPNSToken if you are using getToken in testing or have disabled FCM Swizzling

That is

if you are using getToken in testing or have disabled FCM Swizzling

Almost no one does either. In the testing case, you can inject a "correctly formatted but useless" APNS token just to exercise FCM APIs, but who would do that except someone that implements FCM APIs (that is: us here, as maintainers...). So it's possible but I expect no one else to do it.

And disabling swizzling is something I'd consider "advanced" on the iOS side. If you're disabling swizzling you are effectively on your own as you have moved past the default + works implementation and are stating clearly (by disabling swizzling): "we know what we're doing on iOS, don't worry about us"

mikehardy avatar Feb 16 '23 17:02 mikehardy

EDIT: Saw your reply, i'll have a read through. The thing is, nothing changed in our code, we just updated the package, then it started throwing the APNS error. Been working flawlessly prior to this :)

--> https://github.com/invertase/react-native-firebase/issues/6893#issuecomment-1422890413

mikehardy avatar Feb 16 '23 17:02 mikehardy

Yes, as you quote, I quote the important bit:

See documentation for setAPNSToken if you are using getToken in testing or have disabled FCM Swizzling

That is

if you are using getToken in testing or have disabled FCM Swizzling

Almost no one does either. In the testing case, you can inject a "correctly formatted but useless" APNS token just to exercise FCM APIs, but who would do that except someone that implements FCM APIs (that is: us here, as maintainers...). So it's possible but I expect no one else to do it.

And disabling swizzling is something I'd consider "advanced" on the iOS side. If you're disabling swizzling you are effectively on your own as you have moved past the default + works implementation and are stating clearly (by disabling swizzling): "we know what we're doing on iOS, don't worry about us"

Yeah, but the thing is; this code have been running fine in a simulator upon until today when doing a package update, then the freeze, now the error. This also occurred on a real device

Spxc avatar Feb 16 '23 17:02 Spxc

when doing a package update

...across a breaking change boundary, which contains this note:

https://github.com/invertase/react-native-firebase/blob/main/CHANGELOG.md#1700-2023-02-02

app, ios: You must have an APNS token before calling getToken to get an FCM token on iOS. Previously it was not required. See documentation for setAPNSToken if you are using getToken in testing or have disabled FCM Swizzling, and use setAPNSToken to set a token before using getToken

It's a big deal, it must be handled.

Getting an APNS token is an asynchronous network-bound process that could fail, or may even be disabled by some configuration issue.

Previously these misconfigurations or order-of-operations issues were ignored and Firebase would gladly vend an FCM token that was useless as it had no corresponding APNS counterpart.

Now it is (correctly, but maybe painfully) saying "Nope, an FCM token in this context is actually without value, so we won't give you an FCM token without the APNS token behind it"

And we all have to adjust by making sure the APNS token is really there before asking for an FCM token. Might require checking network, re-trying, verifying you really register for remote notifications, you really have your iOS app entitlements correct, you have permission etc, but that's all justified and correct. Just a bit painful, maybe unexpected.

mikehardy avatar Feb 16 '23 17:02 mikehardy

Yeah, but how do we actually check for the token? That's what we are asking about. How can we adjust the code? We've followed the docs step by step, and it's this simple line: firebase.messaging().getToken()

Isn't that function supposed to check to see if the APNS are there?

Just want to reiterate: that all the certificates/keys etc are in order

Spxc avatar Feb 16 '23 17:02 Spxc

Isn't that function supposed to check to see if the APNS are there?

well...it does, but not in a pleasant way. It checks and throws an error if it's not there. Shouldn't be hanging you should be getting the error I think you report:

The operation couldnā€™t be completed. No APNS token specified before fetching FCM Token

So, perhaps you want to make sure you have permissions from the user, that you register for remote notifications, and that getAPNSToken returns a token (any token, value doesn't matter - except undefined is bad of course). Once those work (perhaps in a backoff retry loop with a final error to user saying some functionality won't work?) then you go for the FCM token

mikehardy avatar Feb 16 '23 17:02 mikehardy

So, perhaps you want to make sure you have permissions from the user, that you register for remote notifications, and that getAPNSToken returns a token (any token, value doesn't matter - except undefined is bad of course). Once those work (perhaps in a backoff retry loop with a final error to user saying some functionality won't work?) then you go for the FCM token

Awesome, yes, that's exactly what I ended up doing.

Good to know that it handles the error kinda weird. The hanging/freezing issue was fixed by moving the getToken() function after requesting permissions from the user.

Spxc avatar Feb 16 '23 18:02 Spxc

Got the same error after upgrade "@react-native-firebase/messaging": "^14.7.0" -> "@react-native-firebase/messaging": "^17.3.0" Only iOS issue, on Android seems everything is fine.

Signing & Capabilities -> Background Modes (Remote notifications, Background processing) enabled.

Before this upgrade everything was fine. Is there any solution for this issue?

I see this is a new issue but I think a lot of people will see this issue after upgrades. So any workaround, patch or instruction is really needed. Right now, I decided to stick with old version of module.

flashman2 avatar Feb 17 '23 20:02 flashman2

@flashman2 it appears based on your comment you have not read the rest of the comments. Explanations and solutions are detailed throughout, please read through.

mikehardy avatar Feb 18 '23 12:02 mikehardy

@mikehardy Thanks for your answer. I'm sorry if I missed something. But I really can't find a clear instruction on what to do when migrate to 17.x.x version from older versions. Even in this thread, I see multiple solutions like this: https://github.com/invertase/react-native-firebase/issues/6893#issuecomment-1427998691 or this: https://github.com/invertase/react-native-firebase/issues/6893#issuecomment-1421591979

None of them help to solve issue. I still get error message. Can you please point where and what I need to change to make it work again?

Below is my current code which works fine with version 14.7.0.

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

const App = () => {
  //Push Notifications

  const requestUserPermission = async () => {
    const authStatus = await messaging().requestPermission();
    const enabled =
      authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
      authStatus === messaging.AuthorizationStatus.PROVISIONAL;

    if (enabled) {
      console.log('Authorization status:', authStatus);
    }
  };
  useEffect(() => {
    if (Platform.OS === 'ios') {
      requestUserPermission();
    }
    messaging()
      .subscribeToTopic('main')
      .then(() => console.log('Subscribed to topic!'));

    const unsubscribe = messaging().onMessage(async (remoteMessage) => {
      await onDisplayLocalNotification(
        remoteMessage.notification.title,
        remoteMessage.notification.body,
      );
    });

    return unsubscribe;
  }, []);

  async function onDisplayLocalNotification(title, message) {
    // Create a channel
    const channelId = await notifee.createChannel({
      id: 'default',
      name: 'Default Channel',
    });

    // Display a notification
    await notifee.displayNotification({
      title: title,
      body: message,
      android: {
        channelId,
      },
    });
  }

  return (
    <GlobalStateContext.Provider value={preferences}>
      ...
    </GlobalStateContext.Provider>
  );
};

export default App;

flashman2 avatar Feb 18 '23 15:02 flashman2

I don't see an await for user permission I don't see a check for apns token and then check for FCM token ( with await) before subscription

mikehardy avatar Feb 18 '23 16:02 mikehardy

How do i do this I don't see a check for apns token and then check for FCM token ( with await) before subscription @mikehardy

iampato avatar Feb 28 '23 12:02 iampato

something like


// How to see if you have an APNS token
const apnsToken = await firebase.messaging().getAPNSToken();
if (apnsToken === undefined) {
    // we do not appear to have an APNS token.
    // possible misconfiguration, possibly user did not grant permission, possible network timeout, possibly non-APNS Simulator
    // if you *really* know you are in a dev environment on Simulator, maybe setAPNSToken to some string to continue
    // if this is a real environment then maybe try a few times with sleeps to see if it comes in?
}

// How to register
if (apnsToken !== undefined) {
  firebase.messaging().<some call here that requires a valid FCM token like getToken or subscribe or whatever>
}

Checking for an APNS token and using the token should be thought of as separate things with FCM usage depending on APNS, so do the APNS check work first and if it succeeds set some state that will trigger the effect of using it

This is all really dependent on a project's requirements so it will vary and I cannot suggest what your project will need in practice.

mikehardy avatar Feb 28 '23 13:02 mikehardy