How to display Local Notification in Background - react-native

I am trying to set up a local notifications with certain time to pushed for user when the time arrives.
I want help in two steps :
1) How to let that notifications fired while the app is in Background
2) How to add a sound to notifications when fired
Also I want to know if the approach I am using is right ?
import React, {useEffect, useState} from 'react';
import { Text, View, Button, Vibration, Platform , Alert} from 'react-native';
import {Notifications} from 'expo';
import * as Permissions from 'expo-permissions';
import Constants from 'expo-constants';
const LocalNotificationsScreen = () => {
const [notification, setNotification] = useState({});
useEffect(() => {
askPermissions();
}, []);
let Times = [
{time: '3:16' , name : 'test1'}, {time : '0:7', name : 'test2'},
{time : '0:9', name : 'test3'}, {time : '2:8' , name : 'test4'},
{time : '3:37' , name : 'test5'} , {time : '3:39', name : 'test6'}
];
const askPermissions = async () => {
const { status: existingStatus } = await Permissions.getAsync(Permissions.NOTIFICATIONS);
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
finalStatus = status;
}
if (finalStatus !== 'granted') {
return false;
}
return true;
};
const localNotification = {
id : 1,
title : 'Testing',
body : 'The body ',
data: { name : 'This is the data'},
ios : {
sound : true,
_displayInForeground : true
},
android : {
name : 'Sound',
sound : true,
vibrate : [ 0, 250, 250, 250 ],
repeat : false
},
userText: 'Hi from Notfications'
}
const schedulingOptions = {
time : (new Date()).getTime() + 5000,
}
console.log((new Date()).getTime())
const currentTime = `${new Date().getHours()}:${new Date().getMinutes()}`;
console.log(currentTime);
const pushTime = () => {
return Times.map((t) => {
if (t.time === currentTime) {
let notificationId =
Notifications.scheduleLocalNotificationAsync(localNotification, schedulingOptions);
console.log(notificationId);
setTimeout(function () {
Notifications.cancelAllScheduledNotificationsAsync()
}, 8000);
}
})
}
pushTime();
Notifications.addListener(
notification => {
Vibration.vibrate();
console.log(notification);
setNotification(notification);
}
)
return (
<View>
<Text>LocalNotifications </Text>
</View>
);
}
export default LocalNotificationsScreen;

I have no idea with expo but I have used local notifications in my app by using this package..
Check local notifications section... I hope it will work with expo..
https://github.com/zo0r/react-native-push-notification

You can use notification schedule of react-native-firebase:
https://github.com/invertase/react-native-firebase-docs/blob/master/docs/notifications/scheduling-notifications.md
Install and setup react-native-firebase
create notification and schedule as below
Create a notificationListener to listen and trigger to show notification.
Setup a schedule notification firebase.notifications().scheduleNotification(notification, {
fireDate: date.getTime(),
}), notificationListener will be triggered when fireDate comes
.setSound(channel.sound) set sound for notification
import firebase from 'react-native-firebase';
// Build notification
const notificationListener = firebase
.notifications()
.onNotification(notification => {
const {title, body, data} = notification;
console.log('onNotification:', notification);
if (typeof onNotification == 'function')
onNotification(title, body, data);
const localNotification = new firebase.notifications.Notification({
sound: 'sound',
show_in_foreground: true,
show_in_background: true,
})
.setSound(channel.sound)
.setNotificationId(notification.notificationId)
.setTitle(title)
.setBody(body)
.setData(data)
.android.setChannelId('#string/default_notification_channel_id') // e.g. the id you chose above
.android.setSmallIcon('#mipmap/ic_launcher') // create this icon in Android Studio
.android.setColor('#000000') // you can set a color here
.android.setPriority(firebase.notifications.Android.Priority.High);
firebase
.notifications()
.displayNotification(localNotification)
.then(() => {
cancelNotification(notification.notificationId);
})
.catch(err => console.error(err));
});
// Schedule the notification for 1 minute in the future
const date = new Date();
date.setMinutes(date.getMinutes() + 1);
firebase.notifications().scheduleNotification(notification, {
fireDate: date.getTime(),
})

Related

React Native useEffect not run when app first opened

