DEV Community

Cover image for React Native, Local, Scheduled, Push Notification With Firebase
Vikrant Negi
Vikrant Negi

Posted on

React Native, Local, Scheduled, Push Notification With Firebase

With ever going increase in app usage, the app developers try to find new ways to keep their user engaged with their apps. Push notifications are one way to keep your users engaged and informed.

Push notifications are the communications channel used by apps to drive user re-engagement and retention. Push notification technology has come a long way from being a single messages delivery system to a rich and interactive medium.

There are two types of notifications, remote and local notifications.

Remote Notifications

With remote notifications, you use one of your company’s servers to push data to user devices via the Apple Push Notification service or FCM.

Local Notifications

Both Android and IOS support the ability to trigger notifications from your application locally. These can either be displayed immediately, or scheduled to be displayed at a later date.

In this article we will be using local notifications feature to send daily a reminder to the user at a particular time every day.

Prerequisites

This tutorial requires basic knowledge of React Native. To set up your development machine, follow the official guide here.

To implement push notifications in React Native application, we are going to use the react-native-firebase.

React Native Firebase has Notifications module that supports for both remote (FCM) and local notifications.

To make sure we are on the same page, the following are the versions used in this tutorial:

  • Node v10.15.0
  • npm 6.4.1
  • yarn 1.16.0
  • react-native 0.59.9
  • react-native-firebase 5.2.3

Getting Started

To create a new project using react-native-cli, type the following in terminal:

$ react-native init localReminders
$ cd localReminders

Install React Native Firebase

Install react-native-firebase by following installation instructions here.

Make sure you have completed both iOS and Android setup.

Install Modules

React Native Firebase only provides your application with access to Core features.

To user notification in our react native app, we'll need to also install the Cloud Messaging and Notifications modules.

Install Cloud Messaging by following the instructions here.

Install Notifications by following the instructions here.

Again, make sure you followed the steps for both iOS and Android.

Initial code setup

In your App.js file add these imports:

import React, { Component } from "react";
import { Alert } from "react-native";
import firebase from "react-native-firebase";

import Dashboard from "./src/Dashboard";

Create an empty Dashboard.js file in your src folder. We'll fill this with code in later part of the tutorial.

Now create a class component called App as follow:

export default class App extends Component {
  componentDidMount() {
    // Create notification channel required for Android devices
    this.createNotificationChannel();

    // Ask notification permission and add notification listener
    this.checkPermission();
  }

  createNotificationChannel = () => {};

  checkPermission = async () => {};

  render() {
    return <Dashboard />;
  }
}

We've created a few helper methods in this class component that we called on componentDidMount() lifecycle method. In render, we'll return the Dashboard component.

Let's review and add code to these methods and see what they do and why do we need them.

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 Firebase to work seamlessly across all versions of Android, you will need to create a channel before you can display a notification. This block of code can be re-run multiple times, so it is safe to do it each time your application starts.

To create this notification channel we created a custom helper method createNotificationChannel(). Update it with the following:

createNotificationChannel = () => {
  // Build a android notification channel
  const channel = new firebase.notifications.Android.Channel(
    "reminder", // channelId
    "Reminders Channel", // channel name
    firebase.notifications.Android.Importance.High // channel importance
  ).setDescription("Used for getting reminder notification"); // channel description

  // Create the android notification channel
  firebase.notifications().android.createChannel(channel);
};

Android channel accept three parameters channelId, name and importance.

For full reference documentation, please see AndroidChannel and AndroidNotifications.

Notification Permission and Listener

Before we can send any notification we need to make sure we have the notification permission and then, when we have that permission we can add a notification listener. This notification listener will listen for any notification and return us with the notification when received.

Update your checkPermission() method with the following:

checkPermission = async () => {
  const enabled = await firebase.messaging().hasPermission();
  if (enabled) {
    // We've the permission
    this.notificationListener = firebase
      .notifications()
      .onNotification(async notification => {
        // Display your notification
        await firebase.notifications().displayNotification(notification);
      });
  } else {
    // user doesn't have permission
    try {
      await firebase.messaging().requestPermission();
    } catch (error) {
      Alert.alert(
        "Unable to access the Notification permission. Please enable the Notification Permission from the settings"
      );
    }
  }
};

When the notification listener receives a notification, we call displayNotification() method with the notification received which will display the notification.

We can now receive and show the notification. Now its time to schedule a local notification which will fire at some point in the future.

Dashboard Screen

We are going to create a Dashboard screen which will have a switch to enable and disable notifications and a time picker to set time to receive notifications. It will look something like below.

