Firebase SDK with Firestore for React Native apps in 2018

Source: Human Torch

At Firebase Dev Summit 2017, Google introduced Firestore as fully-managed NoSQL document database for mobile and web app development. Compared to Firebase Realtime Database, it has better querying and more structured data, together with ease manual fetching of data.

The new structure of collection and document is probably the eye catching, this makes data more intuitive to users and query a breeze.

From https://firebase.googleblog.com/2017/10/cloud-firestore-for-rtdb-developers.html

In this post, I will show how to setup Firebase Cloud Firestore in React Native apps for both iOS and Android through, of course, some pain points. Then we create and fetch document in Firestore database.

Firebase Javascript SDK

My first option is to go with Firebase Javascript SDK, as it worked well for me with Firebase Realtime Database. My use case is to just fetch and update Firestore collections, I think it does not involve much of native features. Furthermore, when possible I try to avoid native code as much as possible when dealing with React Native.

So let’s try Get started with Cloud Firestore

npm install firebase

The version I install is 5.4.0. Next, import firebase and note that we need to import firestore as well

const firebase = require("firebase");
// Required for side-effects
require("firebase/firestore");

document is not defined

This issue made me bang against my desk for a while. As people have pointed out, it is because of document being accessed.

var BrowserPlatform = /** @class */ (function () {
function BrowserPlatform() {
this.emptyByteString = '';
this.document = document; // delete this line
this.window = window; // delete this line
this.base64Available = typeof atob !== 'undefined';
}

The firestore component in the current Firebase Javascript SDK does not fully support React Native, so we need to work around or use beta version with npm install firebase@next . In the mean time, let’s try React Native Firebase.

React Native Firebase

Reading over at Cloud Firestore Library and framework integrations, React Native Firebase is recommended. Although some features from the Firebase Web SDK will generally work with React Native, it is mainly built for the web and as such has a limited compatible feature set.

Source: https://rnfirebase.io/docs/v4.3.x/getting-started

The below article and their starter app is the guiding star. The integration with native code in iOS and Android can be painful, but I React Native Firebase is very powerful as it has up-to-date wrappers around native Firebase SDK.

Let ‘s npm install react-native-firebase , the current version is 4.3.8 , and follow manual setup guide for existing project, this helps you learn more about the process and the bootstrap script.

A quick look

First you need to Firebase console and add a project. A project allows many apps to stay, for example I have 4 apps (2 iOS, 2 Android) that have access to Firestore database.

Head over to Database in the left menu, we can see a quick look into Firestore and its collection/document structure

Setup for iOS

Follow iOS Installation Guide

Firstly, download GoogleService-Info.plist and place it in the correct folder, make sure it has been added to project via Xcode. Otherwise Firebase SDK causes app to crash right after start.

Then add #import <Firebase.h> to AppDelegate.m and [FIRApp configure]; to function didFinishLaunchingWithOptions . Next create Podfile with pod init inside ios folder. For Firestore, you need Firebase/Firestore to prevent the error below

You attempted to use a firebase module that’s not installed natively on your iOS project by calling firebase.firestore()

And you shouldn’t use use_frameworks! as it gives error ‘FirebaseCore/FIRAnalyticsConfiguration.h’ file not found

platform :ios, '9.0'
target 'FoodshopGuest' do
pod 'Firebase/Core', '~> 5.3.0'
pod 'Firebase/Firestore', '~> 5.3.0'
end

If you get framework not found FirebaseAnalytics , then make sure each target has $(inherited) at the top for Framework Search Paths

Then run react-native link react-native-firebase and you should be good for iOS.

Setup for Android

Android is a bit less straightforward to setup than iOS. But it’s not impossible. Let’s follow Android Installation guide.

Firstly, place google-services.json in android/app/google-services.json . Let’s also use Gradle 4.4 and Google Play Services 15.0.1 . Change gradle/gradle-wrapper.properties to use

distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

Below is my project build.gradle with compileSdkVersion 27 and buildToolsVersion 27.0.3 . Make sure google() stays above jcenter()

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenLocal()
google()
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.google.gms:google-services:4.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
google()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
}
ext {
buildToolsVersion = "27.0.3"
minSdkVersion = 16
compileSdkVersion = 27
targetSdkVersion = 26
supportLibVersion = "26.1.0"
}

For my app module build.gradle , let’s have apply plugin: ‘com.google.gms.google-services’ at the very bottom of the file, this is important. In dependencies section, you must have com.google.firebase:firebase-firestore to include Firestore component.

dependencies {
implementation project(':react-native-firebase')
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
// Firebase dependencies
implementation "com.google.android.gms:play-services-base:15.0.1"
implementation "com.google.firebase:firebase-core:16.0.1"
implementation "com.google.firebase:firebase-firestore:17.0.2"
}

Make sure there is no duplication of project(‘:react-native-firebase’) . And since we are using Gradle 4, let’s use implementation instead of compile

Because of Firestore, let’s follow react-native-firebase-starter to fix heap problem

dexOptions {
javaMaxHeapSize "4g"
}
multiDexEnabled true

If you get Native module RNFirebaseModule tried to override FNFirebaseModule

Native module RNFirebaseModule tried to override FNFirebaseModule for module name Firebase. If this was your intention, set `canOverrideExistingModule=true

Then make sure your MainApplication.java has no duplication for new RNFirebasePackage() . Here is my MainApplication.java , note that you need import io.invertase.firebase.firestore.RNFirebaseFirestorePackage; in order to use RNFirebaseFirestorePackage

package com.fantageek.foodshophost;
import android.app.Application;
import com.facebook.react.ReactApplication;
import io.invertase.firebase.RNFirebasePackage;
import io.invertase.firebase.firestore.RNFirebaseFirestorePackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RNFirebasePackage(),
new RNFirebaseFirestorePackage()
);
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}

My rule of thumb is that you should always use Android Studio to perform Gradle sync or Build projectThere you should be able to see compile issues much easier. With all the steps above, compilation should succeed.

One problem with running React Native on Android, if after react-native run-android and Metro keeps showing Loading dependency graph, done , then you should start emulator via Android Studio -> AVD Manager or adb , the app should be already installed in the emulator, open the app and Metro will start loading again.

Trying Firestore

React Native Firebase should give you similar APIs to those in the web, so learn from Get data with Cloud Firestore for how to get or set documents.

I like to organise services in separate files, here is how to reference firestore and load document.

import firebase from 'react-native-firebase'
class FirebaseService {
constructor() {
this.ref = firebase.firestore().collection('people')
}
async load(id) {
const doc = await this.ref.doc(id).get()
if (doc.exists) {
return doc.data()
} else {
const defaultDoc = {
name: "ABC",
age: 2
}
await this.ref.doc(id).set(defaultDoc)
return doc
}
}
}
export const firebaseService = new FirebaseService()

Where to go from here

I hope this article helps in setting up Firebase SDK in React Native apps. Below are some resources that helps you explore further. The react-native-firebase-starter contains awesome reference code if you get into any troubles with react-native-firebase.