Expo scheduled daily notification - how to not get stacked notifications in the tray?

137 Views Asked by At

So, I'm using expo-notifications, and I'm scheduling a daily notification using

 Notifications.scheduleNotificationAsync({
            content: {
              title: "Title",
              body: 'Message',
            },
            trigger: {
              hour: hrInt,
              minute: minInt,
              repeats: true,
            },
          });

hrInt and minInt are constants passed by user input and everything works fine.

The problem is this: If the user didn't interact with the notification (tapped on or cleared it) by the time the next notification should arrive, they will stack, so the user might have 2,3,4 or maybe 100 notifications in their tray. I don't want this behavior.

I would like either:

Solution A: Somehow dismiss the notification from the tray before the next notification will arrive,

or

Solution B: not send a new notification if the notification in the tray is still there.

For solution A:

I tried scheduling a background task to set a time for dismissing previous notifications, using Expo Task Manager and Expo Background Fetch Libraries.

  • Inside the function where I'm scheduling the notification, I'm getting the current time it was called, and then calculating the difference between the current time and the notification time. Say it's now 10:32:20 and the notification is scheduled to 10:34:00, the time for the task would be 1 min and 40 sec (100 sec), and I would substract a few seconds from it.

It would be like this:

const BACKGROUND_FETCH_TASK = 'background-fetch';

TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {

  Notifications.dismissAllNotificationsAsync();

  return BackgroundFetch.BackgroundFetchResult.NewData;
});

async function unregisterBackgroundFetchAsync() {

  return BackgroundFetch.unregisterTaskAsync(BACKGROUND_FETCH_TASK);
}
async function registerBackgroundFetchAsync(taskTime) {

  const taskRegistration = await BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
    minimumInterval: taskTime,
    stopOnTerminate: false,
    startOnBoot: true,
  });

  if (taskRegistration) {
    console.log('Unregistering background fetch task');
    await BackgroundFetch.unregisterTaskAsync(BACKGROUND_FETCH_TASK);
  }
}

and

useEffect(() => {
      MakeNotificationTime();
    }, [])

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


    const MakeNotificationTime = async () => {

      Notifications.cancelAllScheduledNotificationsAsync();

      const hr = (await getData('notificationHr')) ?? 12;
      const min = (await getData('notificationMin')) ?? 0;
      const hrInt = parseInt(hr);
      const minInt = parseInt(min)

      const now = new Date();
      const nowHr = now.getHours();
      const nowMin = now.getMinutes()
      const nowSec = now.getSeconds()

      const hrDif = hrInt - nowHr;
      const minDif = minInt - nowMin;

      const taskTime = (hrDif * 60 * 60) + (minDif * 60) - nowSec - 5;
      console.log("Task time: " + taskTime)


        Notifications.scheduleNotificationAsync({
            content: {
              title: "Title",
              body: 'Message',
            },
            trigger: {
              hour: hrInt,
              minute: minInt,
              repeats: true,
            },
          });
  
        
        unregisterBackgroundFetchAsync();
        registerBackgroundFetchAsync(taskTime);

        checkStatusAsync();

        getAllScheduledNotifications();
      
    }

This would just behave unexpectedly. It seems the BackgroundFetch would start counting only after the app goes to background, and I want it to start counting right after it is registered. Also the behavior is quite weird, sometimes it works, sometimes not.

For solution B:

I can potentially schedule a notification that is non-repeating, and then schedule it again when the notification in the tray is tapped or when the user enters the app, by listening to interaction with the notificaion. But Expo's addNotificationResponseRecivedListener would not listen to when the notification is cleared by the user, so if the user would clear it, the notification wouldn't fire again, and that may create confusion in the user and it's not an optimal behavior since it is meant to schedule a daily repeating notification, even if it's cleared.

Anyway I'm really stuck. Anyone got ideas?

1

There are 1 best solutions below

0
On

The solution is very simple...

If you schedule the notification with an ID, the new notification simply replaces the previous one.