0

Hi so I've been experimenting with the expo-notifications library all day and firstly it's really neat however I've run into a bit of an obstacle and that is scheduling a notification that repeats daily but at a random time and shows different data (e.g. fetch quote from an API)

To better explain think of how BeReal send their notifications... daily, random times. I'm tryna mimic that locally.

I can't figure out how to achieve this and would really appreciate some clarification on whether this is even possible.

I've created a basic custom hook to experiment:

import { View, Text, Platform } from "react-native";
import React, { useEffect, useState, useRef } from "react";
import * as Notifications from "expo-notifications";
import * as Device from "expo-device";
// import { useNavigation } from "@react-navigation/native";

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: true,
    shouldSetBadge: false,
  }),
});

export default function useNotifications() {
  const [expoPushToken, setExpoPushToken] = useState("");
  const [givenNotificationPerm, setGivenNotificationPerm] = useState(false);
  const [notification, setNotification] = useState(false);
  const notificationListener = useRef();
  const responseListener = useRef();

  useEffect(() => {
    // permissions(); - asks for permission
    givenPermissions(); // checks if has permissions
    getScheduled(); // get current notifications in pipeline

    Notifications.cancelAllScheduledNotificationsAsync();

    notificationListener.current =
      Notifications.addNotificationReceivedListener((notification) => {
        setNotification(notification);
        console.log("--- notification received ---");
        // const show_time = notification?.request?.trigger?.dateComponents;
        // console.log(show_time);
        console.log(notification);
        console.log("------");
      });

    responseListener.current =
      Notifications.addNotificationResponseReceivedListener((response) => {
        console.log("--- notification tapped ---");
        const screen = response?.notification?.request?.content?.data?.screen;
        const show_time =
          response?.notification?.request?.content?.data?.show_time; // temp
        // navigation.navigate("Root", { screen: screen });
        console.log("this showed: " + show_time);
        console.log("------");
      });

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

  async function permissions() {
    registerForPushNotificationsAsync().then((token) =>
      setExpoPushToken(token)
    );
  }

  async function getScheduled() {
    console.log("getting schedfuled notifcation");

    const slay = await Notifications.getAllScheduledNotificationsAsync();
    console.log("scheduled:");
    console.log(slay);
  }

  function getRandomIntInclusive(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1) + min); // The maximum is inclusive and the minimum is inclusive
  }

  async function schedulePushNotification() {
    console.log("reqested notifcation");
    const randomSeconds = getRandomIntInclusive(61, 75);

    const months = [
      "January",
      "February",
      "March",
      "April",
      "May",
      "June",
      "July",
    ];
    const random = Math.floor(Math.random() * months.length);

    Notifications.scheduleNotificationAsync({
      content: {
        title: `${months[random]} is random`,
        data: { screen: "screenName", show_time: randomSeconds },
      },
      trigger: {
        seconds: randomSeconds,
        repeats: true,
      },
    });
    await Notifications.cancelAllScheduledNotificationsAsync();
    getScheduled();
  }

  async function registerForPushNotificationsAsync() {
    let token;

    if (Platform.OS === "android") {
      await Notifications.setNotificationChannelAsync("default", {
        name: "default",
        importance: Notifications.AndroidImportance.MAX,
        vibrationPattern: [0, 250, 250, 250],
        lightColor: "#FF231F7C",
      });
    }

    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!");
        return;
      }
      token = (await Notifications.getExpoPushTokenAsync()).data;
      console.log(token);
    } else {
      alert("Must use physical device for Push Notifications");
    }

    return token;
  }

  async function givenPermissions() {
    if (Device.isDevice) {
      const { status: existingStatus } =
        await Notifications.getPermissionsAsync();
      if (existingStatus !== "granted") {
        setGivenNotificationPerm(false);
      }
      setGivenNotificationPerm(true);
    } else {
      alert("Must use physical device for Push Notifications");
    }
  }

  return {
    expoPushToken,
    notification,
    permissions,
    schedulePushNotification,
    givenNotificationPerm,
  };
}

Pastebin code

And then for the App.js screen:

export default function App() {
  const { permissions, schedulePushNotification } = useNotifications();

  return(
    <>
    <Button title="Enable notifications - onboarding screen only button" onPress={permissions} />
    <Button title="Schedule notification" onPress={schedulePushNotification} />
    </>
  )
}

Click the button multiple times, multiple notifications scheduled with random time and month for example purposes but how would i put this into practice to create an almost automation desire?

Right now my brain is thinking of just creating an array of 5 notifications and schedule them all in one go and then after X time has passed produce another 5 notifications but to do that i would have to ensure the user comes on the app within that timeframe to schedule more etc.

Bit stuck. Help appreciated

Thanks so much.

Jack
  • 11
  • 4
  • Did you think about CRON JOB with a cloud function? – Fiston Emmanuel Jan 06 '23 at 21:42
  • Firebase Cloud function should be a reference - https://firebase.google.com/docs/functions/schedule-functions – Fiston Emmanuel Jan 06 '23 at 21:42
  • @FistonEmmanuel oooo i didn't think about trying that. How exactly would that work? How would it be triggered? Anymore details/example of how it would work with the expo library would be much appreciated. Thankyou so much. – Jack Jan 07 '23 at 10:03
  • Expo provides simple REST API - https://docs.expo.dev/push-notifications/sending-notifications/ from their server. You can simply run push code inside CRON JOB – Fiston Emmanuel Jan 07 '23 at 14:53

0 Answers0