Files
daily-notification-plugin/docs/platform-capability-reference.md
Matthew Raymer 35babb3126 docs(alarms): unify and enhance alarm directive documentation stack
Create unified alarm documentation system with strict role separation:
- Doc A: Platform capability reference (canonical OS facts)
- Doc B: Plugin behavior exploration (executable test harness)
- Doc C: Plugin requirements (guarantees, JS/TS contract, traceability)

Changes:
- Add canonical rule to Doc A preventing platform fact duplication
- Convert Doc B to pure executable test spec with scenario tables
- Complete Doc C with guarantees matrix, JS/TS API contract, recovery
  contract, unsupported behaviors, and traceability matrix
- Remove implementation details from unified directive
- Add compliance milestone tracking and iOS parity gates
- Add deprecation banners to legacy platform docs

All documents now enforce strict role separation with cross-references
to prevent duplication and ensure single source of truth.
2025-11-25 10:09:46 +00:00

306 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Platform Capability Reference: Android & iOS Alarm/Notification Behavior
**⚠️ DEPRECATED**: This document has been superseded by [01-platform-capability-reference.md](./alarms/01-platform-capability-reference.md) as part of the unified alarm documentation structure.
**See**: [Unified Alarm Directive](./alarms/000-UNIFIED-ALARM-DIRECTIVE.md) for the new documentation structure.
**Author**: Matthew Raymer
**Date**: November 2025
**Status**: **DEPRECATED** - Superseded by unified structure
## 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-appstyle 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