docs: add comprehensive alarm/notification behavior documentation
- 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
This commit is contained in:
301
docs/platform-capability-reference.md
Normal file
301
docs/platform-capability-reference.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# 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**:
|
||||
|
||||
1. Persist all alarms in storage (Room DB or SharedPreferences)
|
||||
2. Add a `BOOT_COMPLETED` / `LOCKED_BOOT_COMPLETED` broadcast receiver
|
||||
3. 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 receiver
|
||||
* `SCHEDULE_EXACT_ALARM` - Android 12+ (API 31+)
|
||||
|
||||
**Background Work**:
|
||||
* `WorkManager` - Deferrable background work
|
||||
* `JobScheduler` - Alternative (API 21+)
|
||||
|
||||
### 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. Platform-Specific Constraints Summary
|
||||
|
||||
### 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`
|
||||
|
||||
### 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
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Plugin Behavior Exploration Template](./plugin-behavior-exploration-template.md) - Uses this reference
|
||||
- [Plugin Requirements & Implementation](./plugin-requirements-implementation.md) - Implementation based on this reference
|
||||
- [Android Alarm Persistence Directive](./android-alarm-persistence-directive.md) - Original Android reference
|
||||
- [Improve Alarm Directives](./improve-alarm-directives.md) - Improvement directive
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
- **v1.0** (November 2025): Initial platform capability reference
|
||||
- Android alarm matrix
|
||||
- iOS notification matrix
|
||||
- Cross-platform comparison
|
||||
|
||||
Reference in New Issue
Block a user