How to install, configure and use Firebase in React Native applications

Project Final Interface

After starting to use Firebase in some personal and professional projects, I see how these libraries can help us and empower our applications, especially when we don't have the structure of a backend, or when we want to have a login or database in a simpler way. example.

Therefore, I decided to create this design/project exclusively for us to learn how to configure Firebase and its packages in our projects, in addition to explaining how to use Auth to create a login with email and password, and firestore for storing user data .

The first step will be to start our project, with that, I decided to create it with the React Native CLI since Expo has some problems in the latest version of SDK 65, mainly related to the `@types/react dependency where it enters a loop saying you didn't install the dependency even though it was already installed.

To start our project with TypeScript, we will run the following command:

npx react-native init projectname --template react-native-template-typescript

As the project was created from the CLI, to run on our emulators it is necessary to build the app in Android Studio and XCode or by running yarn android and yarn ios .

πŸ’‘ Whenever I create a project, I also create the folder for it on Github, so I can version and not lose what I have progressed in the project.

Project created and built successfully βœ…

Default application interface created and emulated

After creating and building the project, the next step I take is to start installing Firebase. However, before starting, do you know the tool?

What is Firebase?

It is a Google platform that assists in the development of web and/or mobile applications, quickly and simply.

Firebase is a BaaS (Backend as a Service), that is, it provides the structure and the backend without having to develop the backend manually, in addition, it offers several solutions such as: file storage, user authentication, database , analytics, feature-flags...

To learn more about the tool, just access the two documentation available, the react native firebase https://rnfirebase.io/ e a do prΓ³prio Firebase https://firebase.google.com/docs.

What are the advantages of Firebase?

  • It has a free and very complete version by the way
  • scalable
  • It has support for several types of platforms (iOS, Android, JavaScript and C++) using the same API
  • Reduces development time as it delivers the ready-made backend
  • Has easy implementation

Creating a project in Firebase Console

  1. Before we start installing packages in code, we need to access the https://firebase.google.com/ to create a new project. You can use a Google account to connect, or create a new free account if you don't have one, and for that, just click on "Start".

Firebase Console

  1. After logging in to the Firebase Console, click on + Add Project

Add firebase console project

Then enter a name for your project and click on the continue button. In the next step, you can leave Google Analytics enabled or not and click on continue button.

Under Configure Google Analytics, select the "Default Account for Firebase" option and click the "Create Project" button.

Ready! Now just wait for the project to be created. πŸŽ‰

Project created in firebase console

Installation of React Native Firebase App

Now, let's install the React Native Firebase App module. Well, he is the one who makes the connection of our application with Firebase.

Then, run the installation in the root of the project:

# With npm
npm install --save @react-native-firebase/app

# With Yarn
yarn add @react-native-firebase/app

Configuration on Android

To perform the configuration on Android, we first need to go to the Firebase console to add a new Android application. Then, click on the Android icon.

Configure android app

  1. To register our Android app in the first step, we will carry out the instructions below and then click on Register app to move on to the next steps.

Add firebase android app

a. To find the name of the Android package, just access the MainActivity.java file in our code and the name will be on the first line of the file.

MainActivity.java file

b. In the nickname of the app we can put Android.

c. In the SHA-1 signature certificate field, we will not need it in this example, as it is mandatory only in some specific scenarios, but if you need to generate the certificate, type the code below at the prompt and the certificate will be generated.

cd android
bash ./gradlew signinReport

Several keys will be generated, but the one needed for this field is Variant: androiddebugkey - SHA1

SHA1 key

  1. In the next step, we will download the configuration file which is google-services.json and click on Next.

a. We'll download it and insert it into our code inside /android/app/

Download firebase configuration file

  1. Later we will add the Firebase SDK to our application, that is, we will configure the native code that will connect our application with Firebase.

a. First, let's go inside the /android/build.gradle file and add it inside buildscript:

buildscript {
  repositories {
    // Check that you have the following line (if not, add it):
    google() // Google's Maven repository
  }
  dependencies {
    ...
    // Add this line
    classpath("com.google.gms:google-services:4.3.13")

  }
}

allprojects {
  ...
  repositories {
    // Check if you have this line, if not, add it:
    google() // Google's Maven repository
    ...
  }
}

b. Later, we'll add the following snippet inside the /android/app/build.gradle file:

apply plugin: 'com.android.application'

// Add this line
apply plugin: 'com.google.gms.google-services'

dependencies {
  // Import Firebase BoM if using analytics
  implementation platform('com.google.firebase:firebase-bom:30.3.1')

  // Add dependency for Firebase SDK if you are going to use Analytics
  // When using BoM, don't specify versions in Firebase dependencies
   implementation 'com.google.firebase:firebase-analytics'
}

Configuration on iOS

To perform the configuration on iOS, we will follow the same pattern as on Android, first we will go to the Firebase console, click on Add app and then, we will click on the iOS+ icon.

Add iOS project in firebase console

  1. As configured on Android, we will fill in the fields below and then click on Register app to proceed to the next steps.

Add firebase in iOS app

a. To find the name of the Apple package ID we need to open our project in XCode by clicking on the name of the project and this will open next to the name, on the right side, more details of the project, and inside the General tab we can see inside Bundle Identifier the name that we will use inside the Apple Bundle ID.

bundle identifier XCode

b. In the nickname of the app I put the name of iOS

c. In the App Store Code field you will add if you already have the appStoreConect account, but it is completely optional

  1. In the next step, we will download the configuration file which is GoogleService-Info.plist and click on Next.

Download the googleservice-info.plist file

a. We will download it and to insert it into the project, we will open XCode again β†’ we will click on the name of the project, we will click with the right mouse button β†’ we will select Add Files to "name of the project "

Add files inside project

b. We will select the downloaded file and click on Add

googleServices-info.plist file

That's it, now the file is already added:

File added inside project

  1. Now from step 3 of the documentation, we will not follow exactly as described. In this step, we are asked to add the Firebase SDK, but every time I tried to do this step, the SDK somehow caused my project to have some bugs, so I preferred not to install it, but feel free to do so , if you wish. That is, this step I skip.

Add firebase SDK to iOS project

In the step of adding the initialization code, we will also do it a little differently than what is visualized, because our iOS code is in C++ and the options displayed are only for SwiftUI, Swift and Objective-C.

a. To allow Firebase to use the credentials on iOS, open the /ios/{projectName}/AppDelegate.m file in code and add the following line to the top of the file, just below #import "AppDelegate.h":

#import "AppDelegate.h"

#import "Firebase.h"
#import "FirebaseCore.h"

B. In this file, add the following code snippet:

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  // Add this configuration
  [FIRApp configure];

  return YES;
}

Installation of firebase libraries

Now that our Firebase is installed and properly configured, we will install the libraries that we will use in this login project.

  1. The first lib to be installed will be Cloud Firestore, which is a NoSQL document database. It is scalable and focused on mobile and web application development.

Main benefits:

  • Flexibility
  • Expressive queries
  • Real-time updates
  • We can use data synchronization to update them on any connected device
  • Offline support
  • Caches the data actively used by the application
  • Designed for climbing

So, in order to use it, we need to install the library as follows:

yarn add @react-native-firebase/firestore
  1. The second library that we will install will be the Auth library so that we can bring to life the login screens with email and password. To install it we need to run:
yarn add @react-native-firebase/auth

That's it, now yes, our Firebase is installed, configured, and with the necessary libraries also installed. But we need to run the pod install in our iOS folder and later rebuild the project in our Android and iOS emulators, since we made configurations in native codes.

cd ios/ && pod install

It may be that an error occurs when running the pod install similar to the one below: The Swift pod FirebaseCoreInternal depends upon GoogleUtilities, which does not define modules. To opt into those targets generating module maps (which is necessary to import them from Swift when building as static libraries), you may set use_modular_headers! globally in your Podfile, or specify :modular_headers => true for particular dependencies.

Basically we have to allow linking Swift static libraries, such as FirebaseCoreInternal and for that we will add the following command in our Podfile file:

pod 'Firebase', :modular_headers => true
pod 'FirebaseCore', :modular_headers => true
pod 'FirebaseCoreInternal', :modular_headers => true
pod 'GoogleUtilities', :modular_headers => true

And then build the project again in Android and iOS emulators, via prompt or via Android Studio and XCode or via prompt:

yarn ios

yarn android

Now, everything is ready to start using it in our code.

To start using the Firebase libraries we installed, I created the Water Reminder project on my Github, which can be accessed through the link: https://github.com/ildaneta/water-reminder.

If you want, you can clone the project from the feature/screens branch, so all the screens, components and navigations will already be configured, and it will be possible to implement the SignIn, *SignUp screens * and **Recovery password** which we will learn next.

Branch: https://github.com/ildaneta/water-reminder/tree/feature/screens

Using Auth and Cloud Firestore

To start using the Auth of Firebase, we will go to the console https://console.firebase.google.com and in the upper left menu we will click in Creation β†’ Authentication

Auth firebase console

Then, click on Let's get started β†’ choose the E-mail/Password option

image

We will activate the first option and then click on Save.

image

We configured our Auth in the Firebase console, now we will create our Cloud Firestore, that is, our database, which will save the users' data. To do this, we will again go to the top left menu, click on Firestore Database and then on Create database.

image

Choose Production Mode β†’ Next, then Cloud Firestore Location and Enable.

image

Once our database is created, we will go inside Rules and delete the : if false; part next to ,write , then click on Publish, because this way, we will save data in the database. data, even when the user is not yet logged in.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: // if false; // to switch off
    }
  }
}

image

The next step is to set up a collection, which would be the same as a table, in this case it will be our users table. We will name the collection and click Next.

image

To create a collection by Firebase it is necessary to insert a document id, in this case, we can click on Automatic Code and Save, so our collection will be created.

Now it's time for the code. πŸ‘©πŸ»β€πŸ’»

For this application, as everything is related to the login part, I created a hook called useAuth where all the necessary functions for the login to work correctly will be: signUp(responsible for creating a user), signIn( responsible for performing the login), singOut (responsible for logging out the user), recoveryPassword (responsible for resetting the user's password via e-mail), isLoading (will return if there is a loading), and user (returns the user id and username).

Creating a User with Firebase Auth and adding it inside the Firebase Firestore Users collection.

To create the user with auth it is necessary to call the auth method .createUserWithEmailAndPassword(email, password) passing the email and password entered by the user. After that, I store the data in the firestore, calling the firestore() method, to save the data in the collection of users, I use the .collection('users') method passing the name of the collection.

Here is an important detail, because to add data to a collection I can use two ways, one with the .add() method, so we create new data in the collection with a random id created by Firebase, but in this scenario I needed the collection's document id was the same as the user id created in auth, so when adding I use the .doc(uid) method passing the user account id inside auth, and call the .set method () passing the user id and registration name that will be stored in the firestore users collection.

const signUp = async ({ username, email, password }: SignUpData) => {
  if (!username || !email || !password) {
    return Alert.alert(
      'SignUp',
      'Enter username, e-mail and password to create your account.'
    )
  }

  if (password.length < 6) {
    return Alert.alert('SignUp', 'Password cannot be less than 6 characters.')
  }

  try {
    setIsLoading(true)
    await auth()
      .createUserWithEmailAndPassword(email, password)
      .then((account) => {
        const { uid } = account.user

        firestore()
          .collection('users')
          .doc(uid)
          .set({
            id: id,
            username,
          })
          .then(() => {
            Alert.alert('SignUp', 'Account created with success!', [
              {
                text: 'Okay',
                onPress: () => navigation.navigate('SignIn'),
              },
            ])
          })

        setIsLoading(false)
      })
      .catch((error) => {
        const { code } = error

        if (code === 'auth/email-already-in-use') {
          return Alert.alert('SignUp', 'E-mail is already in use')
        }
        setIsLoading(false)
      })
      .finally(() => {
        setIsLoading(false)
      })
  } catch (error) {}
}

Basically these are the steps to create a user with the two libs, the rest of the code is just some checks and redirects that I perform.

Log in a user already registered in the auth and firestore database

The steps for logging in are very similar to creating a new user, what changes are the methods used.

In auth, instead of using .createUserWithEmailAndPassword() to create, we'll use .signInWithEmailAndPassword(email, password) to perform the login, and to bring that already registered user from the firestore, we use the .get( ) passing first which collection we will fetch the data from and which id of the document to be retrieved.

Another step that I do in signIn is to save the user's data, which are the id and the name inside the AsyncStorage so I can check if the user is already logged in so that he doesn't have to go through the login screen again. signIn.

const signIn = async ({ email, password }: SignInData) => {
  if (!email || !password) {
    return Alert.alert('SignIn', 'E-mail and password is required.')
  }

  setIsLoading(true)

  auth()
    .signInWithEmailAndPassword(email, password)
    .then((response) => {
      const { uid } = response.user
      firestore()
        .collection('users')
        .doc(uid)
        .get()
        .then(async (profile) => {
          const { id, username } = profile.data() as IUser

          if (profile.exists) {
            const userData = {
              id,
              username,
            }

            setUser(userData)

            AsyncStorage.setItem(USER_COLLECTION, JSON.stringify(userData))
            navigation.navigate('Home')
          }

          setIsLoading(false)
        })
    })
    .catch((error) => {
      const { code } = error

      if (code === 'auth/wrong-password') {
        return Alert.alert(
          'SignIn',
          'The password is invalid or the user does not have a password.'
        )
      }

      if (code === 'auth/user-not-found') {
        Alert.alert(
          'SignIn',
          'There is no user record corresponding to this email.'
        )
      }
    })
    .finally(() => setIsLoading(false))
}

Perform user password recovery

To send a password recovery email so that the user can modify it, we use the auth method .sendPasswordResetEmail(email), this is very simple, because firebase takes care of everything else, which would be sending the e-mail and save the new registered password. In the code below, in addition to calling the method to recover the password, I present alerts in case of success and error.

const recoveryPassword = async ({ email }: RecoveryPasswordData) => {
  if (!email) {
    return Alert.alert('Recovery password', 'E-mail is required.')
  }

  await auth()
    .sendPasswordResetEmail(email)
    .then(() => {
      Alert.alert(
        'Recover password',
        'We have sent a link to your email to reset your password.',
        [
          {
            text: 'Okay',
            onPress: () => navigation.navigate('SignIn'),
          },
        ]
      )
    })
    .catch((error) => {
      const { code } = error

      if (code === 'auth/user-not-found') {
        Alert.alert(
          'Recover password',
          'It was not possible to send the password reset to your e-mail, because the e-mail you entered was not registered.'
        )
      }
    })
}

Logoff the user from the application

Last but not least, would be the step of logging the user out of the application, and for that we call the auth method .signOut(). As I also save user data in AsyncStorage when he logs in, at that moment I also remove them and navigate again to the SignIn screen.

const signOut = async () => {
  setIsLoading(true)
  await auth().signOut()
  await AsyncStorage.removeItem(USER_COLLECTION)
  setUser(null)
  setIsLoading(false)

  navigation.navigate('SignIn')
}

Basically these are the steps we have to take to have the complete login solution using firebase.

Remembering that you can follow all the progress / implementation of the application through the project on Github: https://github.com/ildaneta/water-reminder

In addition, this project is open source, that is, the code is open and you can use it as you wish, in addition, it is a great opportunity to make contributions, that is, you can make this app come to life, send requests for pull request for me, insert tests, in short, put all the knowledge into practice and still contribute to a community project.

I hope you enjoyed the article, although it is quite long, I tried to explain in as much detail as possible how to install, configure and use Firebase, which is already one of my favorite libs, and which in the beginning I had some problems with the initial installation, which for me is the most complex.

Until the next article folks! 🫢🏻