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,
};
}
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.