- Add platform capability reference (Android & iOS OS-level facts) - Add plugin behavior exploration template (executable test matrices) - Add plugin requirements & implementation directive - Add Android-specific implementation directive with detailed test procedures - Add exploration findings from code inspection - Add improvement directive for refining documentation structure - Add Android alarm persistence directive (OS capabilities) All documents include: - File locations, function references, and line numbers - Detailed test procedures with ADB commands - Cross-platform comparisons - Implementation checklists and code examples
14 KiB
Platform Capability Reference: Android & iOS Alarm/Notification Behavior
Author: Matthew Raymer
Date: November 2025
Status: Platform Reference - Stable
Purpose
This document provides pure OS-level facts about alarm and notification capabilities on Android and iOS. It contains no plugin-specific logic—only platform mechanics that affect plugin design.
This is a reference document to be consulted when designing plugin behavior, not an implementation guide.
1. Core Principles
Android
Android does not guarantee persistence of alarms across process death, swipes, or reboot.
It is the app's responsibility to persist alarm definitions and re-schedule them under allowed system conditions.
iOS
iOS does persist scheduled local notifications across app termination and device reboot, but:
- App code does not run when notifications fire (unless user interacts)
- Background execution is severely limited
- Plugin must persist its own state if it needs to track or recover missed notifications
2. Android Alarm Capability Matrix
| Scenario | Will Alarm Fire? | OS Behavior | App Responsibility |
|---|---|---|---|
| Swipe from Recents | ✅ Yes | AlarmManager resurrects the app process | None (OS handles) |
| App silently killed by OS | ✅ Yes | AlarmManager still holds scheduled alarms | None (OS handles) |
| Device Reboot | ❌ No (auto) / ✅ Yes (if you reschedule) | All alarms wiped on reboot | Must reschedule from persistent storage on boot |
| Doze Mode | ⚠️ Only "exact" alarms | Inexact alarms deferred; exact alarms allowed | Must use setExactAndAllowWhileIdle |
| Force Stop | ❌ Never | Android blocks all callbacks + receivers until next user launch | Cannot bypass; must detect on app restart |
| User reopens app | ✅ You may reschedule & recover | App process restarted | Must detect missed alarms and reschedule future ones |
| PendingIntent from user interaction | ✅ If triggered by user | User action unlocks the app | None (OS handles) |
Android Allowed Behaviors
2.1 Alarms survive UI kills (swipe from recents)
AlarmManager.setExactAndAllowWhileIdle(...) alarms will fire even after:
- App is swiped away
- App process is killed by the OS
The OS recreates your app's process to deliver the PendingIntent.
Required API: setExactAndAllowWhileIdle() or setAlarmClock()
2.2 Alarms can be preserved across device reboot
Android wipes all alarms on reboot, but you may recreate them.
Required Components:
- Persist all alarms in storage (Room DB or SharedPreferences)
- Add a
BOOT_COMPLETED/LOCKED_BOOT_COMPLETEDbroadcast receiver - On boot, load all enabled alarms and reschedule them using AlarmManager
Permissions required: RECEIVE_BOOT_COMPLETED
Conditions: User must have launched your app at least once before reboot
2.3 Alarms can fire full-screen notifications and wake the device
Required API: setFullScreenIntent(...), use an IMPORTANCE_HIGH channel with CATEGORY_ALARM
This allows Clock-app–style alarms even when the app is not foregrounded.
2.4 Alarms can be restored after app restart
If the user re-opens the app (direct user action), you may:
- Scan the persistent DB
- Detect "missed" alarms
- Reschedule future alarms
- Fire "missed alarm" notifications
- Reconstruct WorkManager/JobScheduler tasks wiped by OS
Required: Create a ReactivationManager that runs on every app launch
Android Forbidden Behaviors
3.1 You cannot survive "Force Stop"
Settings → Apps → YourApp → Force Stop triggers:
- Removal of all alarms
- Removal of WorkManager tasks
- Blocking of all broadcast receivers (including BOOT_COMPLETED)
- Blocking of all JobScheduler jobs
- Blocking of AlarmManager callbacks
- Your app will NOT run until the user manually launches it again
Directive: Accept that FORCE STOP is a hard kill. No scheduling, alarms, jobs, or receivers may execute afterward.
3.2 You cannot auto-resume after "Force Stop"
You may only resume tasks when:
- The user opens your app
- The user taps a notification belonging to your app
- The user interacts with a widget/deep link
- Another app explicitly targets your component
Directive: Provide user-facing reactivation pathways (icon, widget, notification).
3.3 Alarms cannot be preserved solely in RAM
Android can kill your app's RAM state at any time.
Directive: All alarm data must be persisted in durable storage.
3.4 You cannot bypass Doze or battery optimization restrictions without permission
Doze may defer inexact alarms; exact alarms with setExactAndAllowWhileIdle are allowed.
Required Permission: SCHEDULE_EXACT_ALARM on Android 12+ (API 31+)
3. iOS Notification Capability Matrix
| Scenario | Will Notification Fire? | OS Behavior | App Responsibility |
|---|---|---|---|
| Swipe from App Switcher | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) |
| App Terminated by System | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) |
| Device Reboot | ✅ Yes (for calendar/time triggers) | iOS persists scheduled local notifications across reboot | None for notifications; must persist own state if needed |
| App Force Quit (swipe away) | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) |
| Background Execution | ❌ No arbitrary code | Only BGTaskScheduler with strict limits | Cannot rely on background execution for recovery |
| Notification Fires | ✅ Yes | Notification displayed; app code does NOT run unless user interacts | Must handle missed notifications on next app launch |
| User Taps Notification | ✅ Yes | App launched; code can run | Can detect and handle missed notifications |
iOS Allowed Behaviors
3.1 Notifications survive app termination
UNUserNotificationCenter scheduled notifications will fire even after:
- App is swiped away from app switcher
- App is terminated by system
- Device reboots (for calendar/time-based triggers)
Required API: UNUserNotificationCenter.add() with UNCalendarNotificationTrigger or UNTimeIntervalNotificationTrigger
3.2 Notifications persist across device reboot
iOS automatically persists scheduled local notifications across reboot.
No app code required for basic notification persistence.
Limitation: Only calendar and time-based triggers persist. Location-based triggers do not.
3.3 Background tasks for prefetching
Required API: BGTaskScheduler with BGAppRefreshTaskRequest
Limitations:
- Minimum interval between tasks (system-controlled, typically hours)
- System decides when to execute (not guaranteed)
- Cannot rely on background execution for alarm recovery
- Must schedule next task immediately after current one completes
iOS Forbidden Behaviors
4.1 App code does not run when notification fires
When a scheduled notification fires:
- Notification is displayed to user
- No app code executes unless user taps the notification
- Cannot run arbitrary code at notification time
Workaround: Use notification actions or handle missed notifications on next app launch.
4.2 No repeating background execution
iOS does not provide repeating background execution APIs except:
BGTaskScheduler(system-controlled, not guaranteed)- Background fetch (deprecated, unreliable)
Directive: Plugin cannot rely on background execution to reconstruct alarms. Must persist state and recover on app launch.
4.3 No arbitrary code on notification trigger
Unlike Android's PendingIntent which can execute code, iOS notifications only:
- Display to user
- Launch app if user taps
- Execute notification action handlers (if configured)
Directive: All recovery logic must run on app launch, not at notification time.
4.4 Background execution limits
BGTaskScheduler Limitations:
- Minimum intervals between tasks (system-controlled)
- System may defer or skip tasks
- Tasks have time budgets (typically 30 seconds)
- Cannot guarantee execution timing
Directive: Use BGTaskScheduler for prefetching only, not for critical scheduling.
4. Cross-Platform Comparison
| Feature | Android | iOS |
|---|---|---|
| Survives swipe/termination | ✅ Yes (with exact alarms) | ✅ Yes (automatic) |
| Survives reboot | ❌ No (must reschedule) | ✅ Yes (automatic for calendar/time triggers) |
| App code runs on trigger | ✅ Yes (via PendingIntent) | ❌ No (only if user interacts) |
| Background execution | ✅ WorkManager, JobScheduler | ⚠️ Limited (BGTaskScheduler only) |
| Force stop equivalent | ✅ Force Stop (hard kill) | ❌ No user-facing equivalent |
| Boot recovery required | ✅ Yes (must implement) | ❌ No (OS handles) |
| Missed alarm detection | ✅ Must implement on app launch | ✅ Must implement on app launch |
| Exact timing | ✅ Yes (with permission) | ⚠️ ±180s tolerance |
| Repeating notifications | ✅ Must reschedule each occurrence | ✅ Can use repeats: true in trigger |
5. Required Platform APIs
Android
Alarm Scheduling:
AlarmManager.setExactAndAllowWhileIdle()- Android 6.0+ (API 23+)AlarmManager.setAlarmClock()- Android 5.0+ (API 21+)AlarmManager.setExact()- Android 4.4+ (API 19+)
Permissions:
RECEIVE_BOOT_COMPLETED- Boot receiverSCHEDULE_EXACT_ALARM- Android 12+ (API 31+)
Background Work:
WorkManager- Deferrable background workJobScheduler- Alternative (API 21+)
iOS
Notification Scheduling:
UNUserNotificationCenter.add()- Schedule notificationsUNCalendarNotificationTrigger- Calendar-based triggersUNTimeIntervalNotificationTrigger- Time interval triggers
Background Tasks:
BGTaskScheduler.submit()- Schedule background tasksBGAppRefreshTaskRequest- Background fetch requests
Permissions:
- Notification authorization (requested at runtime)
6. Platform-Specific Constraints Summary
Android Constraints
- Reboot: All alarms wiped; must reschedule from persistent storage
- Force Stop: Hard kill; cannot bypass until user opens app
- Doze: Inexact alarms deferred; must use exact alarms
- Exact Alarm Permission: Required on Android 12+ for precise timing
- Boot Receiver: Must be registered and handle
BOOT_COMPLETED
iOS Constraints
- Background Execution: Severely limited; cannot rely on it for recovery
- Notification Firing: App code does not run; only user interaction triggers app
- Timing Tolerance: ±180 seconds for calendar triggers
- BGTaskScheduler: System-controlled; not guaranteed execution
- State Persistence: Must persist own state if tracking missed notifications
Related Documentation
- Plugin Behavior Exploration Template - Uses this reference
- Plugin Requirements & Implementation - Implementation based on this reference
- Android Alarm Persistence Directive - Original Android reference
- Improve Alarm Directives - Improvement directive
Version History
- v1.0 (November 2025): Initial platform capability reference
- Android alarm matrix
- iOS notification matrix
- Cross-platform comparison