Using Firebase in Expo (React Native) app - react-native

I'm considering Firebase for my new mobile app which is an Expo app. Expo's team did a nice tutorial about it (https://docs.expo.io/versions/latest/guides/using-firebase/).
Reading this tutorial, I can see that the recommanded way is to put API credentials (key, project ID, etc.) directly in the app and initialize the client that way:
import * as firebase from 'firebase';
// Initialize Firebase
const firebaseConfig = {
apiKey: "<YOUR-API-KEY>",
authDomain: "<YOUR-AUTH-DOMAIN>",
databaseURL: "<YOUR-DATABASE-URL>",
storageBucket: "<YOUR-STORAGE-BUCKET>"
};
firebase.initializeApp(firebaseConfig);
The question: is it safe to put an API key in a RN (Expo) project?

im using firebase too , and along with that a lot other third party sdk which needs API KEy. I've done it by storing it in the backend, and when the App is initialized(i.e mounted),I call an API to backend whihc gives all the API keys , and I store them in respective Async storages, so that whenever i need that particular API key , i just do AsyncStorage.getItem('API_Key') , and it's both secured and cannot be tracked since it's from backend. And obviously in backend you want to store them as env variables. So i would suggest you to follow that.
In your case , just do
let firebaseApiKey = AsyncStorage.getItem('firebaseKey');
// Initialize Firebase
const firebaseConfig = {
apiKey: firebaseApiKey,
authDomain: "<YOUR-AUTH-DOMAIN>",
databaseURL: "<YOUR-DATABASE-URL>",
storageBucket: "<YOUR-STORAGE-BUCKET>"
};
firebase.initializeApp(firebaseConfig);

I'd recommend you use a service like Visual Studio App Center to define your env variables then reference those variables in your code. During the build process, VS App Center will fit in the values in places where you've used it in your code.
So the sensitive values never even touch your codebase. That's the safest solution I can think of.

Related

Running html only if running in Electron.js [duplicate]

I'm trying to serve real react app on electron app. It doesn't mean I'm developing electron app with react. I've created a react app and injected it into electron app. (Like slack, it will serve as a web application and desktop application.) But I'm confused that send desktop notifications.
Now the main question is:
How can I get the application type. I mean, is user using my app on web or on desktop. How can I get this?
Thank you :)
There are many ways to detect whether you are running in a desktop environment or not.
You can check the User-Agent and you can set the userAgent value in Electron when you call loadURL.
Another way is declaring a global variable using a preload script.
// main process
new BrowserWindow({
webPreferences: {
preload: "preload.js",
},
});
// preload.js
// you don't need to use contextBridge if contextIsolation is false
// but it's true by default in Electron 12
const { contextBridge } = require("electron");
contextBridge.exposeInMainWorld("IN_DESKTOP_ENV", true);
// renderer process (your React world)
if (globalThis.IN_DESKTOP_ENV) {
// do something...
}

Firebase Google Sign In not working in React Native

import firebase from 'firebase';
import React from 'react';
import { useAuthState } from 'react-firebase-hooks/auth';
import App from './testlogin';
import { View, Text, Button } from 'react-native';
import { firebaseConfig } from './firebaseConfig';
const app = firebase.initializeApp(firebaseConfig);
const auth = app.auth();
const db = app.firestore();
const googleProvider = new firebase.auth.GoogleAuthProvider()
export const signInWithGoogle = async () => {
try {
const res = await auth.signInWithPopup(googleProvider);
const user = res.user;
const query = await db
.collection("users")
.where("uid", "==", user.uid)
.get();
if (query.docs.length === 0) {
await db.collection("users").add({
uid: user.uid,
name: user.displayName,
authProvider: "google",
email: user.email,
});
}
} catch (err) {
console.error(err);
alert(err.message);
}
};
This code accesses the google sign in method and should pop up a window, but I don't get anything when I click the button. I have been having difficulty with implementing Firebase in React Native and this is one of the examples. I need an example of easy Google sign in button in React Native.
I recommend you to use https://rnfirebase.io/ library (their docs are quite helpful).
Here are their instructions for Google Sign-in: https://rnfirebase.io/auth/social-auth#google.
According to them, you need to
ensure the "Google" sign-in provider is enabled on the Firebase Console.
also install #react-native-google-signin/google-signin',
then "Before triggering a sign-in request, you must initialize the Google SDK using your any required scopes and the webClientId, which can be found in the android/app/google-services.json"
Finally, as because following:
Starting April 2020, all existing applications using external 3rd party login services (such as Facebook, Twitter, Google etc) must ensure that Apple Sign-In is also provided. - You would also need to support iOS / and Apple Sign-in too. (if are building app also for iOS).
NOTE: I also remember that I had to put both, SHA1 and SHA256 hashes in the Firebase Console as some Firebase services were not working without it.
How to find SHA hashes in Android for Firebase (signing with Keystore that will be used in production should be already configured):
The debug signing certificate is optional to use Firebase with your app, but is required for Dynamic Links, Invites and Phone Authentication. To generate a certificate run
cd android && ./gradlew signingReport
and copy the SHA1 and SHA256 from the debug key. This generates two variant keys. You can copy the 'SHA1' that belongs to the debugAndroidTest variant key option.
Again, I recommend you to put both SHA hashes in Firebase Console.

How do I use the local Firebase Auth emulator and not production auth to test my users?

