Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"method is deprecated and will be removed" Solution: migrate to modular style APIs. There is a guide #8282

Closed
nazacity opened this issue Feb 8, 2025 · 63 comments

Comments

@nazacity
Copy link

nazacity commented Feb 8, 2025

[Maintainer edit 👋 - We are resolving comments as people note things and we implement changes - but we really appreciate any feedback. If you convert to modular namespace and still see deprecation messages, or have other feedback, please leave a comment. Thanks]


Got Warning
This v8 method is deprecated and will be removed in the next major release as part of move to match Firebase Web modular v9 SDK API. Please use getApp() instead.

on both Android and IOS

Image
@umakantv

This comment has been minimized.

@furkananter

This comment has been minimized.

@sanjaykdotworld

This comment has been minimized.

@SamJbori

This comment has been minimized.

@retyui

This comment has been minimized.

@mikehardy mikehardy changed the title [🐛] Bug Report This v8 method is deprecated and will be removed in the next major release as part of move to match Firebase Web modular v9 SDK API. Please use getApp() instead "method is deprecated and will be removed in the next major release" Solution: you must migrate to modular firebase-js-sdk style APIs Feb 8, 2025
@mikehardy
Copy link
Collaborator

mikehardy commented Feb 8, 2025

Maintainer here 👋

This message will trigger for every API you use that is deprecated, so basically every single time you use any of the non-modular / chained APIs directly off one of the firebase modules - they are easy enough to search for in each file.

You will need to move to the new non-modular APIs.

I will really underline to everyone: This sounds painful. When I first looked into it in my projects I thought "oh no..."

The API move is purely mechanical though. It is really just changing syntax. It is not difficult, it just changes a lot of files.

The migration is not to be feared.

We just posted up a migration document but this isn't a bug or an issue or anything.
Google has deprecated the non-modular APIs in firebase-js-sdk and they are removing them.
We are obligated to conform to the firebase-js-sdk API set, so we must follow them.

The migration is straightforward thankfully - see here for how you migrate, or - once you accept that you know react-native-firebase v22 will drop all the APIs that are warning you - you can defer your maintenance as long as you like and disable the messages

https://rnfirebase.io/migrating-to-v22

(note, the feature of disabling the messages is present in react-native-firebase 21.7.3+)
(also note, the feature of enabling "strict mode" is present in react-native-firebase 21.10.1+)

Frequent Questions

Things I'm noting as I read comments here, we will add to the migration guide as we see people's concerns:

-" is it that critical?"

the APIs will be removed in react-native-firebase v22 so you will not be able to upgrade until you complete the migration. How critical is it for you to maintain a path to upgrade such that you maintain the ability to receive bugfixes, new ios/android system support, etc? Every project has a different timeline and answer for that

  • "I've seen some issues related to the migration":

Indeed there are still some typing issues at the moment, for typescript users. We are treating those as high priority bugs and fixing them as quickly as possible

  • Your thought here. I/we are listening. If you post a comment noting something specific you see about the migration, and have some constructive suggestion that would be great. We'll try to smooth the process out in response to any specific notes or constructive suggestions

Cheers

@mikehardy mikehardy pinned this issue Feb 8, 2025
@furkananter

This comment has been minimized.

@mikehardy

This comment has been minimized.

@omerkars78

This comment has been minimized.

@mikehardy

This comment has been minimized.

@furkananter

This comment has been minimized.

@mikehardy mikehardy changed the title "method is deprecated and will be removed in the next major release" Solution: you must migrate to modular firebase-js-sdk style APIs "method is deprecated and will be removed" Solution: migrate to modular style APIs. There is a guide Feb 8, 2025
@mikehardy

This comment has been minimized.

@mikehardy

This comment has been minimized.

@mikehardy

This comment has been minimized.

@SamJbori

This comment has been minimized.

@emokeOrdog

This comment has been minimized.

@mikehardy

This comment has been minimized.

@ryansobol

This comment has been minimized.

@mikehardy

This comment has been minimized.

@mikehardy
Copy link
Collaborator

@fobos531 I would just use getMessaging() (or more generally, any modular call you need) directly from the package exports every time

@KrisLau
Copy link

KrisLau commented Mar 4, 2025

@mikehardy are we supposed to use it like this:

import {getAuth} from '@react-native-firebase/auth';

const auth = getAuth();
const user = auth.currentUser;
auth.createUserWithEmailAndPassword(email, password);