I am trying to make an app where the USER_ID is loaded from the device's local storage if found, otherwise, a new id is generated and stored in the local storage. I am trying to make use of React useContext() to make the USER_ID visible to the whole app after it is first run.
import React, {useEffect, useState} from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
import uuid from 'react-native-uuid';
export const UserIdContext = React.createContext('undef');
export const UserIdProvider = ({children}) => {
const [userId, setUserId] = useState('');
useEffect(() => {
async function getOrInitUserId() {
try {
let temp = await AsyncStorage.getItem('USER_ID');
if (temp == null) {
temp = uuid.v4();
await AsyncStorage.setItem('USER_ID', uuid.v4());
console.log('USER_ID Generated: ' + temp);
} else {
console.log('USER_ID Found: ' + temp);
}
setUserId(temp);
} catch (error) {
console.error(error);
}
}
if (!userId) {
getOrInitUserId();
}
});
return (
<UserIdContext.Provider value={userId}>{children}</UserIdContext.Provider>
);
};
export const useUserId = () => React.useContext(UserIdContext);
The provider is used as below:
const App = () => {
useEffect(() => {
....
});
return (
<UserIdProvider>
...contents of app...
</UserIdProvider>
);
};
export default App;
However, the useEffect() of < UserIdProvider /> is not run as the app is launched for the first time after being installed on a device, as there is no log on the console. After the app is closed/quit and relaunched, the console log a USER_ID found, instead of USER_ID generated.
Add 2nd argument as [] so it will render only once. Otherwise, it will render every time when any state will be updated.
const App = () => {
useEffect(() => {
....
},[]);
return (
<UserIdProvider>
...contents of app...
</UserIdProvider>
);
};
export default App;
In order to trigger useEffect when first run you should enter [] as prop like this:
useEffect(() => {
async function getOrInitUserId() {
try {
let temp = await AsyncStorage.getItem('USER_ID');
if (temp == null) {
temp = uuid.v4();
await AsyncStorage.setItem('USER_ID', uuid.v4());
console.log('USER_ID Generated: ' + temp);
} else {
console.log('USER_ID Found: ' + temp);
}
setUserId(temp);
} catch (error) {
console.error(error);
}
}
if (!userId) {
getOrInitUserId();
}
}, []);

Voximplant push notifications - React Native