To make this UI Screen we'll add few third party helper libraries.

  1. react-native-elements - UI component library
  2. moment - Handling Date Object
  3. react-native-modal-datetime-picker - A React-Native datetime-picker for Android and iOS

Let's start with adding the required imports:

import React, { Component } from "react";
import { Platform, StyleSheet, Text, SafeAreaView, View } from "react-native";
import { ListItem } from "react-native-elements";
import firebase from "react-native-firebase";
import DateTimePicker from "react-native-modal-datetime-picker";
import moment from "moment";

Now we'll create and default export Dashboard class component.

Now, add some local states:

state = {
  enableNotification: true,
  isDateTimePickerVisible: false,
  notificationTime: moment({ hour: 17 })
};

Now we want to set reminder as soon as user lands on the dashboard, so we'll create and call a setReminder() method on componentDidMount() lifecycle method:

componentDidMount() {
  this.setReminder();
}

setReminder = async () => {
  const { notificationTime, enableNotification } = this.state;

  if (enableNotification) {
    // schedule notification
    firebase.notifications().scheduleNotification(this.buildNotification(), {
      fireDate: notificationTime.valueOf(),
      repeatInterval: 'day',
      exact: true,
    });
  } else {
    return false;
  }
};

In setReminder() method first we use notificationTime and enableNotification state.

If enableNotification is true we schedule the notification using scheduleNotification() method.

The scheduleNotification() has two parameters, notification and schedule.

For notification we'll call another custom method buildNotification() which will return notification and, in schedule we'll pass an object with fireDate, repeatInterval and exact keys.

The fireDate is the date when the notification should first be shown, in milliseconds. For repeatInterval we'll use day, as we want the notification to be shown everyday. The exact option is Android only and it denotes if the fireDate should be respected exactly, i.e. for reminders, or if it can deviate slightly to save battery.

In else we'll just return false.

Now, we'll add buildNotification() method which will build a notification when a notification is received:

buildNotification = () => {
  const title = Platform.OS === "android" ? "Daily Reminder" : "";
  const notification = new firebase.notifications.Notification()
    .setNotificationId("1") // Any random ID
    .setTitle(title) // Title of the notification
    .setBody("This is a notification") // body of notification
    .android.setPriority(firebase.notifications.Android.Priority.High) // set priority in Android
    .android.setChannelId("reminder") // should be the same when creating channel for Android
    .android.setAutoCancel(true); // To remove notification when tapped on it

  return notification;
};

Let's add some helper method for the notification switch and time picker. These will be used by their respective components to set local states which will then later be used:

enableNotification = value => {
  this.setState({
    enableNotification: value
  });
};

showDateTimePicker = () => {
  this.setState({ isDateTimePickerVisible: true });
};

hideDateTimePicker = () => {
  this.setState({ isDateTimePickerVisible: false });
};

handleDatePicked = date => {
  this.hideDateTimePicker();

  this.setState({
    notificationTime: moment(date)
  });
};

Finally, the render() which we'll return the UI of the dashboard:

render() {
  const { enableNotification, isDateTimePickerVisible, notificationTime } = this.state;
  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.cardTitleView}>
        <Text style={styles.cardTitle}>Add Reminder</Text>
      </View>
      <ListItem
        title="Notification"
        bottomDivider
        titleStyle={styles.titleStyle}
        switch={{ onValueChange: this.enableNotification, value: enableNotification }}
      />
      <ListItem
        title="Time"
        titleStyle={styles.titleStyle}
        onPress={this.showDateTimePicker}
        rightElement={<Text style={{ opacity: 0.7 }}>{moment(notificationTime).format('LT')}</Text>}
      />
      <DateTimePicker
        isVisible={isDateTimePickerVisible}
        onConfirm={this.handleDatePicked}
        onCancel={this.hideDateTimePicker}
        mode="time" // show only time picker
        is24Hour={false}
        date={new Date(notificationTime)}
        titleIOS="Pick your Notification time"
      />
    </SafeAreaView>
  );
}

Time to sprinkle in some styles to make UI more appealing.

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"
  }
});

That's it. We are done with development. In the next section, we'll test it out in an iOS simulator.

Running the app

Test the app by enabling notification and setting time 1 min in the future.

Note: Sometimes the notification may not show at the exact time. Please wait for a whole minute for notification to appear.

Conclusion

We can now schedule daily local push notification in our React Native app for both iOS and Android.

Apart from firebase, there are other libraries you can use to implement local push notification like react-native-push-notification.

Here is the Github repo local-reminders.

Originally published on Medium

PS: Cover image by Jamie Street on Unsplash

Top comments (1)

Collapse
 
efleurine profile image
Emmanuel

thanks for this tuto.

it is a great start for a project I am doing research for