title: How to resolve React Native Firebase Error (messaging().getToken()), related to react-native-device-info
body: <p>I am in the process of migrating react-native-device-info from v2 to v3 and I have a breaking change. Prior to updating the package, everything was working fine. The error appears on all emulators and real devices.</p>
  
  <p>The error I get is: </p>
  
  <pre><code>NativeFirebaseError: [messaging/unregistered] You must be registered for remote notifications before calling get token, see messaging().registerForRemoteNotifications() or requestPermission().
  </code></pre>
  
  <p>Env Info: </p>
  
  <pre><code>   System:
      OS: macOS 10.15.4
      CPU: (8) x64 Intel(R) Core(TM) i7-6920HQ CPU @ 2.90GHz
      Memory: 6.44 GB / 16.00 GB
      Shell: 5.7.1 - /bin/zsh
    Binaries:
      Node: 12.14.0 - ~/.nvm/versions/node/v12.14.0/bin/node
      Yarn: 1.22.4 - /usr/local/bin/yarn
      npm: 6.13.4 - ~/.nvm/versions/node/v12.14.0/bin/npm
    SDKs:
      iOS SDK:
        Platforms: iOS 13.4, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
      Android SDK:
        API Levels: 28, 29
        Build Tools: 28.0.3, 29.0.3
        System Images: android-28 | Google Play Intel x86 Atom
    IDEs:
      Android Studio: 3.6 AI-192.7142.36.36.6241897
      Xcode: 11.4.1/11E503a - /usr/bin/xcodebuild
    npmPackages:
      react: 16.12.0 =&gt; 16.12.0 
      react-native: 0.61.5 =&gt; 0.61.5 
    npmGlobalPackages:
      create-react-native-app: 2.0.2
      react-native-cli: 2.0.1
      react-native-debugger-open: 0.3.24
  </code></pre>
  
  <p>My code: </p>
  
  <pre><code>export interface LoginParams {
      token?: string;
      useProduct?: string;
      useUser?: string;
      ssoToken?: string;
  }
  
  // TODO: Should be switched out with tv-ui-common once the whole app starts using Product model.
  interface AuthenticationResponse {
      noCacheToken: string;
      products: ProductData[];
      currentUserId: number;
  }
  interface ProductsResponse {
      currentProductCode: string;
      products: ProductData[];
  }
  
  const getInitialIsLoggedIn = () =&gt; false;
  const getInitialAuthenticating = () =&gt; false;
  const getInitialProducts = () =&gt; [];
  const getInitialSelectedProduct = () =&gt; null;
  const getInitialCurrentUserId = () =&gt; null;
  
  export default class AuthenticationStore {
      private static async authenticate({ token, useProduct, useUser, ssoToken }: LoginParams) {
          const params = new URLSearchParams();
          params.append('ui', UI);
          params.append('uuid', DeviceInfo.getUniqueId());
          params.append('model', DeviceInfo.getSystemName());
          params.append('hwVersion', DeviceInfo.getModel());
          params.append('swVersion', DeviceInfo.getSystemVersion());
          params.append('uiVersion', getUiVersion());
          if (useProduct) {
              params.append('useProduct', useProduct);
          }
          if (useUser) {
              params.append('useUser', useUser);
          }
  
          try {
              const notificationToken = await messaging().getToken();
              params.append('pushToken', notificationToken);
              console.log(notificationToken, 'notificationToken');
          } catch (error) {
              // iPhone Simulator does not give a token
              console.log("error", error);
          }
  
          try {
              // If we have token, meaning user authenticated via TV pairing
              if (token) {
                  params.append('token', token);
                  return await Api.post&lt;AuthenticationResponse&gt;(
                      'authentication/token',
                      params.toString(),
                      undefined,
                      '3.0',
                  );
              }
              if (ssoToken) {
                  params.append('ssoToken', ssoToken);
              }
              return await Api.post&lt;AuthenticationResponse&gt;(
                  'authentication/sso',
                  params.toString(),
                  undefined,
                  '3.0',
              );
          } catch (error) {
              console.log('err', error);
              if (error.response.status === 423) {
                  throw new ProductNotAvailableError(error.response.data.products);
              } else {
                  throw error;
              }
          }
      }
  
      @observable public isLoggedIn = getInitialIsLoggedIn();
      @observable public authenticating = getInitialAuthenticating();
      @observable public products: ProductData[] = getInitialProducts();
      @observable public selectedProduct: ProductData | null = getInitialSelectedProduct();
      @observable public currentUserId: number | null = getInitialCurrentUserId();
  
      constructor() {
          this.registerPushNotificationToken = this.registerPushNotificationToken.bind(this);
          this.loadProducts = this.loadProducts.bind(this);
      }
  
      @action public reset() {
          this.isLoggedIn = getInitialIsLoggedIn();
          this.authenticating = getInitialAuthenticating();
          this.products = getInitialProducts();
          this.selectedProduct = getInitialSelectedProduct();
          this.currentUserId = getInitialCurrentUserId();
      }
  
      public async registerPushNotificationToken(token: string) {
          if (this.isLoggedIn) {
              await Api.post('push-token-update', { token }, undefined, '3.0');
          }
      }
  
      public async login(params: LoginParams = {}): Promise&lt;boolean&gt; {
          this.setAuthenticating(true);
  
          try {
              const response = await AuthenticationStore.authenticate(params);
              setNoCacheToken(response.data.noCacheToken);
  
              const products = response.data.products || [];
  
              this.setProducts(products);
              if (response.status === 202) {
                  if (products.length === 1) {
                      const [product] = products;
                      return this.login({ useProduct: product.code });
                  }
                  if (products.length &gt; 1) {
                      throw new ProductNotSelectedError();
                  }
              }
              this.setSelectedProduct(products[0]);
  
              this.setAuthenticating(false, true, response.data.currentUserId);
              analytics().setUserId(response.data.currentUserId.toString());
          } catch (error) {
              this.setAuthenticating(false, false);
  
              if (error.response &amp;&amp; error.response.status === 401) {
                  if (error.response.data.errorCode === 'E_UNAUTHORIZED') {
                      // Silently fail error if user was not authenticated while doing sso request.
                      // We do not need to handle that 'error'. It's common case for cookies
                      // to expire.
                      return false;
                  }
                  throw new NoProductsError();
              }
              if (
                  (error.response &amp;&amp; error.response.status === 400)
                  || error instanceof ProductNotSelectedError
              ) {
                  throw error;
              } else if (error instanceof ProductNotAvailableError) {
                  // Product is suspended or in debt and thus not usable
  
                  const selectedProduct = error.products.find(
                      product =&gt; product.code === params.useProduct,
                  );
                  this.setProducts(error.products, selectedProduct);
                  throw error;
              } else {
                  // Something went wrong with authentication on server side.
                  throw new Error(`Unexpected authentication error: ${error}`);
              }
          }
  
          return this.isLoggedIn;
      }
  
      public async loadProducts() {
          try {
              // Logged in version of fetching products
              const { data: { products, currentProductCode } } = await Api.get&lt;ProductsResponse&gt;('products');
              const selectedProduct = products.find(product =&gt; product.code === currentProductCode);
              this.setProducts(products, selectedProduct);
          } catch (error) {
              if (error.response.status === 401) {
                  // Logged out version of fetching products
                  try {
                      const response = await AuthenticationStore.authenticate({});
                      const products = response.data.products || [];
                      this.setProducts(products);
                  } catch (loginError) {
                      // TODO: Handle error
                  }
              }
              // TODO: Handle failed request on loading products
          }
      }
  
      @action public setAuthenticating(
          authenticating: boolean = false,
          isLoggedIn: boolean = this.isLoggedIn,
          currentUserId: number | null = this.currentUserId,
      ) {
          this.authenticating = authenticating;
          this.isLoggedIn = isLoggedIn;
          this.currentUserId = this.isLoggedIn ? currentUserId : null;
      }
  
      @action private setProducts(
          products: ProductData[],
          selectedProduct: ProductData | null = null,
      ) {
          this.products = products;
          this.setSelectedProduct(selectedProduct);
      }
  
      @action private setSelectedProduct(product: ProductData | null = null) {
          this.selectedProduct = product;
      }
  }
  </code></pre>
  
  <p>I have dug around online but can't seem to find anything at all similar, does anyone have any ideas what I can try? </p>