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.
The error I get is:
NativeFirebaseError: [messaging/unregistered] You must be registered for remote notifications before calling get token, see messaging().registerForRemoteNotifications() or requestPermission().
Env Info:
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 => 16.12.0 react-native: 0.61.5 => 0.61.5 npmGlobalPackages: create-react-native-app: 2.0.2 react-native-cli: 2.0.1 react-native-debugger-open: 0.3.24
My 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 = () => false;const getInitialAuthenticating = () => false;const getInitialProducts = () => [];const getInitialSelectedProduct = () => null;const getInitialCurrentUserId = () => 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<AuthenticationResponse>('authentication/token', params.toString(), undefined,'3.0', ); } if (ssoToken) { params.append('ssoToken', ssoToken); } return await Api.post<AuthenticationResponse>('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<boolean> { 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 > 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 && 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 && 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 => 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<ProductsResponse>('products'); const selectedProduct = products.find(product => 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; }}
I have dug around online but can't seem to find anything at all similar, does anyone have any ideas what I can try?