Hello folks. I hope you all are doing well.
In this tutorial, you're going to learn how to handle and schedule local push notification with firebase using react native development.
There are two types of notifications, remote and local notifications.
Remote Notifications
With remote notifications, we should use one of our company servers to push data to user devices via any notification service.
Local Notifications
In local notification, notification is scheduled and triggered by an app on a particular time and date and delivered on the same device.
In this tutorial, we will use local notification to schedule reminder.
Prerequisites
This tutorial requires basic knowledge of React Native development. To set up your development machine, follow the official guide here.
We are going to use react-native-firebase to handle push notification
Before implementing to schedule push notification, please visit this article to configure project.
After the configured project, Let's create one FCMService to handle notification
Create one folder in project directory named it as src
and under the src
folder create one file name as FCMService.js
Before use push notification in the app, we require the user permission to display notifications in the app. If the user denies permission it explicitly changes from the settings.
First, let's write below code in FCMService.js to get permission from the user
checkPermission = (onRegister) => {
firebase.messaging().hasPermission()
.then(enabled => {
if (enabled) {
//user has permission
this.getToken(onRegister)
} else {
//user don't have permission
this.requestPermission(onRegister)
}
}).catch(error => {
console.log("Permission rejected", error)
})
}
getToken = (onRegister) => {
firebase.messaging().getToken()
.then(fcmToken => {
if (fcmToken) {
onRegister(fcmToken)
} else {
console.log("User does not have a device token")
}
}).catch(error => {
console.log("getToken rejected ", error)
})
}
requestPermission = (onRegister) => {
firebase.messaging().requestPermission()
.then(() => {
this.getToken(onRegister)
}).catch(error => {
console.log("Requested persmission rejected ", error)
})
}
deletedToken = () => {
firebase.messaging().deleteToken()
.catch(error => {
console.log("Delected token error ", error)
})
}
After getting permission from the user we will create listeners for listen notification.
createNoitificationListeners = (onRegister, onNotification, onOpenNotification) => {
// This listener triggered when notification has been received in foreground
this.notificationListener = firebase.notifications().onNotification((notification) => {
onNotification(notification)
})
// This listener triggered when app is in backgound and we click, tapped and opened notifiaction
this.notificationOpenedListener = firebase.notifications()
.onNotificationOpened((notificationOpen) => {
console.log(notificationOpen)
if (notificationOpen) {
const notification = notificationOpen.notification
onOpenNotification(notification)
this.removeDelieveredNotification(notification)
}
})
// This listener triggered when app is closed and we click,tapped and opened notification
firebase.notifications().getInitialNotification()
.then(notificationOpen => {
if (notificationOpen) {
const notification = notificationOpen.notification
onOpenNotification(notification)
this.removeDelieveredNotification(notification)
}
})
// Triggered for data only payload in foreground
this.messageListener = firebase.messaging().onMessage((message) => {
onNotification(message)
})
// This listener triggered when new token
this.onTokenRefreshListener = firebase.messaging().onTokenRefresh(fcmToken => {
console.log("FCM new token: ", fcmToken)
onRegister(fcmToken)
})
}
Read More: Implement Push Notification with Firebase in React Native
Create Android Notification Channel
As of Android 8.0 (API Level 26), notifications must specify a Notification Channel or they will not appear. To allow React Native App Developers for Integrating Firebase to work seamlessly across all versions of Android, we will create buildChannel()
before we build notification.
buildChannel = (obj) => {
return new firebase.notifications.Android.Channel(
obj.channelId, obj.channelName,
firebase.notifications.Android.Importance.High)
.setDescription(obj.channelDes)
}
Build channel in android accepts three parameters channelId
, name
and importance
.
Now, we’ll add buildNotification() method which will build a notification when a notification is received:
buildNotification = (obj) => {
console.log(obj)
firebase.notifications().android.createChannel(obj.channel)
const notification = new firebase.notifications.Notification()
.setSound(obj.sound)
.setNotificationId(obj.dataId)
.setTitle(obj.title)
.setBody(obj.content)
.setData(obj.data)
.android.setChannelId(obj.channel.channelId)
.android.setLargeIcon(obj.largeIcon)
.android.setSmallIcon(obj.smallIcon)
.android.setColor(obj.colorBgIcon)
.android.setPriority(firebase.notifications.Android.Priority.High)
.android.setVibrate(obj.vibrate)
.android.setAutoCancel(true)
return notification
}
Let's create one function that displays notifications when a notification arrives.
displayNotification = (notification) => {
firebase.notifications().displayNotification(notification)
.catch(error => { console.log("Display Notification error", error) })
}
Whenever we open a notification and displays a notification after that we need to remove delivered notification so, we create
removeDelieveredNotification()
removeDelieveredNotification = (notification) => {
firebase.notifications()
.removeDeliveredNotification(notification.notificationId)
}
The Purpose of this tutorial is to schedule notification so, Let's create scheduleNotificaion()
scheduleNotification = (notification, datetime) => {
const date = new Date(datetime)
firebase.notifications()
.scheduleNotification(notification, { fireDate: date.getTime() })
}
So, Final FCMService.js
looks like this
import firebase from 'react-native-firebase' | |
class FCMService { | |
// we use this method to register notification service in our app. | |
// we call this method in componetDidMount() so, we app load we get permission to | |
// display notification. | |
register = (onRegister,onNotification, onOpenNotification) =>{ | |
this.checkPermission(onRegister) | |
// when register function call that time we create notification listener | |
this.createNoitificationListeners(onRegister, onNotification, onOpenNotification) | |
} | |
checkPermission = (onRegister) => { | |
firebase.messaging().hasPermission() | |
.then(enabled => { | |
if (enabled) { | |
//user has permission | |
this.getToken(onRegister) | |
} else { | |
//user don't have permission | |
this.requestPermission(onRegister) | |
} | |
}).catch(error => { | |
console.log("Permission rejected", error) | |
}) | |
} | |
getToken = (onRegister) => { | |
firebase.messaging().getToken() | |
.then(fcmToken => { | |
if (fcmToken) { | |
onRegister(fcmToken) | |
} else { | |
console.log("User does not have a device token") | |
} | |
}).catch(error => { | |
console.log("getToken rejected ", error) | |
}) | |
} | |
requestPermission = (onRegister) => { | |
firebase.messaging().requestPermission() | |
.then(() => { | |
this.getToken(onRegister) | |
}).catch(error => { | |
console.log("Requested persmission rejected ", error) | |
}) | |
} | |
deletedToken = () => { | |
firebase.messaging().deleteToken() | |
.catch(error => { | |
console.log("Delected token error ", error) | |
}) | |
} | |
createNoitificationListeners = (onRegister, onNotification, onOpenNotification) => { | |
// This listener triggered when notification has been received in foreground | |
this.notificationListener = firebase.notifications().onNotification((notification) => { | |
onNotification(notification) | |
}) | |
// This listener triggered when app is in backgound and we click, tapped and opened notifiaction | |
this.notificationOpenedListener = firebase.notifications() | |
.onNotificationOpened((notificationOpen) => { | |
console.log(notificationOpen) | |
if (notificationOpen) { | |
const notification = notificationOpen.notification | |
onOpenNotification(notification) | |
this.removeDelieveredNotification(notification) | |
} | |
}) | |
// This listener triggered when app is closed and we click,tapped and opened notification | |
firebase.notifications().getInitialNotification() | |
.then(notificationOpen => { | |
if (notificationOpen) { | |
const notification = notificationOpen.notification | |
onOpenNotification(notification) | |
this.removeDelieveredNotification(notification) | |
} | |
}) | |
// Triggered for data only payload in foreground | |
this.messageListener = firebase.messaging().onMessage((message) => { | |
onNotification(message) | |
}) | |
// This listener triggered when new token | |
this.onTokenRefreshListener = firebase.messaging().onTokenRefresh(fcmToken => { | |
console.log("FCM new token: ", fcmToken) | |
onRegister(fcmToken) | |
}) | |
} | |
buildChannel = (obj) => { | |
return new firebase.notifications.Android.Channel( | |
obj.channelId, obj.channelName, | |
firebase.notifications.Android.Importance.High) | |
.setDescription(obj.channelDes) | |
} | |
buildNotification = (obj) => { | |
console.log(obj) | |
firebase.notifications().android.createChannel(obj.channel) | |
const notification = new firebase.notifications.Notification() | |
.setSound(obj.sound) | |
.setNotificationId(obj.dataId) | |
.setTitle(obj.title) | |
.setBody(obj.content) | |
.setData(obj.data) | |
.android.setChannelId(obj.channel.channelId) | |
.android.setLargeIcon(obj.largeIcon) | |
.android.setSmallIcon(obj.smallIcon) | |
.android.setColor(obj.colorBgIcon) | |
.android.setPriority(firebase.notifications.Android.Priority.High) | |
.android.setVibrate(obj.vibrate) | |
.android.setAutoCancel(true) | |
return notification | |
} | |
scheduleNotification = (notification, datetime) => { | |
const date = new Date(datetime) | |
firebase.notifications() | |
.scheduleNotification(notification, { fireDate: date.getTime() }) | |
} | |
displayNotification = (notification) => { | |
firebase.notifications().displayNotification(notification) | |
.catch(error => { console.log("Display Notification error", error) }) | |
} | |
removeDelieveredNotification = (notification) => { | |
firebase.notifications() | |
.removeDeliveredNotification(notification.notificationId) | |
} | |
} | |
export const fcmService = new FCMService() |
Before proceeding further Please install this dependency
$ npm install react-native-elements react-native-modal-datetime-picker moment @react-native-community/datetimepicker react-native-vector-icons
So, we have created one file under src
folder scheduleReminder.js
Let's write below code into scheduleReminder.js
file
import React, { Component } from 'react'; | |
import { StyleSheet, Text, SafeAreaView, View, } from 'react-native'; | |
import { ListItem, Input, Button, Overlay } from 'react-native-elements'; | |
import DateTimePicker from 'react-native-modal-datetime-picker'; | |
import moment from 'moment'; | |
import { fcmService } from './FCMService' | |
class ScheduleReminder extends Component { | |
state = { | |
isDateTimePickerVisible: false, | |
notificationTime: moment(), | |
notificationTitle: '', | |
notificationDescription: '', | |
isVisibleOverlay: false, | |
notifyData: {} | |
}; | |
componentDidMount() { | |
//Register fcm service and attached listener callback function | |
fcmService.register(this.onRegister, this.onNotification, this.onOpenNotification) | |
} | |
onRegister = (token) => { | |
console.log("[Notification fcm ] onRegister:", token) | |
} | |
onNotification = (notify) => { | |
console.log("[Notification fcm ] : onNotification:", notify) | |
// we will use fcm service method to buildnotification | |
const notification = fcmService.buildNotification(this.createNotification(notify)) | |
fcmService.displayNotification(notification) | |
} | |
onOpenNotification = (notify) => { | |
console.log("[Notification fcm ] : onOpenNotification ", notify) | |
this.setState({ notifyData: notify._data }, () => this.setState({ isVisibleOverlay: true })) | |
} | |
setReminder = () => { | |
const { notificationDescription, notificationTitle ,notificationTime} = this.state | |
let body = { | |
_title: notificationTitle, | |
_body: notificationDescription, | |
// when ever app is backgound and notification open it will get data from _data object | |
_data: { | |
title: notificationTitle, | |
body: notificationDescription, | |
}, | |
// we need to give notification id otherwise it will give error | |
_notificationId: Math.random().toString(), | |
time: notificationTime | |
} | |
this.scheduleReminder(body) | |
}; | |
scheduleReminder = (notifyDetails) => { | |
const notification = fcmService.buildNotification(this.createNotification(notifyDetails)) | |
// to schedule notification we need to give notification object and datetime object | |
fcmService.scheduleNotification(notification, notifyDetails.time) | |
this.resetState() | |
} | |
closeOverLay = () => { | |
this.setState({ isVisibleOverlay: false }) | |
} | |
createNotification = (notify) => { | |
const channelObj = { | |
channelId: "SmapleChannelID", | |
channelName: "SmapleChannelName", | |
channelDes: "SmapleChannelDes" | |
} | |
// we use fcm service build channel method to build channnel | |
const channel = fcmService.buildChannel(channelObj) | |
const buildNotify = { | |
title: notify._title, | |
content: notify._body, | |
sound: 'default', | |
channel: channel, | |
data: notify._data, | |
colorBgIcon: "#1A243B", | |
largeIcon: 'ic_launcher', | |
smallIcon: 'ic_launcher', | |
vibrate: true, | |
dataId: notify._notificationId | |
} | |
return buildNotify | |
} | |
resetState = () => { | |
this.setState({ | |
notificationTime: moment(), | |
notificationTitle: '', | |
notificationDescription: '' | |
}) | |
} | |
displayDateTimePicker = () => { | |
this.setState({ isDateTimePickerVisible: true }); | |
}; | |
closeDateTimePicker = () => { | |
this.setState({ isDateTimePickerVisible: false }); | |
}; | |
handlePicked = date => { | |
this.closeDateTimePicker(); | |
this.setState({ | |
notificationTime: moment(date), | |
}); | |
}; | |
handleValueChange = (value, name) => { | |
this.setState({ | |
[name]: value | |
}) | |
} | |
render() { | |
const { isDateTimePickerVisible, | |
notificationTime, notificationTitle, | |
notificationDescription, notifyData } = this.state; | |
return ( | |
<SafeAreaView style={styles.container}> | |
<View style={styles.cardTitleView}> | |
<Text style={styles.cardTitle}>Add Reminder</Text> | |
</View> | |
<ListItem | |
title="Time" | |
titleStyle={styles.titleStyle} | |
onPress={this.displayDateTimePicker} | |
rightElement={<Text style={{ opacity: 0.7 }}>{moment(notificationTime).format('LT')}</Text>} | |
/> | |
<View style={styles.titleView}> | |
<Input | |
style={styles.titleinput} | |
value={notificationTitle} | |
onChangeText={(text) => this.handleValueChange(text, 'notificationTitle')} | |
placeholder="Title" | |
/> | |
<Input | |
multiline={true} | |
numberOfLines={3} | |
style={styles.titleinput} | |
value={notificationDescription} | |
onChangeText={(text) => this.handleValueChange(text, 'notificationDescription')} | |
placeholder="Description" | |
/> | |
</View> | |
<View style={{ alignItems: 'center', justifyContent: 'center', marginBottom: 10 }}> | |
<Button | |
title="Add reminder" | |
buttonStyle={{ width: 200, height: 40 }} | |
onPress={() => this.setReminder()} | |
/> | |
</View> | |
// we will use overlay to display notification | |
<Overlay | |
style={{ flex: 1 }} | |
isVisible={this.state.isVisibleOverlay} | |
onBackdropPress={() => this.closeOverLay()}> | |
<View style={{ flexDirection: 'column' }}> | |
<Text style={{ margin: 20, fontSize: 20, fontWeight: '600' }}>{notifyData && notifyData.title}</Text> | |
<Text style={{ margin: 20, fontSize: 16 }}>{notifyData && notifyData.body}</Text> | |
</View> | |
</Overlay> | |
<DateTimePicker | |
isVisible={isDateTimePickerVisible} | |
onConfirm={this.handlePicked} | |
onCancel={this.closeDateTimePicker} | |
mode="datetime" | |
is24Hour={false} | |
date={new Date(notificationTime)} | |
titleIOS="Pick your Notification time" | |
/> | |
</SafeAreaView> | |
); | |
} | |
} | |
const styles = StyleSheet.create({ | |
container: { | |
flex: 1, | |
backgroundColor: '#EEEFF0', | |
}, | |
cardTitleView: { | |
paddingHorizontal: 15, | |
paddingTop: 15, | |
paddingBottom: 8, | |
}, | |
cardTitle: { | |
fontSize: 15, | |
color: '#585858', | |
fontWeight: '600', | |
}, | |
titleStyle: { | |
fontSize: 20, | |
color: '#585858', | |
}, | |
subtitleStyle: { | |
fontSize: 16, | |
color: '#585858', | |
}, | |
titleView: { | |
margin: 20, | |
backgroundColor: '#EEEFF0', | |
}, | |
titleinput: { | |
fontSize: 20, | |
fontWeight: '600', | |
margin: 5, | |
backgroundColor: "#fff" | |
} | |
}); | |
export default ScheduleReminder |
On componentDidMount()
we have register our fcmservice and link listener callback function we have link three function onRegister()
, onNotification()
and onOpenNotification()
.
onRegister
function we have got the user permission, onNotification
function called when our app is opened and any notification arrives that time onNotification function creates a notification and displays the notification and onOpenNotification
function called whenever you tap and open the notification.
We get time, title and description from the user to schedule a reminder, before a schedule reminder we need to create a notification object by using buildNotification()
of FCMService because a FCMService's scheduleNotification()
function accepts a parameter as notification object and date & time.
After configuring all things now it's time to test the app

Find the source code in the Github repo here.
Top comments (3)
Hi ,
It's not with the rnfirebase v6 right ? with @@react-native-firebase/messaging' ......
Hi,
I need firebase notification code which includes all three types of notifications like foreground, background and quite state. if you have please send or send repo link
thanks
Things have changed and here's a link to help people from now on:
notifee.app/react-native/docs/trig...