# Platform Capability Reference: Android & iOS Alarm/Notification Behavior **Author**: Matthew Raymer **Date**: November 2025 **Status**: Platform Reference - Stable **Version**: 1.1.0 **Last Synced With Plugin Version**: v1.1.0 ## 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. **⚠️ CANONICAL RULE**: No other document may contain OS-level behavior. All platform facts **MUST** reference this file. If platform behavior is described elsewhere, it **MUST** be moved here and replaced with a reference. **⚠️ DEPRECATED**: The following documents are superseded by this reference: - `platform-capability-reference.md` - Merged into this document - `android-alarm-persistence-directive.md` - Merged into this document **See**: [Unified Alarm Directive](./000-UNIFIED-ALARM-DIRECTIVE.md) for document structure. --- ## 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 * Apps must persist their own state if they need to track or recover missed notifications --- ## 2. Android Alarm Capability Matrix | Scenario | Will Alarm Fire? | OS Behavior | App Responsibility | Label | | --------------------------------------- | --------------------------------------- | -------------------------------------------------------------------- | ----------------------------------------------------- | ------------- | | **Swipe from Recents** | ✅ Yes | AlarmManager resurrects the app process | None (OS handles) | OS-guaranteed | | **App silently killed by OS** | ✅ Yes | AlarmManager still holds scheduled alarms | None (OS handles) | OS-guaranteed | | **Device Reboot** | ❌ No (auto) / ✅ Yes (if app reschedules) | All alarms wiped on reboot | Apps may reschedule from persistent storage on boot | Plugin-required | | **Doze Mode** | ⚠️ Only "exact" alarms | Inexact alarms deferred; exact alarms allowed | Apps must use `setExactAndAllowWhileIdle` | Plugin-required | | **Force Stop** | ❌ Never | Android blocks all callbacks + receivers until next user launch | Cannot bypass; apps may detect on app restart | Forbidden | | **User reopens app** | ✅ Apps may reschedule & recover | App process restarted | Apps may detect missed alarms and reschedule future ones | Plugin-required | | **PendingIntent from user interaction** | ✅ If triggered by user | User action unlocks the app | None (OS handles) | OS-guaranteed | ### 2.1 Android Allowed Behaviors #### 2.1.1 Alarms survive UI kills (swipe from recents) **OS-guaranteed**: `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.1.2 Alarms can be preserved across device reboot **Plugin-required**: Android wipes all alarms on reboot, but **apps may recreate them**. **OS Behavior**: All alarms are cleared on device reboot. No alarms persist automatically. **App Capability**: Apps may recreate alarms after reboot by: 1. Persisting alarm definitions in durable storage (Room DB, SharedPreferences, etc.) 2. Registering a `BOOT_COMPLETED` / `LOCKED_BOOT_COMPLETED` broadcast receiver 3. Rescheduling alarms from storage after boot completes **Required Permission**: `RECEIVE_BOOT_COMPLETED` **OS Condition**: User must have launched the app at least once before reboot for boot receiver to execute #### 2.1.3 Alarms can fire full-screen notifications and wake the device **OS-guaranteed**: **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.1.4 Alarms can be restored after app restart **Plugin-required**: If the user re-opens the app (direct user action), apps may: * Access persistent storage (database, files, etc.) * Query alarm definitions * Reschedule alarms using AlarmManager * Reconstruct WorkManager/JobScheduler tasks that were cleared **OS Behavior**: When user opens app, app code can execute. AlarmManager and WorkManager APIs are available for rescheduling. **Note**: This is an app capability, not OS-guaranteed behavior. Apps must implement this logic. ### 2.2 Android Forbidden Behaviors #### 2.2.1 You cannot survive "Force Stop" **Forbidden**: **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. #### 2.2.2 You cannot auto-resume after "Force Stop" **Forbidden**: 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 **OS Behavior**: Apps may only resume tasks when user opens app, taps notification, interacts with widget/deep link, or another app explicitly targets the component. #### 2.2.3 Alarms cannot be preserved solely in RAM **Forbidden**: Android can kill your app's RAM state at any time. **OS Behavior**: All alarm data must be persisted in durable storage. RAM-only storage is not reliable. #### 2.2.4 You cannot bypass Doze or battery optimization restrictions without permission **Conditional**: 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 | Label | | --------------------------------------- | ----------------------- | -------------------------------------------------------------------- | ----------------------------------------------------- | ------------- | | **Swipe from App Switcher** | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) | OS-guaranteed | | **App Terminated by System** | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) | OS-guaranteed | | **Device Reboot** | ✅ Yes (for calendar/time triggers) | iOS persists scheduled local notifications across reboot | None for notifications; must persist own state if needed | OS-guaranteed | | **App Force Quit (swipe away)** | ✅ Yes | UNUserNotificationCenter persists and fires notifications | None (OS handles) | OS-guaranteed | | **Background Execution** | ❌ No arbitrary code | Only BGTaskScheduler with strict limits | Cannot rely on background execution for recovery | Forbidden | | **Notification Fires** | ✅ Yes | Notification displayed; app code does NOT run unless user interacts | Must handle missed notifications on next app launch | OS-guaranteed | | **User Taps Notification** | ✅ Yes | App launched; code can run | Can detect and handle missed notifications | OS-guaranteed | ### 3.1 iOS Allowed Behaviors #### 3.1.1 Notifications survive app termination **OS-guaranteed**: `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.1.2 Notifications persist across device reboot **OS-guaranteed**: 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.1.3 Background tasks for prefetching **Conditional**: **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 ### 3.2 iOS Forbidden Behaviors #### 3.2.1 App code does not run when notification fires **Forbidden**: 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. #### 3.2.2 No repeating background execution **Forbidden**: iOS does not provide repeating background execution APIs except: * `BGTaskScheduler` (system-controlled, not guaranteed) * Background fetch (deprecated, unreliable) **OS Behavior**: Apps cannot rely on background execution to reconstruct alarms. Apps must persist state and recover on app launch. #### 3.2.3 No arbitrary code on notification trigger **Forbidden**: 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) **OS Behavior**: All recovery logic must run on app launch, not at notification time. #### 3.2.4 Background execution limits **Forbidden**: **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 | Label | | -------------------------------- | --------------------------------------- | --------------------------------------------- | ------------- | | **Survives swipe/termination** | ✅ Yes (with exact alarms) | ✅ Yes (automatic) | OS-guaranteed | | **Survives reboot** | ❌ No (must reschedule) | ✅ Yes (automatic for calendar/time triggers) | Mixed | | **App code runs on trigger** | ✅ Yes (via PendingIntent) | ❌ No (only if user interacts) | Mixed | | **Background execution** | ✅ WorkManager, JobScheduler | ⚠️ Limited (BGTaskScheduler only) | Mixed | | **Force stop equivalent** | ✅ Force Stop (hard kill) | ❌ No user-facing equivalent | Android-only | | **Boot recovery required** | ✅ Yes (must implement) | ❌ No (OS handles) | Android-only | | **Missed alarm detection** | ✅ Must implement on app launch | ✅ Must implement on app launch | Plugin-required | | **Exact timing** | ✅ Yes (with permission) | ⚠️ ±180s tolerance | Mixed | | **Repeating notifications** | ✅ Must reschedule each occurrence | ✅ Can use `repeats: true` in trigger | Mixed | --- ## 5. Android API Level Matrix ### 5.1 Alarm Scheduling APIs by API Level | API Level | Available APIs | Label | Notes | | --------- | -------------- | ----- | ----- | | **API 19-20** (KitKat) | `setExact()` | OS-Permitted | May be deferred in Doze | | **API 21-22** (Lollipop) | `setExact()`, `setAlarmClock()` | OS-Guaranteed | `setAlarmClock()` preferred | | **API 23+** (Marshmallow+) | `setExact()`, `setAlarmClock()`, `setExactAndAllowWhileIdle()` | OS-Guaranteed | `setExactAndAllowWhileIdle()` required for Doze | | **API 31+** (Android 12+) | All above + `SCHEDULE_EXACT_ALARM` permission required | Conditional | Permission must be granted by user | ### 5.2 Android S+ Exact Alarm Permission Decision Tree **Android 12+ (API 31+) requires `SCHEDULE_EXACT_ALARM` permission**: ``` Is API level >= 31? ├─ NO → No permission required └─ YES → Check permission status ├─ Granted → Can schedule exact alarms ├─ Not granted → Must request permission │ ├─ User grants → Can schedule exact alarms │ └─ User denies → Cannot schedule exact alarms (use inexact or show error) └─ Revoked → Cannot schedule exact alarms (user must re-enable in Settings) ``` **Label**: Conditional (requires user permission on Android 12+) ### 5.3 Required Platform APIs **Alarm Scheduling**: * `AlarmManager.setExactAndAllowWhileIdle()` - Android 6.0+ (API 23+) - **OS-Guaranteed** * `AlarmManager.setAlarmClock()` - Android 5.0+ (API 21+) - **OS-Guaranteed** * `AlarmManager.setExact()` - Android 4.4+ (API 19+) - **OS-Permitted** (may be deferred in Doze) **Permissions**: * `RECEIVE_BOOT_COMPLETED` - Boot receiver - **OS-Permitted** (requires user to launch app once) * `SCHEDULE_EXACT_ALARM` - Android 12+ (API 31+) - **Conditional** (user must grant) **Background Work**: * `WorkManager` - Deferrable background work - **OS-Permitted** (timing not guaranteed) * `JobScheduler` - Alternative (API 21+) - **OS-Permitted** (timing not guaranteed) ### 5.2 iOS **Notification Scheduling**: * `UNUserNotificationCenter.add()` - Schedule notifications * `UNCalendarNotificationTrigger` - Calendar-based triggers * `UNTimeIntervalNotificationTrigger` - Time interval triggers **Background Tasks**: * `BGTaskScheduler.submit()` - Schedule background tasks * `BGAppRefreshTaskRequest` - Background fetch requests **Permissions**: * Notification authorization (requested at runtime) --- ## 6. iOS Timing Tolerance Table ### 6.1 Notification Timing Accuracy | Trigger Type | Timing Tolerance | Label | Notes | | ------------ | ---------------- | ----- | ----- | | **Calendar-based** (`UNCalendarNotificationTrigger`) | ±180 seconds | OS-Permitted | System may defer for battery optimization | | **Time interval** (`UNTimeIntervalNotificationTrigger`) | ±180 seconds | OS-Permitted | System may defer for battery optimization | | **Location-based** (`UNLocationNotificationTrigger`) | Not applicable | OS-Permitted | Does not persist across reboot | **Source**: [Apple Developer Documentation - UNNotificationTrigger](https://developer.apple.com/documentation/usernotifications/unnotificationtrigger) ### 6.2 Background Task Timing | Task Type | Execution Window | Label | Notes | | --------- | ---------------- | ----- | ----- | | **BGAppRefreshTask** | System-controlled (hours between tasks) | OS-Permitted | Not guaranteed, system decides | | **BGProcessingTask** | System-controlled | OS-Permitted | Not guaranteed, system decides | **Source**: [Apple Developer Documentation - BGTaskScheduler](https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler) --- ## 7. Platform-Specific Constraints Summary ### 6.1 Android Constraints 1. **Reboot**: All alarms wiped; must reschedule from persistent storage 2. **Force Stop**: Hard kill; cannot bypass until user opens app 3. **Doze**: Inexact alarms deferred; must use exact alarms 4. **Exact Alarm Permission**: Required on Android 12+ for precise timing 5. **Boot Receiver**: Must be registered and handle `BOOT_COMPLETED` ### 6.2 iOS Constraints 1. **Background Execution**: Severely limited; cannot rely on it for recovery 2. **Notification Firing**: App code does not run; only user interaction triggers app 3. **Timing Tolerance**: ±180 seconds for calendar triggers 4. **BGTaskScheduler**: System-controlled; not guaranteed execution 5. **State Persistence**: Must persist own state if tracking missed notifications --- ## 8. Revision Sources ### 8.1 AOSP Version **Android Open Source Project**: Based on AOSP 14 (Android 14) behavior **Last Validated**: November 2025 **Source Files Referenced**: * `frameworks/base/core/java/android/app/AlarmManager.java` * `frameworks/base/core/java/android/app/PendingIntent.java` ### 8.2 Official Documentation **Android**: * [AlarmManager - Android Developers](https://developer.android.com/reference/android/app/AlarmManager) * [Schedule exact alarms - Android Developers](https://developer.android.com/training/scheduling/alarms) **iOS**: * [UNUserNotificationCenter - Apple Developer](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter) * [BGTaskScheduler - Apple Developer](https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler) ### 8.3 Tested Device Set **Android Devices Tested**: * Pixel 7 (Android 14) * Samsung Galaxy S23 (Android 13) * OnePlus 11 (Android 13) **iOS Devices Tested**: * iPhone 15 (iOS 17) * iPhone 14 (iOS 16) **Note**: OEM-specific behavior variations documented in [§8 - OEM Variation Policy](#8-oem-variation-policy) ### 8.4 Last Validated on Physical Devices **Last Validation Date**: November 2025 **Validation Scenarios**: * Swipe from recents - ✅ Validated on all devices * Device reboot - ✅ Validated on all devices * Force stop (Android) - ✅ Validated on Android devices * Background execution (iOS) - ✅ Validated on iOS devices **Unvalidated Scenarios**: * OEM-specific variations (Xiaomi, Huawei) - ⚠️ Not yet tested --- ## 9. Label Definitions **Required Labels** (every platform behavior MUST be tagged): | Label | Definition | Usage | | ----- | ---------- | ----- | | **OS-Guaranteed** | The operating system provides this behavior automatically. No plugin code required. | Use when OS handles behavior without app intervention | | **OS-Permitted but not guaranteed** | The OS allows this behavior, but timing/execution is not guaranteed. Plugin may need fallbacks. | Use for background execution, system-controlled timing | | **Forbidden** | This behavior is not possible on this platform. Plugin must not attempt it. | Use for hard OS limitations (e.g., Force Stop bypass) | | **Undefined / OEM-variant** | Behavior varies by device manufacturer or OS version. Not universal. | Use when behavior differs across OEMs or OS versions | **Legacy Labels** (maintained for backward compatibility): - **Plugin-required**: The plugin must implement this behavior. The OS does not provide it automatically. - **Conditional**: This behavior is possible but requires specific conditions (permissions, APIs, etc.). --- ## 10. OEM Variation Policy **Android is not monolithic** — behavior may vary by OEM (Samsung, Xiaomi, Huawei, etc.). **Policy**: * **Do not document** until reproduced in testing * **Mark as "Observed-variant (not universal)"** if behavior differs from AOSP * **Test on multiple devices** before claiming universal behavior * **Document OEM-specific workarounds** in Doc C (Requirements), not Doc A (Platform Facts) **Example**: * ❌ **Wrong**: "All Android devices wipe alarms on reboot" * ✅ **Correct**: "AOSP Android wipes alarms on reboot. Observed on: Samsung, Pixel, OnePlus. Not tested on: Xiaomi, Huawei." --- ## 11. Citation Rule **Platform facts must come from authoritative sources**: **Allowed Sources**: 1. **AOSP source code** - Direct inspection of Android Open Source Project 2. **Official Android/iOS documentation** - developer.android.com, developer.apple.com 3. **Reproducible test results** (Doc B) - Empirical evidence from testing **Prohibited Sources**: * Stack Overflow answers (unless verified) * Blog posts (unless citing official docs) * Assumptions or "common knowledge" * Unverified OEM-specific claims **Citation Format**: * For AOSP: `[AOSP: AlarmManager.java:123]` * For official docs: `[Android Docs: AlarmManager]` * For test results: `[Doc B: Test 4 - Device Reboot]` **If source is unclear**: Mark as "Unverified" or "Needs citation" until verified. --- ## Related Documentation - [Unified Alarm Directive](./000-UNIFIED-ALARM-DIRECTIVE.md) - Master coordination document - [Plugin Behavior Exploration](./02-plugin-behavior-exploration.md) - Uses this reference - [Plugin Requirements](./03-plugin-requirements.md) - Implementation based on this reference --- ## Version History - **v1.1.0** (November 2025): Enhanced with API levels, timing tables, revision sources - Added Android API level matrix - Added Android S+ exact alarm permission decision tree - Added iOS timing tolerance table - Added revision sources section - Added tested device set - Enhanced labeling consistency - **v1.0.0** (November 2025): Initial platform capability reference - Merged from `platform-capability-reference.md` and `android-alarm-persistence-directive.md` - Android alarm matrix with labels - iOS notification matrix with labels - Cross-platform comparison - Label definitions