Capacitor Local Notifications don't fire on Android, and randomly fire on iOS

Hey all,

I have a React/Ionic app that uses capacitor local notifications v4.0.0. I have followed the instructions on the documentation to the best of my ability and included the

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

In my androidManifest.xml

For whatever reason, my android monthly notifications never fire, despite passing all my jest tests. My iOS notifications fire every few days. Both should fire off a local notification on the 27th of every month. I am absolutely confused, and unfortunately this is a mission critical part of my application. What am I doing wrong?

Here is my code:

import { useEffect } from 'react';
import { LocalNotifications } from '@capacitor/local-notifications';
import { Storage } from '@capacitor/storage';

import getNextNotificationDates from '../util/getNextNotificationDates';

const useLocalNotifications = () => {
  const STORAGE_KEY = '2023-04-23';

  const scheduleYearlyNotifications = async () => {
    const pending = await LocalNotifications.getPending();
    const currentDate = new Date().toISOString();

    if (
      !pending.notifications.some((notification) =>
        [1, 2, 3].includes(notification.id)
      )
    ) {
      const [nextJuly1st, nextSept23rd, nextSept30th] =
        getNextNotificationDates(currentDate);

      LocalNotifications.schedule({
        notifications: [
          {
            title: `Claim Your Tax Refund Now! 💰`,
            body: 'You can now file for your fuel refund! Press the file return button to get started.',
            id: 1,
            schedule: { at: nextJuly1st, allowWhileIdle: true },
          },
          {
            title: 'One Week Left To File! ⏳',
            body: 'You have one week left to file for your fuel refund!',
            id: 2,
            schedule: { at: nextSept23rd, allowWhileIdle: true },
          },
          {
            title: 'One Day Left To File! 🚨⏰',
            body: 'Today is the last day to file for your fuel refund!',
            id: 3,
            schedule: { at: nextSept30th, allowWhileIdle: true },
          },
        ],
      });
    }
  };

  const scheduleMonthlyNotification = async () => {
    const pending = await LocalNotifications.getPending();

    if (!pending.notifications.some((notification) => notification.id === 4)) {
      LocalNotifications.schedule({
        notifications: [
          {
            title: 'Monthly Receipt Reminder ⛽️',
            body: `Don't forget to upload your fuel receipts!`,
            id: 4,
            schedule: {
              on: {
                day: 27,
                hour: 12,
                minute: 0,
                second: 0,
              },
              allowWhileIdle: true,
            },
          },
        ],
      });
    }
  };

  useEffect(() => {
    (async () => {
      try {
        const permissions = await LocalNotifications.requestPermissions();

        if (permissions.display === 'granted') {
          const pending = await LocalNotifications.getPending();
          console.log('pending', pending);
          const { value } = await Storage.get({ key: 'notificationsSetUp' });
          console.log('value', value);
          if (!value || value !== STORAGE_KEY) {
            await scheduleYearlyNotifications();
            await scheduleMonthlyNotification();
            await Storage.set({
              key: 'notificationsSetUp',
              value: STORAGE_KEY,
            });
          }

          console.log('pending', await LocalNotifications.getPending());

          LocalNotifications.addListener(
            'localNotificationReceived',
            async (notification) => {
              switch (notification.id) {
                case 1:
                case 2:
                case 3:
                  // Remove the current yearly notifications
                  await LocalNotifications.cancel({
                    notifications: [{ id: 1 }, { id: 2 }, { id: 3 }],
                  });

                  // Reschedule the yearly notifications
                  await scheduleYearlyNotifications();
                  break;

                case 4:
                  // Remove the current yearly notifications
                  await LocalNotifications.cancel({
                    notifications: [{ id: 4 }],
                  });

                  // Reschedule the monthly notifications
                  await scheduleMonthlyNotification();
                  break;

                default:
                  console.log(
                    'Unknown notification ID received:',
                    notification.id
                  );
              }
            }
          );
        } else {
          console.log('User denied local notifications');
        }
      } catch (e) {
        console.log('e', e);
      }
    })();
  }, []);

  return null;
};

export default useLocalNotifications;

Quickly looking at things, it’s had to tell without seeing a full working demo.

Can you isolate it in a git repo and we can test that?

EDIT: Also adding that @capacitor/storage was deprecated and renamed to @capacitor/preferences last year, so not sure if that could be causing issues.

Interesting catch on the deprecated capacitor package. Let me update that later in the day and see if that clears up any issues. If not, I will try and report back with a working sample

hi! I’m currently having the same issue as you with the last version of Capacitor 4. On IOS, it fires radomnly ignoring the schedule completly… could you help me with a fix for this?

Seems that the documentation for Android is not completed on the page. I’m doiong exactly what is documented on the guide but i’m not able to get any notification scheduled on Android. It’s working pretty good on IOS but Android…

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

This was added to the AndroidManifest.xml.
and the next lines are the configuration and code that i did for schedule local notifications:

var notificationsLIST: LocalNotificationSchema[] = [];

if (this.device.includes("android")) {

        await LocalNotifications.createChannel({
          id: "alertas",
          name: "alertas",
          description: "Canal para notificaciones locales",
          sound: "beep.wav",
          importance: 3,
          lights: true,
          vibration: true
        });
}

var objectChedule: LocalNotificationSchema = {
              title: "Portal del empleado",
              body: "Recuerde registrar su jornada en el sistema de fichaje.",
              id: randomID (this is a variable),
              schedule: {
                every: "week",
                on: {
                  hour: hour (this is a variable),
                  minute: minute (this is a variable),
                  weekday: valorDia (this is a variable)
                }
              }
            };

if (this.device.includes("android")) {
              objectChedule.channelId = "alertas";
              objectChedule.schedule.allowWhileIdle = true;
 }

notificationsLIST.push(objectChedule);

 var scheduleResult: ScheduleResult = await LocalNotifications.schedule(
        {
          notifications: notificationsLIST
        }
);

This code is working pretty good on IOS, but Android seems like is not working. Not working on android 13, and the next configuration on variables.gradle.

    minSdkVersion = 22
    compileSdkVersion = 33
    targetSdkVersion = 33
    androidxActivityVersion = '1.4.0'
    androidxAppCompatVersion = '1.4.2'
    androidxCoordinatorLayoutVersion = '1.2.0'
    androidxCoreVersion = '1.8.0'
    androidxFragmentVersion = '1.4.1'
    coreSplashScreenVersion = '1.0.0-rc01'
    androidxWebkitVersion = '1.4.0'
    junitVersion = '4.13.2'
    androidxJunitVersion = '1.1.3'
    androidxEspressoCoreVersion = '3.4.0'
    cordovaAndroidVersion = '10.1.1'
    firebaseMessagingVersion = '23.0.5'
    playServicesLocationVersion = '20.0.0'
    androidPlayCore = '1.9.0'
}

image

First, you need to upgrade to Capacitor 5 so you can upgrade Local Notifications to v5. v5 supports requesting and checking permissions that were added as a requirement in Android 13.

  • local-notifications: support Android 13+ permissions (#1189) (ace7d73)

Source

So you think these notifications are not firing because i’m using capacitor 4?
I’ll try to upgrade to capacitor 5 the application then.

is the code is properly applied? i mean, i’m not doing anything wrong for schedule notifications… right?

Don’t bother upgrading. It does not work in 5 either. I noticed on android using the cron for notifications I had to subtract one from the number I needed. So August would be 7, etc.

I tried too with capacitor 5 and is not working…
so any way to schedule on android???

The problem what i see is that using capacitor 5 and the last version of Local notifications- capacitor plugin, if i use checkPermissions(), it always return ‘granted’, never showed to me the propmpt asking for any permission. I uninstalled the applications and started again and it works as the same way. Always ‘granted’. So i checked the app configuration on android and it has the notifications activated by default and the channel created correctly, but NEVER fire any schedule notifications.

I am running Capacitor 5 and have both the permission prompt working on Android 13+ and have notifications working being scheduled daily at a specific time so the plugin definitely works :slight_smile:

I think we need a full isolated example in a Git repo as mhartington mentioned.

I do see though that you are using every and on for your schedule. I believe you only want to use one or the other. The documentation says: “Use either at, on, or every to schedule notifications.”

I’ll try to prepare a git repo with an example, but as you said, maybe i should delete the ‘every’ property.
The problem is that i want the schedule every week of the year…

do you think that with this:

on: {
     hour: hour (this is a variable),
     minute: minute (this is a variable),
     weekday: valorDia (this is a variable)
}

it will be fired every week? not necesary the ‘every’ property?

I would say you are correct from my understanding. Adding weekday to on and removing every should do what you are looking for. weekday was added after I implemented reminders in my app so I haven’t used it yet but will be soon.

1 Like

I’ve been facing a similar issue with Capacitor local notifications on Android, and it’s been quite a puzzle to solve. In my case, I found that ensuring the app is running in the foreground seems to help with Android notifications not firing consistently. Also, double-checking the notification scheduling code and permissions is crucial. Sometimes, seemingly unrelated code changes can affect notifications.

1 Like

done! the mistake was the ‘every’.
Using ‘on’ is everything i need as you said, and the ‘every’ was broking the cron schedule on Android.
Maybe is necesary a return Object or something like that on the Schedule() from LocalNotifications… hope capacitor’s team read this.