I have install the react native firebase notificaiton ,notifications are working fine but when i try to send custom sound it wont work.
I find out that on Android version > 7 we have to create firebase channel in order to play custom sound but i dont know how to and where to create notification channel.
I have created two files inside the src folder of the root folder of my project where i handle notificatons.
1.LocalNotificationService.js
2.FcmService.js
Code for LocalNotificationService.js
import PushNotification from 'react-native-push-notification';
import {Platform} from 'react-native';
// import { notifications } from "react-native-firebase";
class LocalNotificationService {
configure = (onOpenNotification) => {
PushNotification.configure({
onRegister: function (token) {
console.log('[LocalNotificationService] onRegister', token);
},
onNotification: function (notification) {
console.log('[LocalNotificationService] onNotification', notification);
if (!notification?.data) {
return;
}
notification.userInteraction = true;
onOpenNotification(
Platform.OS === 'ios' ? notification.data.item : notification.data,
);
//Only call callback if not from foreground
if (Platform.OS === 'ios') {
notification.finish(PushNotificationIOS.FetchResult.NoData);
}
},
// IOS ONLY (optional): default: all - Permissions to register.
permissions: {
alert: true,
badge: true,
sound: true,
},
// Should the initial notification be popped automatically
// default: true
popInitialNotification: true,
/**
* (optional) default: true
* - Specified if permissions (ios) and token (android and ios) will requested or not,
* - if not, you must call PushNotificationsHandler.requestPermissions() later
* - if you are not using remote notification or do not have Firebase installed, use this:
* requestPermissions: Platform.OS === 'ios'
*/
requestPermissions: true,
});
};
unregister = () => {
PushNotification: this.unregister();
};
showNotification = (id, title, message, data = {}, options = {}) => {
PushNotification.localNotification({
...this.buildAndroidNotification(id, title, message, data, options),
title: title || '',
message: message || '',
playSound: options.playSound || true,
soundName: options.soundName || 'default',
// sound:'test',
userInteracsstion: false, /// boolean if the condition was opened by the user from the notification
});
};
buildAndroidNotification = (id, title, message, data = {}, options = {}) => {
return {
id: id,
// sound:"test",
autoCancel: true,
largeIcon: options.largeIcon || 'icon',
smallIcon: options.smallIcon || 'test_icon',
bigText: message || '',
subText: title || '',
color: 'green',
vibrate: options.vibrate || true,
vibration: options.vibration || 1000,
priority: options.priority || ' high',
importance: options.importance || 'high', // (options) set notification importance , default high
// data : data,
};
};
cancelAllLocalNotification = () => {
if (Platform.OS === 'ios') {
PushNotificationIOS.removedAllDeliveredNotification();
} else {
PushNotification.cancelAllLocalNotification();
}
};
removedDeliveredNotificationById = (notificationId) => {
console.log(
'[LocalNotificationService] removeDeliveredNotificationById: ',
notificationId,
);
PushNotification.cancelLocalNotfication({id: `${notificationId}`});
};
}
export const localNotificationService = new LocalNotificationService();
Code for FcmService.js
import messaging from '#react-native-firebase/messaging'
// import type {Notification,NotificationOpen} from 'react-native-firebase'
import { Platform } from 'react-native'
class FCMService {
register = (onRegister,onNotification,onOpenNotification) => {
this.checkPermission(onRegister)
this.createNotificationListeners(onRegister,onNotification,onOpenNotification)
}
registerAppWithFCM = async() => {
if(Platform.OS === "ios"){
await messaging().registerDeviceForRemoteMessages();
await messaging().setAutoInitEnabled(true)
}
}
checkPermission = (onRegister) => {
messaging().hasPermission()
.then(enabled => {
if(enabled) {
//User has permission
this.getToken(onRegister)
}
else{
//User Dont have permission
this.requestPermission(onRegister)
}
}).catch(error => {
console.log("Permission Rejected",error)
})
}
getToken = (onRegister) => {
messaging().getToken()
.then(fcmToken => {
if(fcmToken) {
onRegister(fcmToken)
}
else{
console.log("User Dont ave a Device Token")
}
}).catch(error => {
console.log("get token rejected", error)
})
}
requestPermission = (onRegister) => {
messaging().requestPermission()
.then(() => {
this.getToken(onRegister)
}).catch(error => {
console.log("Request Permission Rejected",error)
})
}
deleteToken = () => {
console.log("Delete Token")
messaging().deleteToken()
.catch(error => {
console.log("Delete token error",error)
})
}
createNotificationListeners = (onRegister, onNotification,onOpenNotification) => {
messaging().onNotificationOpenedApp(remoteMessage => {
console.log("onNotificationOpenedApp notification caused to open app")
if(remoteMessage){
const notification = remoteMessage.notification
onOpenNotification(notification)
}
});
//When the application is opened from a quite state.
messaging().getInitialNotification().then(remoteMessage => {
console.log("getInitialNotification notification caused to open app")
if(remoteMessage){
const notification = remoteMessage.notification
onOpenNotification(notification)
}
})
//Foreground state messages
this.messageListner = messaging().onMessage(async remoteMessage => {
console.log("A new FCM Message Arrived",remoteMessage)
if(remoteMessage){
let notification = null
if(Platform.OS === "ios") {
notification = remoteMessage.data.notification
}else{
notification = remoteMessage.notification
}
onNotification(notification)
}
})
}
unRegister = () => {
}
export const fcmService = new FCMService()
App.js
import React , {useEffect,useState} from 'react'
import {View,StyleSheet,Text,Button,TextInput} from 'react-native'
import {fcmService} from './src/FCMService'
import {localNotificationService} from './src/LocalNotificationService'
import auth from '#react-native-firebase/auth';
export default function App() {
useEffect(() => {
fcmService.registerAppWithFCM()
fcmService.register(onRegister,onNotification,onOpenNotification)
localNotificationService.configure(onOpenNotification)
function onRegister(token) {
console.log("[App] onRegister: ",token)
setTokenwa(token)
}
function onNotification(notify) {
console.log("[App] onNotification: ",notify)
const options = {
soundName : 'test',
playSound : true
}
localNotificationService.showNotification(
0,
notify.title,
notify.body,
notify,
options
)
}
function onOpenNotification(notify) {
console.log("[App] onOpenNotification : " , notify)
alert("Open Notification" + notify.body)
}
return () => {
console.log("[App] unRegister")
fcmService.unRegister()
localNotificationService.unregister()
}
}, [])
const [confirm, setConfirm] = useState(null);
const [code, setCode] = useState('');
const [tokenwa, setTokenwa] = useState('');
// Handle the button press
async function signInWithPhoneNumber(phoneNumber) {
const confirmation = await auth().signInWithPhoneNumber(phoneNumber);
setConfirm(confirmation);
}
async function confirmCode() {
try {
console.log("code send")
await confirm.confirm(code);
} catch (error) {
console.log('Invalid code.');
}
}
if (!confirm) {
return (
<Button
title="Phone Number Sign In"
onPress={() => signInWithPhoneNumber('+91 7769948296')}
/>
);
}
return (
<>
<Text>{tokenwa}</Text>
<View style={styles.container}>
<Text>Sample React Native Firebase </Text>
<Button title="Press Me" onPress={() => localNotificationService.cancelAllLocalNotification}></Button>
<TextInput value={code} placeholder="test" onChangeText={text => setCode(text)} />
<Button title="Confirm Code" onPress={() => confirmCode()} />
</View>
</>
)
}
const styles = StyleSheet.create({
container : {
flex : 1,
alignItems : 'center',
justifyContent : 'center'
}
})
Related
I recently purchased a Sunmi V2 device for a client, and I am trying to print something when I receive a notification from expo-notification using react-native. I have successfully implemented this in another application, but I am having difficulty getting it to work on the Sunmi V2 device.
Here is the approach I took: On my StackNavigator.js component, I have...
const { user } = useAuth();
const { registerForPushNotificationsAsync, handleNotifications, handleNotificationsResponse } = useNotifications();
useEffect(() => {
registerForPushNotificationsAsync();
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: false,
}),
});
const responseListener =
Notifications.addNotificationResponseReceivedListener(
handleNotificationsResponse
);
return () => {
if (responseListener)
Notifications.removeNotificationSubscription(responseListener)
}
}, [user])
Here is the useNotification component:
export const useNotifications = () => {
const { user } = useAuth();
const registerForPushNotificationsAsync = async () => {
if (Device.isDevice) {
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
alert('Failed to get push token for push notification!');
// console.log('Failed to get push token for push notification!')
return;
}
try {
const token = (await Notifications.getExpoPushTokenAsync()).data;
Alert.alert("TOKEN: ", token);
if (user) {
const useRef = doc(db, "users", user.uid);
if (token !== undefined) {
updateDoc(useRef, {
pushTokenExpo: token
});
}
}
} catch (error) {
Alert.alert(error)
}
} else {
if (user) {
alert('Must use physical device for Push Notifications', user.uid)
}
alert('Must use physical device for Push Notifications');
console.log('Must use physical device for Push Notifications')
}
if (Platform.OS === 'android') {
Notifications.setNotificationChannelAsync('default', {
name: 'default',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
});
}
};
const handleNotifications = (notification: Notifications.Notification) => {
console.log('NEW NOTIFICACTION')
};
const handleNotificationsResponse = (
response: Notifications.NotificationResponse
) => {
console.log(response.notification.request.content.data)
// HERE DO WHAT YOU WHAT AFTER CLICK ON NOTIF
}
return { registerForPushNotificationsAsync, handleNotifications, handleNotificationsResponse }
}
When I run this code on my device, it either crashes the app or does not update the Firebase collection 'user'. How can I fix this issue?
I have implemented firebase push notifications using Firebase and react-native-push-notification package.
Currently, I have implemented action buttons according to the click_action of each push notification. Once the app is in the foreground it works and once the app is killed state or background action buttons are not displaying.
My FCM helper file
class FCMServiceHelper {
register = (onRegister, onNotification, onOpenNotification) => {
this.checkPermission(onRegister);
this.createNotificationListeners(
onRegister,
onNotification,
onOpenNotification,
);
};
registerAppWithFCM = async () => {
if (Platform.OS === 'ios') {
await messaging().registerDeviceForRemoteMessages();
await messaging().setAutoInitEnabled(true);
}
};
checkPermission = (onRegister) => {
messaging()
.hasPermission()
.then((enabled) => {
if (enabled) {
// User has permissions
this.deleteToken()
this.getToken(onRegister);
} else {
// User doesn't have permission
this.requestPermission(onRegister);
}
})
.catch((error) => {
console.log('[FCMService] Permission rejected ', error);
});
};
getToken = (onRegister) => {
messaging()
.getToken(undefined,'*')
.then((fcmToken) => {
if (fcmToken) {
onRegister(fcmToken);
} else {
console.log('[FCMService] User does not have a device token');
}
})
.catch((error) => {
console.log('[FCMService] getToken rejected ', error);
});
};
requestPermission = (onRegister) => {
messaging()
.requestPermission()
.then(() => {
this.deleteToken()
this.getToken(onRegister);
})
.catch((error) => {
console.log('[FCMService] Request Permission rejected ', error);
});
};
deleteToken = () => {
console.log('[FCMService] deleteToken ');
messaging()
.deleteToken(undefined,'*')
.catch((error) => {
console.log('[FCMService] Delete token error ', error);
});
};
unregisterDeviceFromNotifications = () => {
console.log('[FCMService] unreg ');
messaging()
.unregisterDeviceForRemoteMessages()
.catch((error) => {
console.log('[FCMService] Unreg device ', error);
});
};
createNotificationListeners = (
onRegister,
onNotification,
onOpenNotification,
) => {
// When the application is running, but in the background
messaging().onNotificationOpenedApp((remoteMessage) => {
console.log(
'[FCMService] onNotificationOpenedApp Notification caused app to open from background state:',
remoteMessage,
);
if (remoteMessage) {
let notification = null;
let data = remoteMessage.data;
let openFromKilling = {"checked" : true}
notification = remoteMessage.notification;
notification.data = data;
notification.checking = openFromKilling;
onOpenNotification(notification);
}
});
// When the application is opened from a quit state.
messaging()
.getInitialNotification()
.then((remoteMessage) => {
console.log(
'[FCMService] getInitialNotification Notification caused app to open from quit state:',
remoteMessage,
);
if (remoteMessage) {
let notification = null;
let data = remoteMessage.data;
let openFromKilling = {"checked" : true}
notification = remoteMessage.notification;
notification.data = data;
notification.checking = openFromKilling;
onOpenNotification(notification);
}
});
// Foreground state messages
this.messageListener = messaging().onMessage(async (remoteMessage) => {
console.log(
'[FCMService] A new FCM message arrived! foreground',
remoteMessage,
);
if (remoteMessage) {
let notification = null;
let data = remoteMessage.data;
if (Platform.OS === 'ios') {
notification = remoteMessage.notification;
} else {
notification = remoteMessage.notification;
}
notification.data = data;
onNotification(notification);
// onOpenNotification(remoteMessage.data);
}
});
// Triggered when have new token
// messaging().onTokenRefresh((fcmToken) => {
// alert('REFRESH TOKEN');
// console.log('[FCMService] New token refresh: ', fcmToken);
// onRegister(fcmToken);
// });
};
unRegister = () => {
// if(this.messageListener){
this.messageListener();
// }
};
}
My notification Handler file
fcmService.registerAppWithFCM();
fcmService.register(onRegister, onNotification, onOpenNotificaion , onAction);
localNotificationService.configure(onOpenNotificaion,onAction);
function onRegister(token) {
saveFCMToken(token);
}
if (Platform.OS == 'android') {
localNotificationService.createChannelAndroid('wapp');
}
function onNotification(notify) {
var RandomNumber = Math.floor(Math.random() * 100) + 1;
let actionData = [];
if(Platform.OS == 'android'){
if(notify.data.click_action == 'alert_dashboard'){
actionData = ["Update contact number"]
}else if(notify.data.click_action == 'account_edit'){
actionData = ["Update Email"]
}
}
const options = {
soundName: 'default',
playSound: true,
};
localNotificationService.showNotification(
RandomNumber,
notify.title,
Platform.OS == 'android' ? notify.body : notify.body,
notify,
options,
'wapp',
actionData
);
}
function onAction(notification) {
console.log ('Notification action received:');
console.log(notification.action);
console.log(notification);
}
Notification Helper File
class NotificationHelper {
configure = (onOpenNotification) => {
PushNotification.configure({
onRegister: function (token) {
console.log('[NotificationManager] onRegister token:', token.token);
},
onNotification: function (notification) {
console.log('[NotificationManager] onNotification:', notification);
if (Platform.OS === 'ios') {
if (notification.data.openedInForeground) {
notification.userInteraction = true;
}
}
if (notification.userInteraction) {
onOpenNotification(notification);
} else {
onNotification(notification);
}
if (Platform.OS === 'android') {
notification.userInteraction = true;
}
// Only call callback if not from foreground
if (Platform.OS === 'ios') {
if (!notification.data.openedInForeground) {
notification.finish('backgroundFetchResultNoData');
}
} else {
notification.finish('backgroundFetchResultNoData');
}
},
onAction: function (notification) {
// alert(notification)
console.log("ACTION:", notification.action);
console.log("NOTIFICATION:", notification);
// notification.userInteraction = true;
// PushNotification.invokeApp(notification);
},
});
};
unregister = () => {
PushNotification.unregister();
};
createChannelAndroid = (channel) => {
PushNotification.createChannel(
{
channelId: channel, // (required)
channelName: 'My channel', // (required)
channelDescription: 'A channel to categorise your notifications', // (optional) default: undefined.
playSound: false, // (optional) default: true
soundName: 'default', // (optional) See `soundName` parameter of `localNotification` function
importance: 4, // (optional) default: 4. Int value of the Android notification importance
vibrate: true, // (optional) default: true. Creates the default vibration patten if true.
},
(created) => console.log(`createChannel returned '${created}'`), // (optional) callback returns whether the channel was created, false means it already existed.
);
};
showNotification = (id, title, message, data = {}, options = {}, channel , testData) => {
PushNotification.localNotification({
/* Android Only Properties */
...this.buildAndroidNotification(
id,
title,
message,
data,
options,
channel,
testData
),
/* iOS and Android properties */
...this.buildIOSNotification(id, title, message, data, options),
/* iOS and Android properties */
title: title || '',
message: message || '',
playSound: options.playSound || true,
soundName: options.soundName || 'default',
userInteraction: true, // BOOLEAN: If the notification was opened by the user from the notification area or not
});
};
buildAndroidNotification = (
id,
title,
message,
data = {},
options = {},
channel,
testData
) => {
console.log('TEST DATA -> ',data)
return {
showWhen: true, // This is probably not needed, since default value is TRUE.
when: new Date().getTime(),
group: "wapp",
groupSummary: true,
channelId: channel,
id: id,
autoCancel: true,
largeIcon: options.largeIcon || 'ic_launcher',
smallIcon: options.smallIcon || 'ic_launcher',
bigText: message || '',
subText: title || '',
vibrate: options.vibrate || true,
vibration: options.vibration || 300,
priority: options.priority || 'high',
importance: options.importance || 'high', // (optional) set notification importance, default: high,
data: data,
actions:testData,
// invokeApp:false,
};
};
buildIOSNotification = (id, title, message, data = {}, options = {}) => {
return {
alertAction: options.alertAction || 'view',
alertBody: message || '',
category: options.category || '',
userInfo: {
id: id,
item: data,
},
};
};
cancelAllLocalNotifications = () => {
if (Platform.OS === 'ios') {
PushNotificationIOS.removeAllDeliveredNotifications();
} else {
PushNotification.cancelAllLocalNotifications();
}
};
removeDeliveredNotificationByID = (notificationId) => {
console.log(
'[LocalNotificationService] removeDeliveredNotificationByID: ',
notificationId,
);
PushNotification.cancelLocalNotifications({id: `${notificationId}`});
};
}
My app index.js file
/**
* #format
*/
import React from 'react';
import 'react-native-gesture-handler';
import { AppRegistry, LogBox, YellowBox } from 'react-native';
import App from './app/Entrypoint';
import { name as appName } from './app.json';
import { enableScreens } from 'react-native-screens';
import messaging from '#react-native-firebase/messaging';
import { backgroundGeo, checkLocationLogics } from './app/helpers/backgroundLocationTracking';
import env from 'react-native-config';
enableScreens();
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('Message handled in the background!', remoteMessage);
});
function HeadlessCheck({ isHeadless }) {
if (isHeadless) {
// App has been launched in the background by iOS, ignore
return null;
}
return <App />;
}
AppRegistry.registerComponent(appName, () => HeadlessCheck);
Try calling the showNotification method inside setBackgroundMessageHandler , this gets called when the app is not in foreground or killed state
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('Message handled in the background!', remoteMessage);
const options = {
soundName: 'default',
playSound: true,
};
const {title, body, data} = remoteMessage;
localNotificationService.showNotification(
title,
body,
data,
options,
}
});
I am using react-native-notifee and react-native-firebase v11.2.0
The problem is, when I press the notification during the app is in foreground, it is not navigating to the required screen. It is working fine while my app is in background.
notification.js
import notifee, {
AndroidCategory,
AndroidImportance,
AndroidStyle,
EventType
} from '#notifee/react-native';
import messaging from '#react-native-firebase/messaging';
import { requestNotificationPermission } from '../helpers/permissions';
import * as RootNavigator from '../navigator/NavigationRef';
const createChannel = async () => {
try {
const channel = await notifee.createChannel({
id: 'default_channel',
name: 'Default Channel',
description: 'Default notification channel',
sound: 'default',
importance: AndroidImportance.HIGH,
vibration: false
});
return channel;
} catch (error) {
console.log('Error in creating notification channel', error);
return 'default_channel';
}
};
export const requestPermissionForNotifications = async () => {
const hasPermission = await messaging().hasPermission();
if (!hasPermission) {
// checking for ios notification permission;
const isGranted = await requestNotificationPermission();
if (isGranted < 1) return false;
}
// always request permisssion even if it is granted
return messaging()
.requestPermission()
.then(() => console.log('granted'))
.catch(err => console.log('error in granted', err));
};
export const displayNotification = async (
title,
body,
notificationId,
imageUrl = null
) => {
try {
// always check permisssion even if it has access to register the app to
// receive the push notification as stated in documentation
await requestPermissionForNotifications();
const channel = await createChannel();
let notificationObj = {
title,
body,
id: notificationId,
android: {
channelId: channel,
smallIcon: 'ic_launcher',
sound: 'default',
category: AndroidCategory.ALARM,
importance: AndroidImportance.HIGH,
pressAction: {
id: 'default'
},
timestamp: Date.now(),
showTimestamp: true
},
ios: {
sound: 'default',
attachments: [
{
url: imageUrl
}
]
}
};
await notifee.displayNotification(notificationObj);
} catch (error) {
console.log('Error in displaying notification', error);
}
};
export const onMessageReceived = async message => {
const { messageId, notification } = message;
return displayNotification(
notification.title,
notification.body,
messageId,
notification.image
);
};
export const notificationPressActionEventListener = async ({
type,
detail
}) => {
try {
const { navigate } = RootNavigator.navigationRef.current;
switch (type) {
case EventType.PRESS:
navigate('SampleStackScreen');
break;
default:
break;
}
} catch (error) {
console.log('Error in navigation', error);
}
return null;
};
export const getDeviceToken = async () => {
const token = await messaging().getToken();
if (token) return token;
return null;
};
NavigationRef.js
import * as React from 'react';
export const navigationRef = React.createRef();
Listeners in Home.js
componentDidMount() {
this.notificationListener = messaging().onMessage(onMessageReceived);
this.notificationActionEventListener = notifee.onForegroundEvent(
notificationPressActionEventListener
);
}
Listeners in index.js
/** #format */
import messaging from '#react-native-firebase/messaging';
import notifee from '#notifee/react-native';
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
import App from './src/App';
import {
notificationPressActionEventListener,
onMessageReceived
} from './src/firebase/notification';
notifee.onBackgroundEvent(notificationPressActionEventListener);
messaging().setBackgroundMessageHandler(onMessageReceived);
AppRegistry.registerComponent(appName, () => App);
Im using React navigation version 5 with Firebase integration. Using that I'm trying to make authentication flow. I almost done a Signing flow and it works Perfect, but after Firebase Signed in it will not render and it is in still same SignIn Page in mobile. PFB the Code of My AppRouter Page.
import React, { Component, useEffect } from 'react'
import { View, Platform, TouchableOpacity, Text, Image, Dimensions, Slider, Button, ActivityIndicator, Alert } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
import RootStackScreen from '../Router/RootStackScreen'
import HomeStackScreen from './TabScreens'
import AsyncStorage from '#react-native-community/async-storage';
import { Authcontext } from '../Components/context'
import auth from '#react-native-firebase/auth';
import Home from '../Pages/OnboardingScreen/Home';
var { height, width } = Dimensions.get('window')
const Drawer = createDrawerNavigator();
const AppRouter = ({navigation}) => {
const initialoginState = {
isLoading: true,
email: null,
userToken: null
};
const loginReducer = (prevState, action) => {
switch (action.type) {
case 'RETRIVE_TOKEN':
return {
...prevState,
userToken: action.token,
isLoading: false,
};
case 'LOGIN':
return {
...prevState,
email: action.id,
userToken: action.token,
isLoading: false,
};
case 'LOGOUT':
return {
...prevState,
email: null,
userToken: null,
isLoading: false,
};
case 'REGISTER':
return {
...prevState,
email: action.id,
userToken: action.token,
isLoading: false,
};
}
}
const [loginState, dispatch] = React.useReducer(loginReducer, initialoginState)
const authContext = React.useMemo(() => ({
signIn: async (email, password) => {
let userToken;
userToken = null;
if (email !== '' && password !== '') {
auth().signInWithEmailAndPassword(email, password)
.then(async (success) => {
try {
await AsyncStorage.setItem('userToken', success.user.uid)
} catch (e) {
console.log(e)
Alert.alert('Shopping', e)
}
})
.catch(error => {
if (error.code === 'auth/email-already-in-use') {
Alert.alert('Shopping', 'That email address is already in use!')
}
if (error.code === 'auth/invalid-email') {
Alert.alert('Shopping', 'That email address is invalid!')
}
Alert.alert('Shopping', error.code)
});
} else {
Alert.alert('Shopping', 'Invalid Email / Password')
}
dispatch({ type: 'LOGIN', id: email, token: userToken , isLoading: false})
},
signUp: () => {
//Pending
},
signOut: async () => {
try {
await AsyncStorage.removeItem('userToken')
} catch (e) {
console.log(e)
}
dispatch({ type: 'LOGOUT' })
},
}), [])
useEffect(() => {
setTimeout(async () => {
let userToken;
userToken = null;
try {
userToken = await AsyncStorage.getItem('userToken')
console.log('token', userToken)
} catch (e) {
console.log(e)
}
dispatch({ type: 'RETRIVE_TOKEN', token: userToken })
}, 1000)
}, []);
if (loginState.isLoading) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator size="large" color="black" />
</View>
)
}
return (
<Authcontext.Provider value={authContext}>
<NavigationContainer>
{loginState.userToken !== null ?
(
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeStackScreen} /> //Dashboard Screens
</Drawer.Navigator>
) :
<RootStackScreen /> //Authentication Screens
}
</NavigationContainer>
</Authcontext.Provider>
)
}
export default AppRouter
Thanks in Advance
You need to dispatch login inner signInWithEmailAndPassword then or userToken always will be null because of the async.
const authContext = React.useMemo(() => ({
signIn: async (email, password) => {
let userToken;
userToken = null;
if (email !== '' && password !== '') {
auth().signInWithEmailAndPassword(email, password)
.then(async (success) => {
dispatch({ type: 'LOGIN', id: email, token: userToken , isLoading: false})
try {
await AsyncStorage.setItem('userToken', success.user.uid)
} catch (e) {
console.log(e)
Alert.alert('Shopping', e)
}
})
.catch(error => {
if (error.code === 'auth/email-already-in-use') {
Alert.alert('Shopping', 'That email address is already in use!')
}
if (error.code === 'auth/invalid-email') {
Alert.alert('Shopping', 'That email address is invalid!')
}
Alert.alert('Shopping', error.code)
});
} else {
Alert.alert('Shopping', 'Invalid Email / Password')
}
},
signUp: () => {
//Pending
},
signOut: async () => {
try {
await AsyncStorage.removeItem('userToken')
} catch (e) {
console.log(e)
}
dispatch({ type: 'LOGOUT' })
},
}), [])
i'm using react native firebase and i'm getting notification whenever is needed, and these notifications have some data to navigate to specific screen.
i used the firebase documentation to implement the functionality but it's not working as it's supposed to
Here is the document i've used Firebase & React-Navigation
and my code looks something like this :
const Stack = createStackNavigator();
const Router = () => {
const navigation = useNavigation();
const [loading, setLoading] = useState(true);
const [initialRoute, setInitialRoute] = useState('Splash');
useEffect(() => {
//fcm
registerAppWithFCM();
// checkRNFBPermission();
const unsubscribe = messaging().onMessage(async remoteMessage => {
console.log('remote DATAAAAAAAAAAAAAAAAAAAAAAAA : ',remoteMessage.data);
// switch (remoteMessage.data.screen) {
// case 'answer':{
// console.log('inside switch condition 1 !!!!!!!!!!!!!');
// useNavigation().navigate('Profile');
// break;
// }
// case 'AnswerQuestion':{
// console.log('inside switch condition 2 !!!!!!!!!!!!!');
// useNavigation().navigate('Profile');
// break;
// }
// default:
// break;
// }
// Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
// const owner = JSON.parse(remoteMessage.data.owner);
// const user = JSON.parse(remoteMessage.data.user);
// const picture = JSON.parse(remoteMessage.data.picture);
});
// Assume a message-notification contains a "type" property in the data payload of the screen to open
messaging().onNotificationOpenedApp(remoteMessage => {
console.log(
'Notification caused app to open from background state:',
remoteMessage.notification,
);
navigation.navigate('Profile');
});
// Check whether an initial notification is available
messaging()
.getInitialNotification()
.then(remoteMessage => {
if (remoteMessage) {
console.log(
'Notification caused app to open from quit state:',
remoteMessage.data, //notification
);
}
setLoading(false);
});
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
});
return unsubscribe;
//fcm
}, []);
//fcm
checkRNFBPermission = async() => {
const enabled = await messaging().hasPermission();
if(enabled){
messaging()
.getToken()
.then(token => {
// console.log('deviceeeee fcm token ------> ', token);
});
}else{
requestUserPermission();
}
}
registerAppWithFCM = async() => {
await messaging().registerDeviceForRemoteMessages();
}
requestUserPermission = async() => {
const settings = await messaging().requestPermission();
if (settings) {
console.log('Permission settings:', settings);
}
}
//fcm
renderLoading = () => (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Domanda</Text>
<ActivityIndicator size='large' color={colors.darkerTeal} />
</View>
);
//firebase
if (loading) {
return null;
}
//firebase
return(
<Provider store={store}>
<PersistGate persistor={persistor} loading={this.renderLoading()}>
<Root>
<NavigationContainer>
<Stack.Navigator initialRouteName={initialRoute} headerMode="none">
<Stack.Screen name="Splash" component={Splash} />
<Stack.Screen name="Login" component={Login} />
<Stack.Screen name="Main" component={Main} />
<Stack.Screen name="AppIntro" component={AppIntro} />
<Stack.Screen name="Tags" component={Tags} />
<Stack.Screen name="Answers" component={Answers} />
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="EditInfo" component={EditInfo} />
<Stack.Screen name="ChangePassword" component={ChangePassword} />
<Stack.Screen name="AnswerQuestion" component={AnswerQuestion} />
<Stack.Screen name="ContactUs" component={ContactUs} />
</Stack.Navigator>
</NavigationContainer>
</Root>
</PersistGate>
</Provider>
)
};
export default Router;
but when i add usenavigation and i want to use it it throws this error:
Error: We couldn't find a navigation object. Is your component inside a screen in a navigator?
i can not use navigation.navigate('Profile'); to navigate to a specific screen.
You're receiving the message in App.js whats outside of your StackNavigator.
You can use a ref to use the navigation property of the navigator
define the navigator in the top of you app.js
var navigator = null;
then add an ref to the navigator
<Stack.Navigator
initialRouteName={initialRoute}
headerMode="none"
ref={nav => {
navigator = nav;
}}
>
and push your route inside the receive method
navigator.dispatch(
NavigationActions.navigate({
routeName: 'theRoute',
params: {},
}),
);
Was struggling 4 hours...
Some were in component, were navigation is available (in my case "Home screen")
// last import
import { ScrollWrapper } from './styles'
export const navigationRef = React.createRef();
export const isReadyRef = React.createRef();
export function navigate(name, params) {
if (isReadyRef.current && navigationRef.current) {
// Perform navigation if the app has mounted
navigationRef.current.navigate(name, params);
} else {
console.log(' else [ELSE] --- ')
// You can decide what to do if the app hasn't mounted
// You can ignore this, or add these actions to a queue you can call later
}
}
// component start
export const SocialHomeScreen = () => {...
In App.js
import { navigate, navigationRef, isReadyRef } from './screens/PeopleAroundYou/index'
// .... navigators
const App = () => {
const [isAuth, setIsAuth] = useState(false)
AsyncStorage.getItem('pushNotify').then(value => {
console.log('value --- ', value)
console.log('JSON.parse(value) --- ', JSON.parse(value))
}).catch(error => {
console.log('error --- ', error)
})
// foreground message arrived
useEffect(() => {
return messaging().onMessage(async remoteMessage => {
const { data, notification } = remoteMessage
if (data.type === 'activity-check-in') {
console.log(' A new FCM message arrived! --- ')
console.log('data --- ', data)
console.log('notification --- ', notification)
console.log(' navigator --- ', navigate)
console.log('navigationRef.current.getRootState() --- ', navigationRef.current.getRootState())
switch (data.category) {
case 'fitness':
// navigate to nested screen
navigate(routes.Fitness, {
screen: routes.ActivityDetails,
params: { activityId: data.eventId}
})
break
case 'companionship':
navigate(routes.Companionships, {
screen: routes.ActivityDetails,
params: { activityId: data.eventId}
})
break
case 'volunteering':
navigate(routes.Volunteering, {
screen: routes.ActivityDetails,
params: { activityId: data.eventId}
})
break
case 'wellbeing':
navigate(routes.Wellbeing, {
screen: routes.ActivityDetails,
params: { activityId: data.eventId}
})
break
}
}
})
}, [])
useEffect(() => {
SplashScreen.hide()
fcmService.registerAppWithFCM()
fcmService.register(onRegister, onNotification, onOpenNotification)
localNotificationService.configure(onOpenNotification)
function onRegister(token) {
console.log('[App] onRegister: ', token)
}
function onNotification(notify) {
console.log('[App] onNotification: ', notify)
const options = {
soundName: 'default',
playSound: true, //,
// largeIcon: 'ic_launcher', // add icon large for Android (Link: app/src/main/mipmap)
// smallIcon: 'ic_launcher' // add icon small for Android (Link: app/src/main/mipmap)
}
localNotificationService.showNotification(
0,
notify.title,
notify.body,
notify,
options,
)
}
function onOpenNotification(notify) {
console.log('[App] onOpenNotification: ', notify)
Alert.alert('Open Notification: ' + notify.body)
}
return () => {
console.log('[App] unRegister')
fcmService.unRegister()
localNotificationService.unregister()
}
}, [])
const authContext = useMemo(() => {
return {
login: () => {
setIsAuth(true)
},
logout: () => {
setIsAuth(false)
},
}
})
return (
<AuthContext.Provider value={authContext}>
<ThemeProvider theme={theme}>
<NavigationContainer
ref={navigationRef}
onReady={() => {
isReadyRef.current = true
}}
linking={linking}
fallback={
<View style={{ justifyContent: 'center', alignItems: 'center' }}>
<Loader loading size='large' color='#61A5C8'/>
</View>
}
>
{isAuth ? <AuthorizedTabs /> : <NonAuthorizedStack/>}
</NavigationContainer>
</ThemeProvider>
</AuthContext.Provider>
)
}