My app still expects to validate users with the production firebase-auth instance, despite having initialised the auth emulator locally with:
firebase init emulators
This is the auth logic in my React app:
const handleLogin = () =>
authentication.signInWithEmailAndPassword("emulator#test.com", "emulator");
After handleLogin is triggered, I get the error "auth/user-not-found" as firebase is querying the production auth instance instead.
You need to call useEmulator synchronously, right after initialisation of your app’s auth instance. useEmulator takes the local emulator URL as its only argument.
You need the following wherever your firebase auth instance is initialised:
Firebase SDK Version 9 with tree shaking
import { getAuth, connectAuthEmulator } from "firebase/auth";
const auth = getAuth();
connectAuthEmulator(auth, "http://localhost:9099");
Firebase SDK Version 8
import firebase from "./firebase-config";
import "firebase/auth";
const authentication = firebase.auth();
authentication.useEmulator("http://localhost:9099");
export default authentication;

How do you identify the Expo project that an Expo Push Notification Token belongs to?

Premise
For better or for worse, I use two Expo accounts for my production and development environments.
Production Expo Account: prod-proj
Development Expo Account: dev-proj
I use Expo's push notification service to send push notifications to my users. I store each user's Expo Push Notification Token on their user document. i.e.:
User
id: 1
name: Jimothy
token: ExponentPushToken[di3ja!-lk2^(24af]
Through an unfortunate series of events, most users in my database have a push notification created using the prod-proj Expo project, but a few users have a push notification created using dev-proj.
Problem
When I try to chunk and send push notifications to all my users, I get an error from Expo:
Error: All push notification messages in the same request must be for the same project; separate your push notifications by project.
But my tokens are all mixed up!
How can I separate the Expo Push Notification Tokens by project?
Figured out the answer to this one!
In the expo-server-sdk Node client for Expo, the details field of the error returned by Expo contains all the information about which tokens belong to which projects.
Example Code
const { Expo } = require('expo-server-sdk');
const expo = new Expo();
const sendNotifications = async () => {
const notifications = [ ... ];
const chunks = expo.chunkPushNotifications(notifications);
for (const chunk of chunks) {
try {
await expo.sendPushNotificationsAsync(chunk)
}
catch (error) {
console.log(JSON.stringify(error));
// The important part:
// error.details = { EXPO_PROJECT_NAME: [ ExponentPushTokens ] }
}
}
}
I'm facing the same issue right now and probably the best thing we can do is to send the expo push token along with the experience id to the backend. From there, group tokens by experience and send those groups as we'd normally do.
import Constants from "expo-constants";
const experienceId = Constants.manifest.id; // #user/project-slug

Correct way to use initialize firestore in react-native expo app

Have seen two different ways to initialize firestore in a react-native app and would like to know what the differences between the two are. The method shown in the firestore docs (https://firebase.google.com/docs/firestore/quickstart#initialize) looks like
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
export fs = admin.firestore();
while the "firebase" way (as seen in this expo post: https://forums.expo.io/t/open-when-an-expo-firebase-firestore-platform/4126/29), which is the way I currently use and appears to work, looks like
import * as firebase from 'firebase';
import 'firebase/firestore';//for using firestore functions, see https://stackoverflow.com/a/50684682/8236733
import { firebaseConfig } from './firebase-credentials';//WARN: gitignored, exports object containing firebase (web)app credentials
// Initialize Firebase
// why in separate file? see https://github.com/zeit/next.js/issues/1999 and https://ilikekillnerds.com/2018/02/solving-issue-firebase-app-named-default-already-exists/
// firebase.initializeApp(firebaseConfig);
try {
firebase.initializeApp(firebaseConfig)
/*WARN:
#firebase/firestore:, Firestore (5.0.4):
The behavior for Date objects stored in Firestore is going to change
AND YOUR APP MAY BREAK.
To hide this warning and ensure your app does not break, you need to add the
following code to your app before calling any other Cloud Firestore methods:
const firestore = firebase.firestore();
const settings = {timestampsInSnapshots: true};
firestore.settings(settings);
With this change, timestamps stored in Cloud Firestore will be read back as
Firebase Timestamp objects instead of as system Date objects. So you will also
need to update code expecting a Date to instead expect a Timestamp. For example:
// Old:
const date = snapshot.get('created_at');
// New:
const timestamp = snapshot.get('created_at');
const date = timestamp.toDate();
Please audit all existing usages of Date when you enable the new behavior. In a
future release, the behavior will change to the new behavior, so if you do not
follow these steps, YOUR APP MAY BREAK.
*/
const fsSettings = {/* your settings... */ timestampsInSnapshots: true};
firebase.firestore().settings(fsSettings)
} catch (err) {
// we skip the "already exists" message which is
// not an actual error when we're hot-reloading
if (!/already exists/.test(err.message)) {
console.error('Firebase initialization error', err.stack)
}
}
export const fs = firebase.firestore()
The post linked to is the only instance where I could find someone else doing this, but again it does work for me (can read and write to firestore).
Very new to using firebase/firestore and would like to use the more 'correct' method. Is there any difference between initializing firestore in the app in these separate ways?
Import:
import * as firebase from 'firebase';
import 'firebase/firestore';
Then
const db = firebase.firestore();
https://github.com/invertase/react-native-firebase
This is a JavaScript bridge to the native Firebase SDKs for both iOS and Android therefore Firebase will run on the native thread.
It has a step-by-step instructions for react-native app integration with firebase.
One important thing is that you have to consider about your react-native version and firebase sdk version.
They do the same things though? The first one simply does it by declaring and expo does it by declaring it inline. You can do it however you like, but both of them do the same things