A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
Hello @fatih uyanık !
If you're using alarmManager.SetExactAndAllowWhileIdle(...) to trigger hourly announcements in your MAUI Android app but are seeing 2–5 minute delays or missed alarms. This isn't a bug in your code, it result of Android’s power management and OEM customizations, please refer to this link for more detail:
https://developer.android.com/training/monitoring-device-state/doze-standby
On Android 6.0+, when the device is idle (screen off, not charging), Android enters Doze mode and batches alarms to conserve battery. setExactAndAllowWhileIdle() bypasses some batching, but not all, especially if alarms are frequent. Android enforces a minimum interval between exact‑while‑idle alarms (often ~15 minutes) in deep idle.
If you want hourly, on‑the‑dot announcements without drift or skips, across all devices, here are the steps you can follow:
- Request the right permissions: On Android 12+, you must declare:
<!-- Exact alarms (API 31+) --> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <!-- Only if you will guide user to ignore battery optimizations --> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> - Use the right alarm type: Use
AlarmType.RtcWakeupso the device wakes up to deliver the alarm. - Reschedule manually: Don’t use
setRepeating(), it’s not exacted in Doze mode. Instead, when the alarm fires, you can calculate the next top‑of‑hour and schedule it again.// Compute next top-of-hour (wall clock) using local time var now = DateTime.Now; var next = new DateTime( now.Year, now.Month, now.Day, now.Hour, 0, 0, DateTimeKind.Local ).AddHours(1); // Convert to epoch ms (UTC) for AlarmManager.RtcWakeup long triggerAtMillis = (long)(next.ToUniversalTime() - DateTime.UnixEpoch).TotalMilliseconds; // Reuse a stable PendingIntent (FLAG_UPDATE_CURRENT) alarmManager.SetExactAndAllowWhileIdle( AlarmType.RtcWakeup, triggerAtMillis, pendingIntent ); - Run work in a foreground service: When the alarm fires, you can start a short‑lived foreground service to do the announcement and stop it immediately after work is done. This helps prevent the OS from killing your task mid‑execution.
- Request Battery Optimization Exemption: This tells Android not to defer your alarms when idle
var intent = new Intent(Android.Provider.Settings.ActionRequestIgnoreBatteryOptimizations); intent.SetData(Android.Net.Uri.Parse("package:" + context.PackageName)); context.StartActivity(intent);
Even with all of these measures, Android does not guarantee millisecond‑accurate delivery during deep idle. On devices with aggressive OEM restrictions, small delays may still occur unless the app is explicitly whitelisted. You can refer to dontkillmyapp.com for device-specific guidance, if core functionality is affected, you may guide users to:
- Enable the app’s Auto‑start / Allow background start
- Lock / pin the app in Recents (prevents aggressive cleanup)
- Disable battery optimization, app sleeping, or background restrictions for the app.
Please note that effectiveness varies by OEM and is not guaranteed.
I hope this helps! Let me know if you have any questions, I’m happy to answer! If you find this answer useful, feel free to mark this as final answer!