-
-
Notifications
You must be signed in to change notification settings - Fork 72
3. Scheduled Android notifications
This guide covers implementing scheduled notifications in Android, including potential challenges and best practices.
Note:
NotificationRequestSchedule.NotifyTimeandNotifyAutoCancelTimeareDateTimeOffset?. Always useDateTimeOffset.Nowso timezone information is preserved correctly.
using Plugin.LocalNotification;
using Plugin.LocalNotification.Core.Models;
var scheduledNotification = new NotificationRequest
{
NotificationId = 100,
Title = "Scheduled Reminder",
Description = "This is a scheduled notification",
Schedule =
{
NotifyTime = DateTimeOffset.Now.AddHours(1), // Schedule for 1 hour later
RepeatType = NotificationRepeat.No // One-time notification
}
};
await LocalNotificationCenter.Current.Show(scheduledNotification);var recurringNotification = new NotificationRequest
{
NotificationId = 101,
Title = "Daily Reminder",
Description = "This notification repeats daily",
Schedule =
{
NotifyTime = DateTimeOffset.Now.AddDays(1),
RepeatType = NotificationRepeat.Daily
}
};
await LocalNotificationCenter.Current.Show(recurringNotification);var monthlyNotification = new NotificationRequest
{
NotificationId = 102,
Title = "Monthly Report",
Description = "Reminder to submit your monthly report",
Schedule =
{
NotifyTime = DateTimeOffset.Now.AddMonths(1),
RepeatType = NotificationRepeat.Monthly // fires on the same day of each month
}
};
await LocalNotificationCenter.Current.Show(monthlyNotification);On iOS and macOS,
Monthlymaps to aUNCalendarNotificationTriggerwithDay,Hour,Minute, andSecondcomponents, which the system repeats once per calendar month. On Android, the next fire time is calculated withDateTimeOffset.AddMonths(1), correctly handling months of different lengths (e.g., scheduling from 31 Jan advances to 28 Feb, not March).
Android 12+ requires the SCHEDULE_EXACT_ALARM (or USE_EXACT_ALARM) permission for precise alarm delivery. Use AndroidScheduleOptions.ScheduleMode to select the right trade-off between battery impact and delivery precision:
var preciseNotification = new NotificationRequest
{
NotificationId = 103,
Title = "Exact Alarm",
Description = "Delivered precisely at the scheduled time",
Schedule =
{
NotifyTime = DateTimeOffset.Now.AddHours(2),
Android =
{
ScheduleMode = AndroidScheduleMode.ExactAllowWhileIdle // fires even in Doze mode
}
}
};
await LocalNotificationCenter.Current.Show(preciseNotification);| Value | AlarmManager API | Fires in Doze | Permission (API 31+) | Best for |
|---|---|---|---|---|
Default |
Exact if permitted, Inexact otherwise | Yes (*AllowWhileIdle) |
Optional | Most apps (backward-compatible) |
Inexact |
set() |
No | None | Non-time-critical reminders |
InexactAllowWhileIdle |
setAndAllowWhileIdle() |
Yes | None | Battery-friendly but Doze-safe |
Exact |
setExact() / setExactAndAllowWhileIdle()
|
Yes (API 23+) | Required | Precise scheduling |
ExactAllowWhileIdle |
setExactAndAllowWhileIdle() |
Yes | Required | Precise + Doze-safe |
AlarmClock |
setAlarmClock() |
Yes | None (exempt) | User-set alarms, shown in clock UI |
Tip:
AlarmClockis exempt from theSCHEDULE_EXACT_ALARMrequirement on API 31+ and is the most reliable delivery path for user-facing alarms. It displays a clock icon in the status bar.
Many Android manufacturers implement aggressive battery optimization that can affect scheduled notifications:
| Manufacturer | Known Issues | Solution Link |
|---|---|---|
| Xiaomi | MIUI's battery saver blocks background services | Fix for Xiaomi |
| Huawei | EMUI's protected apps list | Fix for Huawei |
| Samsung | Maximum 500 scheduled alarms | Android Documentation |
| OnePlus | Aggressive background app management | Fix for OnePlus |
- Samsung devices: Maximum 500 concurrent alarms via AlarmManager
- Android Doze mode may delay notifications
- Background restrictions in newer Android versions
public async Task CheckBatteryOptimization()
{
if (DeviceInfo.Platform == DevicePlatform.Android)
{
// Request user to disable battery optimization
await Launcher.OpenAsync("package:com.android.settings");
}
}// Keep track of scheduled notifications
public async Task ManageScheduledNotifications()
{
// Get all pending notifications
var pending = await LocalNotificationCenter.Current.GetPendingNotificationList();
// Clean up old notifications
foreach (var notification in pending)
{
if (notification.Schedule.NotifyTime < DateTimeOffset.Now)
{
await LocalNotificationCenter.Current.Cancel(notification.NotificationId);
}
}
}public async Task ScheduleWithRetry(NotificationRequest request, int maxRetries = 3)
{
for (int i = 0; i < maxRetries; i++)
{
try
{
await LocalNotificationCenter.Current.Show(request);
break;
}
catch (Exception ex)
{
if (i == maxRetries - 1)
throw;
await Task.Delay(1000); // Wait before retry
}
}
}Instruct users to:
- Open device Settings
- Navigate to Battery/Power settings
- Find your app in the list
- Disable battery optimization or add to protected apps
Ensure users grant necessary permissions:
- Background execution
- Autostart (on some devices)
- Battery optimization exceptions
Check:
- Battery optimization settings
- Background permissions
- System time accuracy
- Notification channel configuration
Possible causes:
- Doze mode
- Battery optimization
- System load
- Network connectivity (if relevant)
Solutions:
- Test on multiple device brands
- Implement device-specific workarounds
- Use foreground services for critical notifications
- Consider push notifications as alternative
- Don't Kill My App - Device-specific solutions
- Android AlarmManager Documentation
- Background Execution Limits
If you encounter device-specific problems:
- Document the device model and Android version
- Note any battery optimization settings
- Record the timing of the issue
- Share your notification scheduling code
- Create an issue in the GitHub repository