Get FCM token in React-Native - firebase

In my React-Native application, I have to use firebase notifications.
So I created this library. Have I done this in the correct way? How can I test this to check if this works properly? What I want is to return the FCM token here.
/** Firebase Cloud Messaging Methods */
import firebase from 'react-native-firebase';
const getToken = async () => {
try {
const token = await firebase.messaging().getToken();
if (token) return token;
} catch (error) {
console.log(error);
}
};
const getFCMToken = async () => {
try {
const authorized = await firebase.messaging().hasPermission();
const fcmToken = await getToken();
if (authorized) return fcmToken;
await firebase.messaging().requestPermission();
return fcmToken;
} catch (error) {
console.log(error);
}
};
export { getFCMToken };

import messaging from '#react-native-firebase/messaging';
const checkToken = async () => {
const fcmToken = await messaging().getToken();
if (fcmToken) {
console.log(fcmToken);
}
}
checkToken();
References: https://rnfirebase.io/messaging/usage and
https://github.com/invertase/react-native-firebase-docs/blob/master/docs/messaging/device-token.md

To check if you have implemented notification correctly. You have to go to
Firebase Console
Click on 'Cloud Messaging' and then "New Notification"
Send a test notification.
If you receive a notification then your code is fine.
BTW you should use the "Topic" implementation rather than the "Token" implementation. It will make this process of sending Notifications very easy and manageable.

Getting FCM notification using 3rd party library always painful for debugging, So Always i would recommend use Native call for such API using react-native bridge.because react-native library should only use if common functionality used in Android and IOS.
this is updated

Related

Phoneauthprovider is not a function firebase react-native