await user.updateProfile({
  displayName: 'John Smith',
  photoURL: "https://example.com/jane-q-user/profile.jpg",
});

OR

import {createUserWithEmailAndPassword, getAuth, updateProfile} from '@react-native-firebase/auth';

const auth = getAuth();
const user = auth.currentUser;
createUserWithEmailAndPassword(auth, email, password);

await updateProfile(user, {
  displayName: 'John Smith',
  photoURL: "https://example.com/jane-q-user/profile.jpg",
});

I tried looking at the documentation but it doesn't seem to be updated yet. The migration documentation links firebase which suggests:

import { getAuth, updateProfile } from "firebase/auth";
const auth = getAuth();
updateProfile(auth.currentUser, {
  displayName: "Jane Q. User", photoURL: "https://example.com/jane-q-user/profile.jpg"
})

I'm confused as to whether there is a difference between using one over the other?


Also should I be calling const auth = getAuth(); in every function or just on the top of my provider file:

function AuthProvider({children}) {
  const auth = getAuth();

@mikehardy
Copy link
Collaborator

@KrisLau in general, you should follow all the guides for using the modular API that are available in the upstream firebase-js-sdk documentation: https://firebase.google.com/docs/auth/web/password-auth

When in doubt, assume the upstream modular documentation style should be followed and that our local documentation on rnfirebase.io has not caught up yet

It should work and when in doubt, assume that if using the modular API the way firebase.google.com shows does not work here, that we have a bug here.

The goal is always for react-native-firebase to be a drop-in / works-the-same replacement for firebase-js-sdk so that upstream docs are correct and we function the same

@KrisLau

This comment has been minimized.

@emokeOrdog

This comment has been minimized.

@KrisLau

This comment has been minimized.

@jeremyplt
Copy link

jeremyplt commented Mar 8, 2025

Having the same warning coming from AppCheck, but for some reason I can't get it working with the new syntax. I'm following this documentation: https://rnfirebase.io/app-check/usage

Firebase Version: 21.11.0

This is my current code raising the warning:

import appCheck from "@react-native-firebase/app-check";

const rnfbProvider = appCheck().newReactNativeFirebaseAppCheckProvider();
rnfbProvider.configure({
  // My Configuration
});

// initialize AppCheck with the modular approach
appCheck().initializeAppCheck({
  provider: rnfbProvider,
  isTokenAutoRefreshEnabled: true,
});

And this is what i'm implementing:

import { ReactNativeFirebaseAppCheckProvider, initializeAppCheck } from `@react-native-firebase/app-check`;

rnfbProvider = new ReactNativeFirebaseAppCheckProvider();
rnfbProvider.configure({
  // My Configuration
});

// initialize AppCheck with the modular approach
initializeAppCheck({
  provider: rnfbProvider,
  isTokenAutoRefreshEnabled: true,
});

But ReactNativeFirebaseAppCheckProvider isn't found in the module and is throwing this error:
Module '"@react-native-firebase/app-check"' has no exported member 'ReactNativeFirebaseAppCheckProvider'. Did you mean to use 'import ReactNativeFirebaseAppCheckProvider from "@react-native-firebase/app-check"' instead?ts(2614)

@Magikarppi

This comment has been minimized.

@omerts
Copy link

omerts commented Mar 19, 2025

there is no documentation on how to inititalize ReactNativeFirebaseAppCheckProvider. Even worse there is wrong documentation, which leads to the error in this issue.

@mikehardy
Copy link
Collaborator

@omerts this is the best example now - it is what I arrived it in my last namespace -> modular sweep:

before(async function () {
const { initializeAppCheck, ReactNativeFirebaseAppCheckProvider } = appCheckModular;
let provider;
if (!Platform.other) {
provider = new ReactNativeFirebaseAppCheckProvider();
provider.configure({
android: {
provider: 'debug',
debugToken: '698956B2-187B-49C6-9E25-C3F3530EEBAF',
},
apple: {
provider: 'debug',
debugToken: '698956B2-187B-49C6-9E25-C3F3530EEBAF',
},
web: {
provider: 'debug',
siteKey: 'none',
},
});
} else {
provider = new ReactNativeFirebaseAppCheckProvider({
getToken() {
return FirebaseHelpers.fetchAppCheckToken();
},
});
}
// Our tests configure a debug provider with shared secret so we should get a valid token
appCheckInstance = await initializeAppCheck(undefined, {
provider,
isTokenAutoRefreshEnabled: false,
});

@andrastoth-ws

This comment has been minimized.

@mikehardy
Copy link
Collaborator

mikehardy commented Mar 22, 2025

Hey @andrastoth-ws

The perfection would be a line number + filename combo, or a stack trace here. Or the very least the name of the culprit function.

Is there any way to force this info out somehow?

Yes - I had the same need for precision when I was migrating our e2e codebase to not have these warnings, so I added the ability to throw a stack trace when it happens, via a toggle that turns on "strict mode". It is documented in the migration guide you linked:

https://rnfirebase.io/migrating-to-v22#enabling-deprecation-strict-modes

@Rakshitg600

This comment has been minimized.

@mikehardy
Copy link
Collaborator

mikehardy commented Mar 23, 2025

@Rakshitg600 sorry for this - those AuthProviders weren't exported correctly yet in the modular API, PR #8323 fixes this - it just finished review and final CI checks and is releasing now

You should be able to use it as a named export and have it work, though you do not want to chain method calls of getAuth, use it like so:

import { GoogleAuthProvider, getAuth, signInWithCredential } from '@react-native-firebase/auth';
const googleCredential = GoogleAuthProvider.credential(idToken);
const userCredential = await signInWithCredential(getAuth(), googleCredential);

@Rakshitg600

This comment has been minimized.

@mikehardy

This comment has been minimized.

@Rakshitg600

This comment has been minimized.

@mikehardy

This comment has been minimized.

@Rakshitg600

This comment has been minimized.

@RodrigoSarmento

This comment has been minimized.

@mikehardy

This comment has been minimized.

@RodrigoSarmento

This comment has been minimized.

@jasimkhan-ariprodesign

This comment has been minimized.

@jasimkhan-ariprodesign

This comment has been minimized.

@mikehardy

This comment has been minimized.

@manishdevtechnosys
Copy link

manishdevtechnosys commented Mar 28, 2025

@mikehardy ,
Please help me with my NotificationController.js file. What do I need to change to resolve the notification error? Please make it correct.

Image

import React, { useState, useEffect } from 'react';
import {
Platform,
Animated,
} from 'react-native';
import messaging from '@react-native-firebase/messaging';
import PushNotificationIOS from '@react-native-community/push-notification-ios';
import AsyncStorage from '@react-native-async-storage/async-storage';
import PushNotification from 'react-native-push-notification';

const NotificationController = ({ navigation }) => {
const [showNotification, setShowNotification] = useState(false);
const [notificationMessage, setNotificationMessage] = useState('');
const slideAnim = useState(new Animated.Value(-80))[0];
const fadeAnim = useState(new Animated.Value(0))[0];

useEffect(() => {
const configurePushNotifications = async () => {
if (Platform.OS === 'android') {
PushNotification.createChannel(
{
channelId: 'default-channel',
channelName: 'Default Channel',
channelDescription: 'A default channel for notifications',
soundName: 'default',
importance: PushNotification.Importance.HIGH,
vibrate: true,
},
created => console.log(Notification channel created: ${created}),
);
}

  PushNotification.configure({
    permissions: {
      alert: true,
      badge: true,
      sound: true,
    },
    popInitialNotification: false,
    requestPermissions: false,
    onRegister: async function (token) {
      console.log('Token:', token);

      if (Platform.OS === 'ios') {
        const fcmToken = await messaging().getToken();
        console.log('FCM Token (iOS):', fcmToken);
        await AsyncStorage.setItem('notification_token', fcmToken);
        global.fcmToken = fcmToken;
      } else {
        console.log('FCM Token (Android):', token.token);
        await AsyncStorage.setItem('notification_token', token.token);
        global.fcmToken = token.token;
      }
    },
    senderID: '581145729913',
    soundName: Platform.OS === 'ios' ? 'default' : 'default',
  });

  if (Platform.OS === 'ios') {
    // PushNotificationIOS.requestPermissions();
  }

  messaging().onMessage(async remoteMessage => {
    console.log('Received foreground notification', remoteMessage);
    global.navigation = navigation;
    setNotificationMessage(remoteMessage);
    setShowNotification(true);

    Animated.sequence([
      Animated.timing(slideAnim, {
        toValue: 0,
        duration: 300,
        useNativeDriver: true,
      }),
      Animated.timing(fadeAnim, {
        toValue: 0.85,
        duration: 300,
        useNativeDriver: true,
      }),
    ]).start();

    setTimeout(() => {
      Animated.sequence([
        Animated.timing(fadeAnim, {
          toValue: 0,
          duration: 300,
          useNativeDriver: true,
        }),
        Animated.timing(slideAnim, {
          toValue: -80,
          duration: 300,
          useNativeDriver: true,
        }),
      ]).start(() => setShowNotification(false));
    }, 3000);
  });

  messaging().onNotificationOpenedApp(remoteMessage => {
    console.log(
      'Notification caused app to open from background or terminated state:',
      remoteMessage,
    );
    if (navigation) {
      navigateToModule(remoteMessage?.data);
    }
  });

  const notificationOpen = await messaging().getInitialNotification();
  if (notificationOpen != null) {
    console.log(
      'App was opened by tapping on a notification:',
      notificationOpen,
    );
    global.onTapNotification = notificationOpen;
  }
};

configurePushNotifications();

return () => {
  if (Platform.OS === 'ios') {
    PushNotificationIOS.removeEventListener('register');
    PushNotificationIOS.removeEventListener('registrationError');
    PushNotificationIOS.removeEventListener('notification');
  }
};

}, []);

return (
<>

</>

);
};

export default NotificationController;

@manishsaini0143
Copy link

@manishdevtechnosys

Please change these lines-

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

replace with -

import { getMessaging, onMessage, getToken, onNotificationOpenedApp, getInitialNotification } from '@react-native-firebase/messaging';

useEffect(() => {
const configurePushNotifications = async () => {
if (Platform.OS === 'android') {
PushNotification.createChannel(
{
channelId: 'default-channel',
channelName: 'Default Channel',
channelDescription: 'A default channel for notifications',
soundName: 'default',
importance: PushNotification.Importance.HIGH,
vibrate: true,
},
created => console.log(Notification channel created: ${created}),
);
}

  PushNotification.configure({
    permissions: {
      alert: true,
      badge: true,
      sound: true,
    },
    popInitialNotification: false,
    requestPermissions: false,
    onRegister: async function (token) {
      console.log('Token:', token);

      if (Platform.OS === 'ios') {
        const fcmToken = await messaging().getToken();
        console.log('FCM Token (iOS):', fcmToken);
        await AsyncStorage.setItem('notification_token', fcmToken);
        global.fcmToken = fcmToken;
      } else {
        console.log('FCM Token (Android):', token.token);
        await AsyncStorage.setItem('notification_token', token.token);
        global.fcmToken = token.token;
      }
    },
    senderID: '581145729913',
    soundName: Platform.OS === 'ios' ? 'default' : 'default',
  });

  if (Platform.OS === 'ios') {
    // PushNotificationIOS.requestPermissions();
  }

  messaging().onMessage(async remoteMessage => {
    console.log('Received foreground notification', remoteMessage);
    global.navigation = navigation;
    setNotificationMessage(remoteMessage);
    setShowNotification(true);

    Animated.sequence([
      Animated.timing(slideAnim, {
        toValue: 0,
        duration: 300,
        useNativeDriver: true,
      }),
      Animated.timing(fadeAnim, {
        toValue: 0.85,
        duration: 300,
        useNativeDriver: true,
      }),
    ]).start();

    setTimeout(() => {
      Animated.sequence([
        Animated.timing(fadeAnim, {
          toValue: 0,
          duration: 300,
          useNativeDriver: true,
        }),
        Animated.timing(slideAnim, {
          toValue: -80,
          duration: 300,
          useNativeDriver: true,
        }),
      ]).start(() => setShowNotification(false));
    }, 3000);
  });

  messaging().onNotificationOpenedApp(remoteMessage => {
    console.log(
      'Notification caused app to open from background or terminated state:',
      remoteMessage,
    );
    if (navigation) {
      navigateToModule(remoteMessage?.data);
    }
  });

  const notificationOpen = await messaging().getInitialNotification();
  if (notificationOpen != null) {
    console.log(
      'App was opened by tapping on a notification:',
      notificationOpen,
    );
    global.onTapNotification = notificationOpen;
  }
};

configurePushNotifications();

return () => {
  if (Platform.OS === 'ios') {
    PushNotificationIOS.removeEventListener('register');
    PushNotificationIOS.removeEventListener('registrationError');
    PushNotificationIOS.removeEventListener('notification');
  }
};

}, []);

replace with -

useEffect(() => {
const configurePushNotifications = async () => {
const messagingInstance = getMessaging();

  if (Platform.OS === 'android') {
    PushNotification.createChannel(
      {
        channelId: 'default-channel',
        channelName: 'Default Channel',
        channelDescription: 'A default channel for notifications',
        soundName: 'default',
        importance: PushNotification.Importance.HIGH,
        vibrate: true,
      },
      created => console.log(`Notification channel created: ${created}`),
    );
  }

  PushNotification.configure({
    permissions: {
      alert: true,
      badge: true,
      sound: true,
    },
    popInitialNotification: false,
    onRegister: async function (token) {
      console.log('Token:', token);

      if (Platform.OS === 'ios') {
        const fcmToken = await getToken(messagingInstance);
        console.log('FCM Token (iOS):', fcmToken);
        await AsyncStorage.setItem('notification_token', fcmToken);
        global.fcmToken = fcmToken;
      } else {
        console.log('FCM Token (Android):', token.token);
        await AsyncStorage.setItem('notification_token', token.token);
        global.fcmToken = token.token;
      }
    },
    senderID: '581145729913',
    soundName: Platform.OS === 'ios' ? 'default' : 'default',
  });

  if (Platform.OS === 'ios') {
    // PushNotificationIOS.requestPermissions();
  }

  // On message event
  onMessage(messagingInstance, async remoteMessage => {
    console.log('Received foreground notification', remoteMessage);
    global.navigation = navigation;
    setNotificationMessage(remoteMessage);
    setShowNotification(true);

    Animated.sequence([
      Animated.timing(slideAnim, {
        toValue: 0,
        duration: 300,
        useNativeDriver: true,
      }),
      Animated.timing(fadeAnim, {
        toValue: 0.85,
        duration: 300,
        useNativeDriver: true,
      }),
    ]).start();

    setTimeout(() => {
      Animated.sequence([
        Animated.timing(fadeAnim, {
          toValue: 0,
          duration: 300,
          useNativeDriver: true,
        }),
        Animated.timing(slideAnim, {
          toValue: -80,
          duration: 300,
          useNativeDriver: true,
        }),
      ]).start(() => setShowNotification(false));
    }, 3000);
  });

  // When the app is opened from background or terminated state
  onNotificationOpenedApp(messagingInstance, remoteMessage => {
    console.log(
      'Notification caused app to open from background or terminated state:',
      remoteMessage,
    );
    if (navigation) {
      navigateToModule(remoteMessage?.data);
    }
  });

  const notificationOpen = await getInitialNotification(messagingInstance);
  if (notificationOpen != null) {
    console.log(
      'App was opened by tapping on a notification:',
      notificationOpen,
    );
    global.onTapNotification = notificationOpen;
  }
};

configurePushNotifications();

return () => {
  if (Platform.OS === 'ios') {
    PushNotificationIOS.removeEventListener('register');
    PushNotificationIOS.removeEventListener('registrationError');
    PushNotificationIOS.removeEventListener('notification');
  }
};

}, []);

@cbdeveloper
Copy link

Hey @mikehardy , thanks for the amazing support.

I've just finished my project's migration and I have a couple of questions that you might be able to help me with.

  1. In Firebase docs regarding the migration to the modular API, we get this:

The modular API introduces a breaking change in which the property firestore.DocumentSnapshot.exists has been changed to a method.

I did not run into this method during the migration. Types and code seem to still be working as if it is a property.

const unsubscribe = onSnapshot(docRef, (docSnapshot) => {
  if (docSnapshot.exists) {} // I was able to keep this
  console.log(typeof docSnapshot.exists); // Logs boolean
});
  1. After the migration, I'm now calling getAuth and getFirestore in several different files. Does it make a difference if I'm calling those methods inside or outside the React components? What is the difference and what do you recommend?

  2. Maybe someone already raised this, but for the onAuthStateChanged method, the firebaseUser is being typed as any:

onAuthStateChanged(auth, (firebaseUser: FirebaseAuthTypes.User)

I had to manually type it using FirebaseAuthTypes.

@mikehardy
Copy link
Collaborator

Hey @cbdeveloper -

1- I peeled that DocumentSnapshot.exists item off to a new issue, that'll need a fix
2- I think you can call getAuth / getFirestore / get anywhere you like, it shouldn't matter
3- this is confusing to me, and I think there was just a change here recently even - #8436 - and that's the confusion - this is fixed but we haven't released it yet. I'll generate a release shortly and then it will be fixed for you and everyone courtesy of user DoctorJohn

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests