How to make Android notifications actually reliable
Exact alarms, Doze, standby buckets and the OEM battery managers that break reminders — what we learned shipping prayer alerts.
If you build any app that depends on telling someone something at a specific moment — a prayer time, a medication reminder, a timer ending — you will eventually meet the hardest problem in Android development. Not rendering, not storage. Getting a notification to appear on time on a phone you do not own.
This is what we learned building the reminder system in Salah Companion, written for developers, with a section at the end for users who just want their alerts to arrive.
The platform baseline
Android's own rules are documented and reasonable:
- Doze batches deferrable work when the device is idle. Ordinary background work waits for a maintenance window.
- App Standby Buckets demote apps you rarely open, further restricting their background allowance.
- Exact alarms are the sanctioned escape hatch for genuinely time-critical alerts, and since Android 12 they require the
SCHEDULE_EXACT_ALARMorUSE_EXACT_ALARMpermission.
If your notification must arrive at a specific minute, setExactAndAllowWhileIdle (or setAlarmClock) is the mechanism. WorkManager is excellent for sync and upload; it is the wrong tool for "notify at 05:14 tomorrow", because it is explicitly allowed to defer.
The OEM layer is where it actually breaks
The platform is only half the story. Manufacturers add their own battery managers on top, and they are more aggressive than stock Android:
- Xiaomi (MIUI/HyperOS), Oppo and Vivo (ColorOS/FuntouchOS), Realme and OnePlus historically require the app to be present in an Autostart list before it may schedule anything after a reboot or a swipe-away.
- Several OEMs kill an app's alarms when the user swipes it from Recents.
- Some restrict apps that have not been opened for a few days, regardless of standby bucket.
The community-maintained site dontkillmyapp.com is the practical reference here, and it exists because this problem is real and vendor-specific.
What we do in the app
- 1.Schedule exact alarms, and reschedule generously. After each fired alarm, after a boot-completed broadcast, after a time-zone change, and whenever the app is opened.
- 2.Handle `BOOT_COMPLETED` and `TIMEZONE_CHANGED`. Alarms do not survive a reboot. This is the single most common reason a reminder app stops working "randomly" after a week.
- 3.Check permission state at runtime.
AlarmManager.canScheduleExactAlarms()tells you whether you still have the right; the user can revoke it, and Android may reset it. Detect it, do not assume it. - 4.Use notification channels per alert type. Sound and importance belong to the channel, and once a user silences one, the app cannot override it. Separate channels mean a user can silence one prayer without silencing all of them.
- 5.Verify, do not hope. We ship a test alert that goes through the identical scheduling path, so a user can confirm the real behaviour rather than the intended behaviour.
- 6.Ask for the OEM exemptions, in context. Not on first launch in a wall of dialogs, but at the moment the user turns on their first reminder, with an explanation of why it is needed.
Detecting the failure instead of guessing
Log the scheduled time and the delivered time. If the gap grows over days, the app is being demoted or killed. That signal, gathered from a handful of users on the same manufacturer, is worth more than any amount of speculation on a forum.
For users: the five-minute fix
If a reminder app is late or silent on your phone:
- 1.Allow Alarms & reminders for the app.
- 2.Set its battery usage to Unrestricted, not Optimised.
- 3.Add it to Autostart (Xiaomi, Oppo, Vivo, Realme, OnePlus).
- 4.Lock it in Recents so cleaners do not kill it.
- 5.Allow it as an exception in Do Not Disturb if you use DND.
The honest conclusion
There is no single API call that guarantees delivery on every Android device. What you can do is use the correct mechanism, reschedule defensively, handle reboots, respect notification channels, give users a way to test, and be explicit about the phone-specific settings that no app can change for them. Everything else is wishful thinking with a progress bar.