Hi everybody im making a app using react-native and fire base im have this initial config at firebase config :
import firebase from 'firebase/app';
import 'firebase/auth';
import Constants from 'expo-constants';
// Firebase Config
// Initialize Firebase
export const firebaseConfig = {
apiKey: Constants?.manifest?.extra?.apiKey,
authDomain: Constants?.manifest?.extra?.authDomain,
projectId: Constants?.manifest?.extra?.projectId,
storageBucket: Constants?.manifest?.extra?.storageBucket,
messagingSenderId: Constants?.manifest?.extra?.messagingSenderId,
appId: Constants?.manifest?.extra?.appId
};
let Firebase
if (firebase.apps.length === 0) {
console.log('hello world')
Firebase = firebase.initializeApp(firebaseConfig);
}
export default Firebase;
And im triyng to call this method:
const loginUser = async() => {
switch(loginType){
case 0:
break;
case 1:
if (typeof(verificationId) == 'string') {
setLoading(true)
try {
const credential = new Firebase.auth.PhoneAuthProvider.credential(
verificationId,
verificationCode
);
await Firebase.auth.signInWithCredential(credential);
showMessage({ text: 'Phone authentication successful 👍' });
} catch (err) {
setLoading(false)
showMessage({ text: `Error: ${err.message}`, color: 'red' });
}
} else {
try {
const phoneProvider = Firebase.auth.PhoneAuthProvider();
const verificationId = await phoneProvider.verifyPhoneNumber(
phoneNumber,
recaptchaVerifier.current
);
setVerificationId(verificationId);
showMessage({
text: 'Verification code has been sent to your phone.',
});
} catch (err) {
showMessage({ text: `Error: ${err.message}`, color: 'red' });
}
}
break;
}
}
When im try to call my 'phone Login method' react-native show me this message:
im use this guide for how to configure the enviroment:
https://blog.jscrambler.com/how-to-integrate-firebase-authentication-with-an-expo-app
but using phone verification with recaptcha im not found the problem i believe the problem its in my implementation but in not found nothing
Thanks for the answers
I see you're trying to implement phone auth using firebase and I personally had success doing that using this:
async function signInWithPhoneNumber(phoneNumber) {
//1. Have the user input thei phone number into a TextInput and pass it to this function
//2. Have a confirm useState to make sure the verification code was sent successfully by firebase
//3. Check for the confirm state in the main component and show the user another TextInput to enter the verification code if confirm has a value
await firebase.auth()
.signInWithPhoneNumber(phoneNumber)
.then(confirmation => {
setConfirm(confirmation)
})
.catch(e => {
Alert.alert('Error sending verification code to this phone number')
})
}
async function confirmCode(code) {
//1. Have the code the user entered through the TextInput pass through here and call the below function
try {
let validation = await confirm?.confirm(code)
if (validation) console.log('correct code.')
} catch (error) {
Alert.alert('Invalid code.')
}
}
You're importing your own Firebase object, which is an instance of FirebaseApp. The PhoneAuthProvider class is not defined on FirebaseApp, but rather is in the (static) firebase.auth namespace.
So you either need to also import the regular Firebase Auth SDK into your code, instead of just your own Firebase object, or you can attach the firebase.authnamespace to yourFirebase` object and use it from there with:
...
if (firebase.apps.length === 0) {
console.log('hello world')
Firebase = firebase.initializeApp(firebaseConfig);
Firebase.auth = firebase.auth;
}
export default Firebase;

connecting to firestore emulator with #firebase/testing

I am trying to test a firebase app locally.
I am running the test with firebase emulators:exec --only firestore 'mocha -r ts-node/register src/**/*.spec.ts
In my spec, I import #firebase/testing and setup my app and followed the directions from
https://firebase.google.com/docs/rules/unit-tests
I have a FirebaseService which is a singleton wrapper for my methods into which I inject my firebase app.
In production, I'll inject the firebase, and it gets initialized in the FirebaseService in testing, I initialize outside of the service.
The wrapper is fairly simple
export const FirebaseService = (function(): FirebaseSrvc {
let firebase;
const fbServiceObj: FirebaseSrvc = {
getInstance: (firebaseConfig, firebaseCore, initialize) => {
firebase = firebaseCore;
if (initialize && firebase.apps.length === 0) {
firebase.initializeApp(firebaseConfig);
}
return fbServiceObj;
},
createActivity: async (title: string) => {
try {
const firebaseUid = firebase.auth().currentuser.uid;
const newActivity: ActivityProps = {
title,
created_at: 123445,
created_by: firebaseUid,
public: false,
available_to: [firebaseUid],
};
console.log(' before create', newActivity);
const createResponse = await firebase
.firestore()
.collection('activities')
.doc(stringToSafeId(title))
.set(newActivity);
console.log('create response', createResponse);
return true;
} catch (e) {
console.log('error creating activity', e);
}
},
getActivity: async (title: string): Promise<ActivityProps> => {
try {
const actResponse: DocumentReferenceTo<ActivityProps> = await firebase
.firestore()
.collection('activities')
.doc(stringToSafeId(title))
.get();
return actResponse as ActivityProps;
} catch (e) {
console.log('error getting activity from firebase', e);
}
},
};
return fbServiceObj;
})();
The test I am attempting to run is
import * as firebase from '#firebase/testing';
import { assert } from 'chai';
import 'mocha';
import * as appConfig from '../../app-dev.json';
import { FirebaseService } from '../services/FirebaseService';
firebase.initializeTestApp({ ...appConfig.expo.extra.firebase, auth: { uid: 'random', email: 'test#test.com' } });
describe('Activity', async () => {
const fb = FirebaseService.getInstance(appConfig.expo.extra.firebase, testApp, false);
const activityData = new Activity(fb);
beforeEach(async () => await firebase.clearFirestoreData({ projectId }));
it('should create a new activity', async () => {
await activityData.set('test-activity'); // this runs FirebaseService.createActivity
const findActivity = await activityData.get('test-activity'); // this run FirebaseService.getActivity
assert(findActivity.title === 'test-activity');
});
});
When I run the test I get an error
Your API key is invalid, please check you have copied it correctly.] {
code: 'auth/invalid-api-key',
message: 'Your API key is invalid, please check you have copied it correctly.'
}
I can confirm that the API key which is passed into firebase.initializeTestApp matches the Web API Key in my firebase console.
I have also downloaded the google-services.json from my firebase console and lists
{
"api_key": [
{ "current_key": different_from_web_key}
]
}
And I have replaced my existing key with this new key, I still get the same error.
I have also tried setting up initializeTestApp({ projectId }) which is how the example from firebase docs sets it up, and I receive the same result.
I am using the same project details to run a project locally in android studio, and I am able to authenticate and write to firestore, so the API key I am using does work, but it appears to have issues being used in the test app.
This usually doesn't have a specific way to solve it. It might be that even a new copy and paste of the API key to the parameters, might make it work and the error to disappear.
I would recommend you to take a look at the following posts from the Community, that have some possible fixes for the error that you are facing.
Firebase Error: auth/invalid-api-key, Your API key is invalid, please check you have copied it correctly
Invalid API Key supplied using Firebase
In addition to that, since Firebase has free support offers, I think you reaching out to the Firebase support would help you fix this quickly. You should be able to contact directly for free.
Let me know if the information helped you!

This operation is not supported in the environment this application is runnung on [duplicate]

I develop a react-native (expo) mobile app and try to sign in with a google account to firebase, but I get an error:
"auth/operation-not-supported-in-this-enviroment. This operation is not supported in the enviroment this application is running on. "location.protocol" must be http, https or chrome-extension and web storage must be enabled"
Code:
loginGoogle() {
var provider = new firebase.auth.GoogleAuthProvider();
provider.addScope('profile');
provider.addScope('email');
firebase.auth().signInWithPopup(provider).then(function(result) {
var token = result.credential.accessToken;
var user = result.user;
return true;
}).catch(function(error) {
alert(error.code + '\n' +
error.message + '\n' +
error.email + '\n' +
error.credential);
return false;
});
}
signInWithPopup is not supported in react-native. You will need to use a third party OAuth library to get the OAuth ID token or access token and then sign in with Firebase:
const cred = firebase.auth.GoogleAuthProvider.credential(googleIdToken, googleAccessToken);
firebase.auth().signInWithCredential(cred)
.then((result) => {
// User signed in.
})
.catch((error) => {
// Error occurred.
});
Firebase does not support signInWithPopup in a React Native environment.
You can view a full list of supported environments on this page.
You can also submit a feature request for extended Firebase support for React Native here.
If you are using expo bare workflow or simple React native cli (or in simple words which contain android and ios folder) then simply use "React Native Firebase" library.
Here is the link https://rnfirebase.io/
But if you are using expo managed workflow(which donot contain android and ios folder ) then you have to follow below steps .
1.setup google developer account
use this guide to setup : https://docs.expo.dev/versions/latest/sdk/google/
Note that: use host.exp.exponent as the package name.
Another problem you may face in this step is generation of hash,which I also faced,the reason for that error is java dev kit(JDK) is not install ,so do install it before proceeding to this step.
2.Setup Firebase account
Simply setup firebase project as you set before, enable google sign in service
but this time the only change is you have to add client ID of your google developer account in (safest client id field) which will popup once you click on edit Google signin in firebase
look like this
3.Coding Part
import * as Google from 'expo-google-app-auth'; //imported from expo package
import {
GoogleAuthProvider,getAuth
} from 'firebase/auth';
import { initializeApp } from "firebase/app";
import { firebaseconfig } from '[your firebase credentials]';
const app=intitializeApp(firebaseconfig)
const auth=getAuth(app);
async function signInWithGoogleAsync() {
try {
const result = await Google.logInAsync({
androidClientId: 'cliend id from google dev console',
iosClientId: 'client id from google dev console for ios app(if you setup)',
scopes: ['profile', 'email'],
});
if (result.type === 'success') {
console.log(result)
const credential = GoogleAuthProvider.credential(result.idToken, result.accessToken);
// Sign in with credential from the Facebook user.
signInWithCredential(auth, credential)
.then(async result => {
console.log(result)
})
.catch(error => { console.log(error) });
return result.accessToken;
} else {
console.log("cancelled by user")
return { cancelled: true };
}
} catch (e) {
console.log(e);
return { error: true };
}//
}

React Native Google Signin idToken null

I am using react-native 0.60.5, with firebase authentication (using package react-native-firebase and react-native-google-signin).
Everything looks good to me and the google sign return an object with the user logged in, but the idToken is always null. I need to get the idToken to perform the authentication in firebase.
import { GoogleSignin } from 'react-native-google-signin';
export const googleLogin = async () => {
GoogleSignin.configure();
const userInfo = await GoogleSignin.signIn();
//here we have the issue. userInfo cotains all google user informations except the idToken
//userInfo.idToken is null
}
how can I fix the google-sign-in to return the idToken?
Add the web client id which is availble in Firebase authentication/signInmethod/Google:
function configureGoogleSign() {
GoogleSignin.configure({
webClientId: WEB_CLIENT_ID,
offlineAccess: false
})
}
This is working for me.
You have not specified webclientId.
and make sure to configure google signIn in useEffect Method so when you load the screen it already configured.
useEffect(() => {
GoogleSignin.configure({
webClientId:
'YOUR_WEBCLIENT_ID',
});
}, []);

Get current users access token from Firebase in React Native

I am trying to get the Firebase authentication access token within a React Native application so that I can authenticate my API calls to a custom server. The Firebase documentation says I should get this token by using auth().currentUser.getIdToken(); however currentUser returns null.
I've tried to use getIdToken() in multiple areas of the application. I know the access token is generated as I can see it in the logs while using expo (user.stsTokenManager.accessToken).
Why is currentUser returning null and how can I get the accessToken?
You need to wrap user.getIdToken() inside of firebase.auth().onAuthStateChanged for user to be available. You can then use jwtToken in your header to authenticate your API calls. You need to import your Firebase configuration file for this to work.
let jwtToken = firebase.auth().onAuthStateChanged(function(user) {
if (user) {
user.getIdToken().then(function(idToken) { // <------ Check this line
alert(idToken); // It shows the Firebase token now
return idToken;
});
}
});
Just putting await before will work too just like this:
await auth().currentUser.getIdToken();
getIdToken returns a promise
firebase.auth()
.signInWithCredential(credential)
.then(async data => {
const jwtToken = await data.user?.getIdToken();
console.log(jwtToken);
})
Hook example
Unfortunately, its not reliable to directly get the token. You first have to listen to the authentication state change event which fires upon initialization since its asynchronous.
import {auth} from '../utils/firebase'
import {useState, useEffect} from 'react'
export default function useToken() {
const [token, setToken] = useState('')
useEffect(() => {
return auth().onAuthStateChanged(user => {
if (user) {
user.getIdToken(true)
.then(latestToken => setToken(latestToken))
.catch(err => console.log(err))
}
})
}, [])
return token
}
then use like so in your functional component
const token = useToken()
useEffect(() => {
if (token) {
// go wild
}
}, [token])

Resources