Local Notifications using Expo
Tags: reactnative, expo, javascript, react
Published: 2021-11-22 06:40:56

## Introduction
Expo is a very useful framework for developing Android Applications.
The documentation is clear and crisp, but I observed that no good write-ups or blogs exist for, so in this post I will explain how to get Local Notifications in your app.
I was developing a Timetable management application known as <a href="https://play.google.com/store/apps/details?id=com.androidclub.timely">Timely</a> , which sends a notification 5 minute prior to the starting time of a class.
I spent a lot of time going through GitHub and Stack Overflow, searching for some answer to find a way to send notifications every week at a certain time.

## Expo Notification
We will be using Expo Notifications since the project is built on Expo.
The best method is to obviously read the documentation provided by 
<a href="https://docs.expo.dev/versions/latest/sdk/notifications/#cancelschedulednotificationasyncidentifier-string-promisevoid
">Expo</a>

<b>Note - Notifications do not work on an emulator,</b> so make sure to use a Physical device.

### Step 1: Install Expo Notifications
First step is to install the package
```js
expo install expo-notifications
``` 

### Step 2: Initialize the Notification Handler

```js
import * as Notifications from "expo-notifications";

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: true,
    shouldSetBadge: true,
  }),
});
```
This will enable the notifications for the app.
This can be done in your entry point file like App.js or in a separate file, or you can even use Context API.

Now, how expo notifications work is that we create a Notification which is allotted a Unique ID, which can be used for deleting it later on. Every Push Notification is allotted a push token ID.


### Step 3: Writing the Notifications function

This function adds the notification listener and subscriber and all the necessary things needed for getting Local notifications  for your Expo App.

```js
export default function Notification() {
  const [expoPushToken, setExpoPushToken] = useState("");
  const [notification, setNotification] = useState(false);
  const notificationListener = useRef();
  const responseListener = useRef();

  useEffect(() => {
    registerForPushNotificationsAsync().then((token) =>
      setExpoPushToken(token)
    );

    notificationListener.current =
      Notifications.addNotificationReceivedListener((notification) => {
        setNotification(notification);
      });

    responseListener.current =
      Notifications.addNotificationResponseReceivedListener((response) => {
        console.log(response);
      });

    return () => {
      Notifications.removeNotificationSubscription(
        notificationListener.current
      );
      Notifications.removeNotificationSubscription(responseListener.current);
    };
  }, []);

  return (
    null
  );
}
```
This code can be used as it is for most projects.

### Step 4: Schedule Notification function
This will be called to schedule a notification. Since I was developing a Timetable Organizer app, therefore the notifications require the day of the week, time in hours and minutes and other info to be displayed in the notification.
```js
export async function schedulePushNotification(
  className,
  slot,
  type,
  time,
  day
) {
  time = new Date(time.getTime() - 5 * 60000);
  var days = [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
  ];
  const weekday = days.indexOf(day) + 1;
  const hours = time.getHours();
  const minutes = time.getMinutes();
  const id = await Notifications.scheduleNotificationAsync({
    content: {
      title: className + " " + type,
      body: slot,
      // sound: 'default',
    },
    trigger: {
      weekday: weekday,
      hour: hours,
      minute: minutes,
      repeats: true,
    },
  });
  console.log("notif id on scheduling",id)
  return id;
}
```
The things you put up inside content will be the things shown to you in the notification.
The trigger object contains the necessary trigger conditions.
You can find more on <a href="https://docs.expo.dev/versions/latest/sdk/notifications/#types">here</a>

### Step 5: Register Push Notification Function
This function again can be used as it is, as it asks for permissions from the user to send the notification and registers the notification.
```js
async function registerForPushNotificationsAsync() {
  let token;
  if (Constants.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!");
      return;
    }
    token = (await Notifications.getExpoPushTokenAsync()).data;
    console.log(token);
  } else {
    alert("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],
      sound: true,
      lightColor: "#FF231F7C",
      lockscreenVisibility: Notifications.AndroidNotificationVisibility.PUBLIC,
      bypassDnd: true,
    });
  }

  return token;
}
```
Inside the condition check for Android device, we can specify the various things we want for the notification like sound true or false or the vibration pattern, whether to bypass DND, etc which can also be found on the documentation provided for Expo Notifications.

### Step 6: Cancelling Notifications
Assume that a user created a reminder for a class but later on want to switch it off. If we don't have this function, the user, even after deleting the reminder, would get the notifications forever as notification are registered with the device itself. (Probably wipe data and cache would work then) so this function will enable us to cancel any notification if we give it the notification ID generated on creating a notification.
```js
export async function cancelNotification(notifId){
  await Notifications.cancelScheduledNotificationAsync(notifId);
}
```

### Conclusion
Now we can call the create notification function or cancel notification function whenever we need to do so.
I will link the GitHub for the whole code of the app. Feel free to check it out and send any PR for improvements!
Also, I would be glad if you could suggest improvements to this post as well as the code for this.
Thank you!

<a href="https://github.com/Neeleshrj/TimeLy/blob/master/src/screens/notification.js">GitHub Repo link for reference</a>