I have successfully managed to get remote messages from Firebase console to send messages when my app is in the QUIT state, FOREGREOUND state and in BACKGROUND state. So all the Firebase setup is working PERFECTLY in my React Native app (Android).
I managed to get Firebase Push Notifications working very well, using the latest Firebase messaging library.
The Version 5 'react-native-firebase' is deprecated and no longer supported, we have to use Version 6 '#react-native-firebase/messaging' for messaging and 'react-native-push-notification' (for the channel stuff and notification). This is good for the future in all React Native work, as the old version is becoming obsolete and Firebase isn't supporting it.
The google-services.json works fine and the push certificate is also successfully uploaded in the Voximplant panel.
I can already make calls when both Voximplant users are on the app (i.e. app states are in the FOREGROUND).
The MAIN reason for needing the push, is to allow another Voximplant user to receive a call from the app QUIT and BACKGROUND state.
What seems to be missing?
Here's my code:
package.json
"#react-native-firebase/app": "^15.2.0",
"#react-native-firebase/messaging": "^15.2.0",
"react-native-voximplant": "^1.28.0",
index.js
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import messaging from '#react-native-firebase/messaging';
import PushBackground from './manager/PushBackground';
//Set handler
messaging().setBackgroundMessageHandler(PushBackground);
// NOT USING (but still works with pure firebase incoming push notifications)
//messaging().setBackgroundMessageHandler(async remoteMessage => {
// console.log('Message handled in the background!', remoteMessage);
//});
AppRegistry.registerComponent(appName, () => App);
App.js
import React, { useState, useEffect } from "react";
import { requestUserPermission, NotificationListener, CancelNotifications } from "./manager/PushManager";
function App() {
useEffect(() => {
//Firebase messaging/notifications
requestUserPermission(); //gets "fcmtoken"
NotificationListener(); //sets up firebase listeners for (QUIT, FOREGROUND, BACKGROUND App states)
CancelNotifications(); //Cancels notifications after received
}, []);
return(...all UI stuff...)
export default App;
}
loginScreen.js
import React, { Component, useEffect, useState, useContext } from "react";
import { Voximplant } from 'react-native-voximplant';
import { APP_NAME, ACC_NAME } from "../../constant/constants";
import AsyncStorage from '#react-native-async-storage/async-storage';
const LoginScreen = ({ navigation }) => {
const voximplant = Voximplant.getInstance();
useEffect(() => {
const connect = async() => {
const status = await voximplant.getClientState();
if(status == Voximplant.ClientState.DISCONNECTED){
await voximplant.connect();
console.log("Status: Voximplant Client DISCONNECTED: " + status);
}
else if (status == Voximplant.ClientState.LOGGED_IN) {
console.log("Status: Voximplant Client LOGGED IN: " + status);
}
const signIn = async () => {
try{
const fqUsername = `${username}#${APP_NAME}.${ACC_NAME}.voximplant.com`;
console.log(fqUsername);
let authResult = await voximplant.login(fqUsername, password);
const loginTokens = authResult.tokens;
console.log("Log In Successful. Token " + JSON.stringify(loginTokens, null, 2));
//We have fcmtoken (firebase) from App.js loading up, so now register it with Voximplant cloud
const fcmToken = await AsyncStorage.getItem("fcmtoken");
//Register it with Voximplant
if(fcmToken != null){
voximplant.registerPushNotificationsToken(fcmToken);
}
//Set fqUsername for Voximplant
await AsyncStorage.setItem("fqUsernameKey", fqUsername);
//Set accessToken for Voximplant
await AsyncStorage.setItem('accessTokenKey', authResult.tokens.accessToken);
}
catch(e) {
console.log("signIn issue: "+ e);
Alert.alert("Already Logged In", `Error code: ${e.code}`);
}
}
return(...UI stuff...)
}
export default LoginScreen;
PushBackground.js
'use strict';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { Voximplant } from 'react-native-voximplant';
export default async (message) => {
console.log('PushBackground android: notification: ' + JSON.stringify(message));
const username = await AsyncStorage.getItem("fqUsernameKey"); //THIS IIS SET IN LOGINSCREEN.JS
const accessToken = await AsyncStorage.getItem("fcmtoken"); //THIS IS SET IN PUSHMANAGER.JS
const client = Voximplant.getInstance();
await client.loginWithToken(username, accessToken);
await client.handlePushNotification(message.data);
return Promise.resolve();
};
PushManager.js
import AsyncStorage from '#react-native-async-storage/async-storage';
import messaging from "#react-native-firebase/messaging";
import PushNotification, {Importance} from 'react-native-push-notification';
async function getFCMToken() {
let fcmtoken = await AsyncStorage.getItem("fcmtoken");
console.log(fcmtoken, "old token")
if(!fcmtoken){
try{
const fcmtoken = await messaging().getToken();
if(fcmtoken) {
console.log(fcmtoken, "new token");
await AsyncStorage.setItem("fcmtoken", fcmtoken);
}
}
catch (error) {
console.log(error, "error in fcmtoken")
}
}
}
//Create Push Notification channel
async function createVoximplantChannel() {
PushNotification.createChannel( //Haven't tried with Voximplant
{
channelId: "voximplant_channel_id", // "channel-id", // (required)
channelName: "Incoming call channel", //"My channel", // (required)
channelDescription: "Incoming call received", //"A channel to categorise your notifications", // (optional) default: undefined.
playSound: true, // (optional) default: true
soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
importance: 5, // (optional) default: 4. Int value of the Android notification importance. importance: 2 <- SILENT NOTIFICATION CHANNEL & importance: 5 <- POPUP NOTIFICATION CHANNEL
vibrate: false, // (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.
);
}
export async function requestUserPermission() {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization Status: ', authStatus);
getFCMToken();
createVoximplantChannel();
}
}
export const NotificationListener = () => {
//******** Notification from BACKGROUND state app ********
messaging().onNotificationOpenedApp((remoteMessage) => {
PushNotification.localNotification({
channelId: "voximplant_channel_id", //remoteMessage.notification.android.channelId, //Perhaps "voximplant_channel_id" ?
message: remoteMessage.notification.body,
title: remoteMessage.notification.title,
//bigPictureUrl: remoteMessage.notification.android.imageUrl,
//smallIcon: remoteMessage.notification.android.imageUrl,
vibrate: true,
data: remoteMessage.data,
})
});
//******** Notification from QUIT state app ********
messaging()
.getInitialNotification()
.then( (remoteMessage) => {
PushNotification.localNotification({
channelId: "voximplant_channel_id", //remoteMessage.notification.android.channelId, //Perhaps "voximplant_channel_id" ?
message: remoteMessage.notification.body,
title: remoteMessage.notification.title,
//bigPictureUrl: remoteMessage.notification.android.imageUrl,
//smallIcon: remoteMessage.notification.android.imageUrl,
vibrate: true,
data: remoteMessage.data,
})
});
//******** Notification from FOREGROUND state app ********
messaging().onMessage(async (remoteMessage) => {
PushNotification.localNotification({
channelId: "voximplant_channel_id", //remoteMessage.notification.android.channelId,
message: remoteMessage.notification.body,
title: remoteMessage.notification.title,
//bigPictureUrl: remoteMessage.notification.android.imageUrl,
//smallIcon: remoteMessage.notification.android.imageUrl,
vibrate: true,
data: remoteMessage.data,
})
});
}
//Cancel notifications (so hopefully no overlapping notificatons)
export const CancelNotifications = () => {
PushNotification.cancelAllLocalNotifications();
};

React Native: How to add items to the set state of useState for getting socket notifications?

I need a function for getting notification from socket (TypeScript) .
For instance ,
when a user click the "Like",the receiver will receive a notice like "You have receive a like from XXX",and I am able to get this message from the below code ,however ,I am not sure how to save those notifications into a list in order to display all the notices ..Could you please take a look how to do it ? Thank you so much in advance !!
I have putted the socket in the useContext :
import React from 'react';
import socketio from 'socket.io-client';
export const socket = socketio.connect(SOCKET_URL);
export const SocketContext = React.createContext();
When I send click a like, the receiver can receive my notification, and then the remark in the below codes,I can't get the notification list :
import {SocketContext} from '../../auth/context';
import React, {useEffect, useState, useContext, useLayoutEffect} from 'react';
const Home = () =>{
const {socket, user} = useContext(SocketContext);
const [notificationCount, setNotificationCount] = useState([]);
const [me, setMe] = useState({});
// init data
const initialData = async () => {
try {
const meResult = await fetchGetMe();
setMe(meResult?.data.data);
} catch (error) {
console.log('initial data get errors:', error);
}
};
useLayoutEffect(() => {
initialData();
}, []);
//get feedback from socket
useEffect(() => {
socket.on('getNotification', data => {
setNotificationCount(pre=> [...pre, data]); //I got the problem here..Can't get the list
console.log('notification data :', notificationCount);
});
return () => {
socket.off('getNotification');
};
}, [socket]);
const onPressLike = ()=>{
socket.emit('sendNotification', {
senderUserId: me?.userId,
senderName: me?.userName,
receiverUserId: 123456,
type: 0, // 0:like 1.gifts 2.sunflower
});
}
<Button onClick={onPressLike}>Like</Button>
}
3.My socket config in the server part :
let onlineUsers = [];
const addUsers = (userId, socketId) => {
!onlineUsers.some((m) => m.userId !== userId) &&
onlineUsers.push({ userId, socketId });
};
const removeUser = (socketId) => {
onlineUsers = onlineUsers.filter((user) => user.socketId !== socketId);
};
const getUser = (receiverId) => {
return onlineUsers.find((m) => m.userId === receiverId);
};
io.on("connection", (socket) => {
console.log("connect now");
socket.on("newUser", (userId) => {
addUsers(userId, socket.id);
console.log("onlineUsers:", onlineUsers);
});
socket.on(
"sendNotification",
({ senderUserId, senderName, receiverUserId, type }) => {
console.log(
`senderName:${senderName},receiverID:${receiverUserId};type:${type},socketId:${socket.id};senderUserId:${senderUserId}`
);
console.log("sendNotification,onlineUsers:", onlineUsers);
let receiver = {};
if (onlineUsers.length > 0) {
receiver = getUser(senderUserId);
console.log("receiver:", receiver);
io.to(receiver.socketId).emit("getNotification", {
senderName,
type,
});
} else {
receiver = null;
console.log("receiver:", receiver);
socket.emit("getNotification", { receiver });
}
}
);
socket.on("disconnect", () => {
console.log("disconnect");
});
});

Testing custom hook - not wrapped in act warning

I' trying to test a custom hook but I receive this warning message
console.error node_modules/#testing-library/react-hooks/lib/core/console.js:19
Warning: An update to TestComponent inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser.
This is my custom hook
import { useState, useEffect } from 'react'
import io from 'socket.io-client'
import config from './../../../../config'
const useNotificationsSocket = (user) => {
const [socket, setSocket] = useState(null)
const [numUnreadMessages, setNumUnreadMessages] = useState(0)
const configureSocket = socket => {
socket.on('connect', () => {
const data = {
user: user,
}
socket.emit('user joined', data)
})
socket && socket.on('messages updated', (data) => {
//console.log(data)
setNumUnreadMessages(data.numUnreadMessages)
})
}
useEffect(() => {
const fetchSocket = async () => {
const s = await io(config.nSocket.url, {transports: ['websocket']})
configureSocket(s)
setSocket(s)
}
// Check that user is not an empty object as this causes a crash.
user && user.Id && fetchSocket()
}, [user])
return [socket, numUnreadMessages]
}
export { useNotificationsSocket }
and this is the test
import { renderHook, act } from '#testing-library/react-hooks'
import { useNotificationsSocket } from './../hooks/useNotificationsSocket'
jest.mock('socket.io-client')
describe('useNotificationsSocket', () => {
it('returns a socket and numUnreadMessages', async () => {
const user = { Id: '1' }
const { result } = renderHook(() => useNotificationsSocket(user))
expect(result).not.toBeNull()
})
})
I've tried importing act and wrapping the code in a call to act but however I try to wrap the code I still get a warning and can't figure out how I should use act in this case.
Your hook is asynchronous, so you need to await its response:
describe('useNotificationsSocket', () => {
it('returns a socket and numUnreadMessages', async () => {
const user = { Id: '1' }
const { result } = renderHook(() => useNotificationsSocket(user))
await waitFor(() => expect(result).not.toBeNull())
})
})
Additionally, if you define multiple tests, you may encounter your original error if you fail to unmount the hook. At least this appears to be the behaviour in #testing-library/react v13.3.0. You can solve this by unmounting the hook when your test completes:
describe('useNotificationsSocket', () => {
it('returns a socket and numUnreadMessages', async () => {
const user = { Id: '1' }
const { result, unmount } = renderHook(() => useNotificationsSocket(user))
await waitFor(() => expect(result).not.toBeNull())
unmount()
})
})

Deep links in react-native-firebase notifications

I am using react-native-firebase with messaging to deliver notifications to my app with cloud functions, with admin.messaging().send(message), very similar to here: https://medium.com/the-modern-development-stack/react-native-push-notifications-with-firebase-cloud-functions-74b832d45386 .
I receive notifications when the app is in the background. Right now I am sending a text in the body of the notification, like 'a new location has been added to the map'. I want to be able to add some sort of deep link, so that when I swipe View on the notification (on iOS for example), it will take me to a specific screen inside the app. How do I pass data from the notification to the app?
I am using react-native-navigation in the app. I can only find code about deep links from inside the app (https://wix.github.io/react-native-navigation/#/deep-links?id=deep-links).
My solution was to use add what information I need in the data object of the notification message object:
in functions/index.js:
let message = {
notification: {
body: `new notification `
},
token: pushToken,
data: {
type: 'NEW_TRAINING',
title: locationTitle
}
};
and process as follows in the app for navigation:
this.notificationOpenedListener =
firebase.notifications().onNotificationOpened((notificationOpen: NotificationOpen) => {
if (notification.data.type === 'NEW_TRAINING') {
this.props.navigator.push({
screen: 'newtrainingscreen',
title: notification.data.title,
animated: true
});
}
I think you are fine with the "how firebase notification work"... cause of this, here is only an description of the Logic how you can Deeplinking into your App.
If you send a notification, add a data-field. Let's say your app has a Tab-Navigator and the sections "News","Service" and "Review".
In your Push-Notification - Datafield (let's name it "jumpToScreen" you define your value:
jumpToScreen = Service
I assume you still have the Handling to recieve Notifications from Firebase implemented.
So create an /lib/MessageHandler.js Class and put your business-logic inside.
import firebase from 'react-native-firebase';
/*
* Get a string from Firebase-Messages and return the Screen to jump to
*/
const getJumpPoint = (pointer) => {
switch (pointer) {
case 'News':
return 'NAV_NewsList'; // <= this are the names of your Screens
case 'Service':
return 'NAV_ServiceList';
case 'Review':
return 'NAV_ReviewDetail';
default: return false;
}
};
const MessageHandler = {
/**
* initPushNotification initialize Firebase Messaging
* #return fcmToken String
*/
initPushNotification: async () => {
try {
const notificationPermission = await firebase.messaging().hasPermission();
MessageHandler.setNotificationChannels();
if (notificationPermission) {
try {
return await MessageHandler.getNotificationToken();
} catch (error) {
console.log(`Error: failed to get Notification-Token \n ${error}`);
}
}
} catch (error) {
console.log(`Error while checking Notification-Permission\n ${error}`);
}
return false;
},
clearBadges: () => {
firebase.notifications().setBadge(0);
},
getNotificationToken: () => firebase.messaging().getToken(),
setNotificationChannels() {
try {
/* Notification-Channels is a must-have for Android >= 8 */
const channel = new firebase.notifications.Android.Channel(
'app-infos',
'App Infos',
firebase.notifications.Android.Importance.Max,
).setDescription('General Information');
firebase.notifications().android.createChannel(channel);
} catch (error) {
console.log('Error while creating Push_Notification-Channel');
}
},
requestPermission: () => {
try {
firebase.messaging().requestPermission();
firebase.analytics().logEvent('pushNotification_permission', { decision: 'denied' });
} catch (error) {
// User has rejected permissions
firebase.analytics().logEvent('pushNotification_permission', { decision: 'allowed' });
}
},
foregroundNotificationListener: (navigation) => {
// In-App Messages if App in Foreground
firebase.notifications().onNotification((notification) => {
MessageHandler.setNotificationChannels();
navigation.navigate(getJumpPoint(notification.data.screen));
});
},
backgroundNotificationListener: (navigation) => {
// In-App Messages if App in Background
firebase.notifications().onNotificationOpened((notificationOpen) => {
const { notification } = notificationOpen;
notification.android.setChannelId('app-infos');
if (notification.data.screen !== undefined) {
navigation.navigate(getJumpPoint(notification.data.screen));
}
});
},
appInitNotificationListener: () => {
// In-App Messages if App in Background
firebase.notifications().onNotificationOpend((notification) => {
notification.android.setChannelId('app-infos');
console.log('App-Init: Da kommt ne Message rein', notification);
firebase.notifications().displayNotification(notification);
});
},
};
export default MessageHandler;
In your index.js you can connect it like this:
import MessageHandler from './lib/MessageHandler';
export default class App extends Component {
state = {
loading: null,
connection: null,
settings: null,
};
async componentDidMount() {
const { navigation } = this.props;
await MessageHandler.initPushNotification();
this.notificationForegroundListener = MessageHandler.foregroundNotificationListener(navigation);
this.notificationBackgroundListener = MessageHandler.backgroundNotificationListener(navigation);
this.setState({ loading: false, data });
}
componentWillUnmount() {
this.notificationForegroundListener();
this.notificationBackgroundListener();
}
async componentDidMount() {
MessageHandler.requestPermission();
AppState.addEventListener('change', this.handleAppStateChange);
MessageHandler.clearBadges();
}
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChange);
}
handleAppStateChange = (nextAppState) => {
if (nextAppState.match(/inactive|background/)) {
MessageHandler.clearBadges();
}
....
I hope this give you an Idea how to implement it for your needs.
I think you don't need to use deep links nor dynamic links but just use Firebase/Notifications properly. If I were you I would add the following logic in the componentDidMount method of your parent container:
async componentDidMount() {
// 1. Check notification permission
const notificationsEnabled = await firebase.messaging().hasPermission();
if (!notificationsEnabled) {
try {
await firebase.messaging().requestPermission(); // Request notification permission
// At this point the user has authorized the notifications
} catch (error) {
// The user has NOT authorized the notifications
}
}
// 2. Get the registration token for firebase notifications
const fcmToken = await firebase.messaging().getToken();
// Save the token
// 3. Listen for notifications. To do that, react-native-firebase offer you some methods:
firebase.messaging().onMessage(message => { /* */ })
firebase.notifications().onNotificationDisplayed(notification => { /* */ })
firebase.messaging().onNotification(notification => { /* */ })
firebase.messaging().onNotificationOpened(notification => {
/* For instance, you could use it and do the NAVIGATION at this point
this.props.navigation.navigate('SomeScreen');
// Note that you can send whatever you want in the *notification* object, so you can add to the notification the route name of the screen you want to navigate to.
*/
})
}
You can find the documentation here: https://rnfirebase.io/docs/v4.3.x/notifications/receiving-notifications