- 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
671 lines
24 KiB
Markdown
671 lines
24 KiB
Markdown
# DIRECTIVE: Explore & Document Alarm / Schedule / Notification Behavior in Capacitor Plugin (Android & iOS)
|
||
|
||
**Author**: Matthew Raymer
|
||
**Date**: November 2025
|
||
**Status**: Active Directive - Exploration Phase
|
||
|
||
## 0. Scope & Objective
|
||
|
||
We want to **explore, test, and document** how the *current* Capacitor plugin handles:
|
||
|
||
- **Alarms / schedules / reminders**
|
||
- **Local notifications**
|
||
- **Persistence and recovery** across:
|
||
- App kill / swipe from recents
|
||
- OS process kill
|
||
- Device reboot
|
||
- **Force stop** (Android) / hard termination (iOS)
|
||
- Cross-platform **semantic differences** between Android and iOS
|
||
|
||
The focus is **observation of current behavior**, not yet changing implementation.
|
||
|
||
We want a clear map of **what the plugin actually guarantees** on each platform.
|
||
|
||
---
|
||
|
||
## 1. Key Questions to Answer
|
||
|
||
For **each platform (Android, iOS)** and for **each "scheduled thing"** the plugin supports (alarms, reminders, scheduled notifications, repeating schedules, etc.):
|
||
|
||
### 1.1 How is it implemented under the hood?
|
||
|
||
- **Android**: AlarmManager? WorkManager? JobScheduler? Foreground service?
|
||
- **iOS**: UNUserNotificationCenter? BGTaskScheduler? background fetch? timers in foreground?
|
||
|
||
### 1.2 What happens when the app is:
|
||
|
||
- Swiped away from recents?
|
||
- Killed by OS (memory pressure)?
|
||
- Device rebooted?
|
||
- On Android: explicitly **Force Stopped** in system settings?
|
||
- On iOS: explicitly swiped away, then device rebooted before next trigger?
|
||
|
||
### 1.3 What is persisted?
|
||
|
||
Are schedules/alarms stored in:
|
||
|
||
- SQLite / Room / shared preferences (Android)?
|
||
- CoreData / UserDefaults / files (iOS)?
|
||
- Or are they only in RAM / native scheduler?
|
||
|
||
### 1.4 What is re-created and when?
|
||
|
||
- On boot?
|
||
- On app cold start?
|
||
- On notification tap?
|
||
- Not at all?
|
||
|
||
### 1.5 What does the plugin *promise* to the JS/TS layer?
|
||
|
||
- "Will always fire even after reboot"?
|
||
- "Will fire as long as app hasn't been force-stopped"?
|
||
- "Best-effort only"?
|
||
|
||
We are trying to align **plugin promises** with **real platform capabilities and limitations.**
|
||
|
||
---
|
||
|
||
## 2. Android Exploration
|
||
|
||
### 2.1 Code-Level Inspection
|
||
|
||
**Source Locations:**
|
||
|
||
- **Plugin Implementation**: `android/src/main/java/com/timesafari/dailynotification/` (Kotlin files may also be present)
|
||
- **Manifest**: `android/src/main/AndroidManifest.xml`
|
||
- **Test Applications**:
|
||
- `test-apps/android-test-app/` - Primary Android test app
|
||
- `test-apps/daily-notification-test/` - Additional test application
|
||
|
||
**Tasks:**
|
||
|
||
1. **Locate the Android implementation in the plugin:**
|
||
- Primary path: `android/src/main/java/com/timesafari/dailynotification/`
|
||
- Key files to examine:
|
||
- `DailyNotificationPlugin.kt` - Main plugin class (see `scheduleDailyNotification()` at line 1302)
|
||
- `DailyNotificationWorker.java` - WorkManager worker (see `doWork()` at line 59)
|
||
- `DailyNotificationReceiver.java` - BroadcastReceiver for alarms (see `onReceive()` at line 51)
|
||
- `NotifyReceiver.kt` - AlarmManager scheduling (see `scheduleExactNotification()` at line 92)
|
||
- `BootReceiver.kt` - Boot recovery (see `onReceive()` at line 24)
|
||
- `FetchWorker.kt` - WorkManager fetch scheduling (see `scheduleFetch()` at line 31)
|
||
|
||
2. **Identify the mechanisms used to schedule work:**
|
||
- **AlarmManager**: Used via `NotifyReceiver.scheduleExactNotification()` (line 92)
|
||
- `setAlarmClock()` for Android 5.0+ (line 219)
|
||
- `setExactAndAllowWhileIdle()` for Android 6.0+ (line 223)
|
||
- `setExact()` for older versions (line 231)
|
||
- **WorkManager**: Used for background fetching and notification processing
|
||
- `FetchWorker.scheduleFetch()` (line 31) - Uses `OneTimeWorkRequest`
|
||
- `DailyNotificationWorker.doWork()` (line 59) - Processes notifications
|
||
- **No JobScheduler**: Not used in current implementation
|
||
- **No repeating alarms**: Uses one-time alarms with rescheduling
|
||
|
||
3. **Inspect how notifications are issued:**
|
||
- **NotificationCompat**: Used in `DailyNotificationWorker.displayNotification()` and `NotifyReceiver.showNotification()` (line 482)
|
||
- **setFullScreenIntent**: Not currently used (check `NotifyReceiver.showNotification()` at line 443)
|
||
- **Notification channels**: Created in `NotifyReceiver.showNotification()` (lines 454-470)
|
||
- Channel ID: `"timesafari.daily"` (see `DailyNotificationWorker.java` line 46)
|
||
- Importance based on priority (HIGH/DEFAULT/LOW)
|
||
- **ChannelManager**: Check for separate channel management class
|
||
|
||
4. **Check for permissions & receivers:**
|
||
- Manifest: `android/src/main/AndroidManifest.xml`
|
||
- Look for:
|
||
- `RECEIVE_BOOT_COMPLETED` permission
|
||
- `SCHEDULE_EXACT_ALARM` permission
|
||
- Any `BroadcastReceiver` declarations for:
|
||
- `BOOT_COMPLETED` / `LOCKED_BOOT_COMPLETED`
|
||
- Custom alarm intent actions
|
||
- Check test app manifests:
|
||
- `test-apps/android-test-app/app/src/main/AndroidManifest.xml`
|
||
- `test-apps/daily-notification-test/` (if applicable)
|
||
|
||
5. **Determine persistence strategy:**
|
||
- Where are scheduled alarms stored?
|
||
- SharedPreferences?
|
||
- SQLite / Room?
|
||
- Not at all (just in AlarmManager/work queue)?
|
||
|
||
6. **Check for reschedule-on-boot or reschedule-on-app-launch logic:**
|
||
- **BootReceiver**: `android/src/main/java/com/timesafari/dailynotification/BootReceiver.kt`
|
||
- `onReceive()` handles `ACTION_BOOT_COMPLETED` (line 24)
|
||
- `rescheduleNotifications()` reloads from database and reschedules (line 38+)
|
||
- Calls `NotifyReceiver.scheduleExactNotification()` for each schedule (line 74)
|
||
- **Alternative**: `DailyNotificationRebootRecoveryManager.java` has `BootCompletedReceiver` inner class (line 278)
|
||
- **App launch recovery**: Check `DailyNotificationPlugin.kt` for initialization logic that reschedules on app start
|
||
|
||
---
|
||
|
||
### 2.2 Behavior Testing Matrix (Android)
|
||
|
||
**Test Applications:**
|
||
|
||
- **Primary**: `test-apps/android-test-app/` - Use this for comprehensive testing
|
||
- **Secondary**: `test-apps/daily-notification-test/` - Additional test scenarios if needed
|
||
|
||
**Run these tests on a real device or emulator.**
|
||
|
||
For each scenario, record:
|
||
|
||
- Did the alarm / notification fire?
|
||
- Did it fire on time?
|
||
- From what state did the app wake up (cold, warm, already running)?
|
||
- Any visible logs / errors?
|
||
|
||
**Scenarios:**
|
||
|
||
#### 2.2.1 Base Case
|
||
|
||
- Schedule an alarm/notification 2 minutes in the future.
|
||
- Leave app in foreground or background.
|
||
- Confirm it fires.
|
||
|
||
#### 2.2.2 Swipe from Recents
|
||
|
||
- Schedule alarm (2–5 minutes).
|
||
- Swipe app away from recents.
|
||
- Wait for trigger time.
|
||
- Observe: does alarm still fire?
|
||
|
||
#### 2.2.3 OS Kill (simulate memory pressure)
|
||
|
||
- Mainly observational; may be tricky to force, but:
|
||
- Open many other apps or use `adb shell am kill <package>` (not force-stop).
|
||
- Confirm whether scheduled alarm still fires.
|
||
|
||
#### 2.2.4 Device Reboot
|
||
|
||
- Schedule alarm (e.g. 10 minutes in the future).
|
||
- Reboot device.
|
||
- Do **not** reopen app.
|
||
- Wait past scheduled time:
|
||
- Does plugin reschedule and fire automatically?
|
||
- Or does nothing happen until user opens the app?
|
||
|
||
Then:
|
||
|
||
- After device reboot, manually open the app.
|
||
- Does plugin detect missed alarms and:
|
||
- Fire "missed" behavior?
|
||
- Reschedule future alarms?
|
||
- Or silently forget them?
|
||
|
||
#### 2.2.5 Android Force Stop
|
||
|
||
- Schedule alarm.
|
||
- Go to Settings → Apps → [Your App] → Force stop.
|
||
- Wait for trigger time.
|
||
- Observe: it should **not** fire (OS-level rule).
|
||
- Then open app again and see if plugin automatically:
|
||
- Detects missed alarms and recovers, or
|
||
- Treats them as lost.
|
||
|
||
**Goal:** build a clear empirical table of plugin behavior vs Android's known rules.
|
||
|
||
---
|
||
|
||
## 3. iOS Exploration
|
||
|
||
### 3.1 Code-Level Inspection
|
||
|
||
**Source Locations:**
|
||
|
||
- **Plugin Implementation**: `ios/Plugin/` - Swift plugin files
|
||
- **Alternative Branch**: Check `ios-2` branch for additional iOS implementations or variations
|
||
- **Test Applications**:
|
||
- `test-apps/ios-test-app/` - Primary iOS test app
|
||
- `test-apps/daily-notification-test/` - Additional test application (if iOS support exists)
|
||
|
||
**Tasks:**
|
||
|
||
1. **Locate the iOS implementation:**
|
||
- Primary path: `ios/Plugin/`
|
||
- Key files to examine:
|
||
- `DailyNotificationPlugin.swift` - Main plugin class (see `scheduleUserNotification()` at line 506)
|
||
- `DailyNotificationScheduler.swift` - Notification scheduling (see `scheduleNotification()` at line 133)
|
||
- `DailyNotificationBackgroundTasks.swift` - BGTaskScheduler handlers
|
||
- **Also check**: `ios-2` branch for alternative implementations or newer iOS code
|
||
```bash
|
||
git checkout ios-2
|
||
# Compare ios/Plugin/DailyNotificationPlugin.swift
|
||
```
|
||
|
||
2. **Identify the scheduling mechanism:**
|
||
- **UNUserNotificationCenter**: Primary mechanism
|
||
- `DailyNotificationScheduler.scheduleNotification()` uses `UNCalendarNotificationTrigger` (line 172)
|
||
- `DailyNotificationPlugin.scheduleUserNotification()` uses `UNTimeIntervalNotificationTrigger` (line 514)
|
||
- No `UNLocationNotificationTrigger` found
|
||
- **BGTaskScheduler**: Used for background fetch
|
||
- `DailyNotificationPlugin.scheduleBackgroundFetch()` (line 495)
|
||
- Uses `BGAppRefreshTaskRequest` (line 496)
|
||
- **No timers**: No plain Timer usage found (would die with app)
|
||
|
||
3. **Determine what's persisted:**
|
||
- Does the plugin store alarms in:
|
||
- `UserDefaults`?
|
||
- Files / CoreData?
|
||
- Or only within UNUserNotificationCenter's pending notification requests (no parallel app-side storage)?
|
||
|
||
4. **Check for re-scheduling behavior on app launch:**
|
||
- On app start (cold or warm), does plugin:
|
||
- Query `UNUserNotificationCenter` for pending notifications?
|
||
- Compare against its own store?
|
||
- Attempt to rebuild schedules?
|
||
- Or does it rely solely on UNUserNotificationCenter to manage everything?
|
||
|
||
5. **Determine capabilities / limitations:**
|
||
- Can the plugin run arbitrary code *when the notification fires*?
|
||
- Only via notification actions / `didReceive response` callbacks.
|
||
- Does it support repeating notifications (daily/weekly)?
|
||
|
||
---
|
||
|
||
### 3.2 Behavior Testing Matrix (iOS)
|
||
|
||
**Test Applications:**
|
||
|
||
- **Primary**: `test-apps/ios-test-app/` - Use this for comprehensive testing
|
||
- **Secondary**: `test-apps/daily-notification-test/` - Additional test scenarios if needed
|
||
- **Note**: Compare behavior between main branch and `ios-2` branch implementations if they differ
|
||
|
||
As with Android, test:
|
||
|
||
#### 3.2.1 Base Case
|
||
|
||
- Schedule local notification 2–5 minutes in the future; leave app backgrounded.
|
||
- Confirm it fires on time with app in background.
|
||
|
||
#### 3.2.2 Swipe App Away
|
||
|
||
- Schedule notification, then swipe app away from app switcher.
|
||
- Confirm notification still fires (iOS local notification center should handle this).
|
||
|
||
#### 3.2.3 Device Reboot
|
||
|
||
- Schedule notification for a future time.
|
||
- Reboot device.
|
||
- Do **not** open app.
|
||
- Test whether:
|
||
- Notification still fires (iOS usually persists scheduled local notifications across reboot), or
|
||
- Behavior depends on trigger type (time vs calendar, etc.).
|
||
|
||
#### 3.2.4 Hard Termination & Relaunch
|
||
|
||
- Schedule some repeating notification(s).
|
||
- Terminate app via Xcode / app switcher.
|
||
- Allow some triggers to occur.
|
||
- Reopen app and inspect whether plugin:
|
||
- Notices anything about missed events, or
|
||
- Simply trusts that UNUserNotificationCenter handled user-visible parts.
|
||
|
||
**Goal:** map what your *plugin* adds on top of native behavior vs what is entirely delegated to the OS.
|
||
|
||
---
|
||
|
||
## 4. Cross-Platform Behavior & Promise Alignment
|
||
|
||
After exploration, produce a summary:
|
||
|
||
### 4.1 What the plugin actually guarantees to JS callers
|
||
|
||
- "Scheduled reminders will still fire after app swipe / kill"
|
||
- "On Android, reminders may not survive device reboot unless app is opened"
|
||
- "After Force Stop (Android), nothing runs until user opens app"
|
||
- "On iOS, local notifications themselves persist across reboot, but no extra app code runs at fire time unless user interacts"
|
||
|
||
### 4.2 Where semantics differ
|
||
|
||
- Android may require explicit rescheduling on boot; iOS may not.
|
||
- Android **force stop** is a hard wall; iOS has no exact equivalent in user-facing settings.
|
||
- Plugin may currently:
|
||
- Over-promise on reliability, or
|
||
- Under-document platform limitations.
|
||
|
||
### 4.3 Where we need to add warnings / notes in the public API
|
||
|
||
- E.g. "This schedule is best-effort; on Android, device reboot may cancel it unless you open the app again," etc.
|
||
|
||
---
|
||
|
||
## 5. Deliverables from This Exploration
|
||
|
||
### 5.1 Doc: `ALARMS_BEHAVIOR_MATRIX.md`
|
||
|
||
A table of scenarios (per platform) vs observed behavior.
|
||
|
||
Includes:
|
||
|
||
- App state
|
||
- OS event (reboot, force stop, etc.)
|
||
- What fired, what didn't
|
||
- Log snippets where useful
|
||
|
||
### 5.2 Doc: `PLUGIN_ALARM_LIMITATIONS.md`
|
||
|
||
Plain-language explanation of:
|
||
|
||
- Android hard limits (Force Stop, reboot behavior)
|
||
- iOS behavior (local notifications vs app code execution)
|
||
- Clear note on what the plugin promises.
|
||
|
||
### 5.3 Annotated code pointers
|
||
|
||
Commented locations in Android/iOS code where:
|
||
|
||
- Scheduling is performed
|
||
- Persistence (if any) is implemented
|
||
- Rescheduling (if any) is implemented
|
||
|
||
### 5.4 Open Questions / TODOs
|
||
|
||
Gaps uncovered:
|
||
|
||
- No reschedule-on-boot?
|
||
- No persistence of schedules?
|
||
- No handling of "missed" alarms on reactivation?
|
||
- Potential next-step directives (separate document) to improve behavior.
|
||
|
||
---
|
||
|
||
## 6. One-Liner Summary
|
||
|
||
> This directive is to **investigate, not change**: we want a precise, tested understanding of what our Capacitor plugin *currently* does with alarms/schedules/notifications on Android and iOS, especially across kills, reboots, and force stops, and where that behavior does or does not match what we think we're promising to app developers.
|
||
|
||
---
|
||
|
||
## Related Documentation
|
||
|
||
- [Android Alarm Persistence Directive](./android-alarm-persistence-directive.md) - General Android alarm capabilities and limitations
|
||
- [Boot Receiver Testing Guide](./boot-receiver-testing-guide.md) - Testing boot receiver behavior
|
||
- [App Startup Recovery Solution](./app-startup-recovery-solution.md) - Recovery mechanisms on app launch
|
||
- [Reboot Testing Procedure](./reboot-testing-procedure.md) - Step-by-step reboot testing
|
||
|
||
---
|
||
|
||
## Source Code Structure Reference
|
||
|
||
### Android Source Files
|
||
|
||
**Primary Plugin Code:**
|
||
- `android/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.kt` (or `.java`)
|
||
- `android/src/main/java/com/timesafari/dailynotification/DailyNotificationWorker.java`
|
||
- `android/src/main/java/com/timesafari/dailynotification/DailyNotificationReceiver.java`
|
||
- `android/src/main/java/com/timesafari/dailynotification/ChannelManager.java`
|
||
- `android/src/main/AndroidManifest.xml`
|
||
|
||
**Test Applications:**
|
||
- `test-apps/android-test-app/app/src/main/` - Test app source
|
||
- `test-apps/android-test-app/app/src/main/assets/public/index.html` - Test UI
|
||
- `test-apps/daily-notification-test/` - Additional test app (if present)
|
||
|
||
### iOS Source Files
|
||
|
||
**Primary Plugin Code:**
|
||
- `ios/Plugin/DailyNotificationPlugin.swift` (or similar)
|
||
- `ios/Plugin/` - All Swift plugin files
|
||
- **Also check**: `ios-2` branch for alternative implementations
|
||
|
||
**Test Applications:**
|
||
- `test-apps/ios-test-app/` - Test app source
|
||
- `test-apps/daily-notification-test/` - Additional test app (if iOS support exists)
|
||
|
||
---
|
||
|
||
## Detailed Code References (File Locations, Functions, Line Numbers)
|
||
|
||
### Android Implementation Details
|
||
|
||
#### Alarm Scheduling
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/NotifyReceiver.kt`
|
||
|
||
- **Function**: `scheduleExactNotification()` - **Lines 92-247**
|
||
- Schedules exact alarms using AlarmManager
|
||
- Uses `setAlarmClock()` for Android 5.0+ (API 21+) - **Line 219**
|
||
- Falls back to `setExactAndAllowWhileIdle()` for Android 6.0+ (API 23+) - **Line 223**
|
||
- Falls back to `setExact()` for older versions - **Line 231**
|
||
- Called from:
|
||
- `DailyNotificationPlugin.kt` - `scheduleDailyNotification()` - **Line 1385**
|
||
- `DailyNotificationPlugin.kt` - `scheduleDailyReminder()` - **Line 809**
|
||
- `DailyNotificationPlugin.kt` - `scheduleDualNotification()` - **Line 1685**
|
||
- `BootReceiver.kt` - `rescheduleNotifications()` - **Line 74**
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.kt`
|
||
|
||
- **Function**: `scheduleDailyNotification()` - **Lines 1302-1417**
|
||
- Main plugin method for scheduling notifications
|
||
- Checks exact alarm permission - **Line 1309**
|
||
- Opens settings if permission not granted - **Lines 1314-1324**
|
||
- Calls `NotifyReceiver.scheduleExactNotification()` - **Line 1385**
|
||
- Schedules prefetch 2 minutes before notification - **Line 1395**
|
||
|
||
- **Function**: `scheduleDailyReminder()` - **Lines 777-833**
|
||
- Schedules static reminders (no content dependency)
|
||
- Calls `NotifyReceiver.scheduleExactNotification()` - **Line 809**
|
||
|
||
- **Function**: `canScheduleExactAlarms()` - **Lines 835-860**
|
||
- Checks if exact alarm permission is granted (Android 12+)
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/PendingIntentManager.java`
|
||
|
||
- **Function**: `scheduleExactAlarm()` - **Lines 127-158**
|
||
- Uses `setExactAndAllowWhileIdle()` - **Line 135**
|
||
- Falls back to `setExact()` - **Line 141**
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/DailyNotificationExactAlarmManager.java`
|
||
|
||
- **Function**: `scheduleExactAlarm()` - **Lines 186-201**
|
||
- Uses `setExactAndAllowWhileIdle()` - **Line 189**
|
||
- Falls back to `setExact()` - **Line 193**
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/DailyNotificationScheduler.java`
|
||
|
||
- **Function**: `scheduleExactAlarm()` - **Lines 237-272**
|
||
- Uses `setExactAndAllowWhileIdle()` - **Line 242**
|
||
- Falls back to `setExact()` - **Line 251**
|
||
|
||
#### WorkManager Usage
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/FetchWorker.kt`
|
||
|
||
- **Function**: `scheduleFetch()` - **Lines 31-59**
|
||
- Schedules WorkManager one-time work request
|
||
- Uses `OneTimeWorkRequestBuilder` - **Line 36**
|
||
- Enqueues with `WorkManager.getInstance().enqueueUniqueWork()` - **Lines 53-58**
|
||
|
||
- **Function**: `scheduleDelayedPrefetch()` - **Lines 62-131**
|
||
- Schedules delayed prefetch work
|
||
- Uses `setInitialDelay()` - **Line 104**
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/DailyNotificationWorker.java`
|
||
|
||
- **Function**: `doWork()` - **Lines 59-915**
|
||
- Main WorkManager worker execution
|
||
- Handles notification display - **Line 91**
|
||
- Calls `displayNotification()` - **Line 200+**
|
||
|
||
- **Function**: `displayNotification()` - **Lines 200-400+**
|
||
- Displays notification using NotificationCompat
|
||
- Ensures notification channel exists
|
||
- Uses `NotificationCompat.Builder` - **Line 200+**
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/DailyNotificationFetcher.java`
|
||
|
||
- **Function**: `scheduleFetch()` - **Lines 78-140**
|
||
- Schedules WorkManager fetch work
|
||
- Uses `OneTimeWorkRequest.Builder` - **Line 106**
|
||
- Enqueues with `workManager.enqueueUniqueWork()` - **Lines 115-119**
|
||
|
||
#### Boot Recovery
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/BootReceiver.kt`
|
||
|
||
- **Class**: `BootReceiver` - **Lines 18-100+**
|
||
- BroadcastReceiver for BOOT_COMPLETED
|
||
- `onReceive()` - **Line 24** - Handles boot intent
|
||
- `rescheduleNotifications()` - **Line 38+** - Reschedules all notifications from database
|
||
- Calls `NotifyReceiver.scheduleExactNotification()` - **Line 74**
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/DailyNotificationRebootRecoveryManager.java`
|
||
|
||
- **Class**: `BootCompletedReceiver` - **Lines 278-297**
|
||
- Inner BroadcastReceiver for boot events
|
||
- `onReceive()` - **Line 280** - Handles BOOT_COMPLETED action
|
||
- Calls `handleSystemReboot()` - **Line 290**
|
||
|
||
#### Notification Display
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/DailyNotificationReceiver.java`
|
||
|
||
- **Function**: `onReceive()` - **Lines 51-485**
|
||
- Lightweight BroadcastReceiver triggered by AlarmManager
|
||
- Enqueues WorkManager work for heavy operations - **Line 100+**
|
||
- Extracts notification ID and action from intent
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/NotifyReceiver.kt`
|
||
|
||
- **Function**: `showNotification()` - **Lines 443-500**
|
||
- Displays notification using NotificationCompat
|
||
- Creates notification channel if needed - **Lines 454-470**
|
||
- Uses `NotificationCompat.Builder` - **Line 482**
|
||
|
||
#### Persistence
|
||
|
||
**File**: `android/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.kt`
|
||
|
||
- Database operations use Room database:
|
||
- `getDatabase()` - Returns DailyNotificationDatabase instance
|
||
- Schedule storage in `scheduleDailyNotification()` - **Lines 1393-1410**
|
||
- Schedule storage in `scheduleDailyReminder()` - **Lines 813-821**
|
||
|
||
#### Permissions & Manifest
|
||
|
||
**File**: `android/src/main/AndroidManifest.xml`
|
||
|
||
- **Note**: Plugin manifest is minimal; receivers declared in consuming app manifest
|
||
- Check test app manifest: `test-apps/android-test-app/app/src/main/AndroidManifest.xml`
|
||
- Look for `RECEIVE_BOOT_COMPLETED` permission
|
||
- Look for `SCHEDULE_EXACT_ALARM` permission
|
||
- Look for `BootReceiver` registration
|
||
- Look for `DailyNotificationReceiver` registration
|
||
|
||
### iOS Implementation Details
|
||
|
||
#### Notification Scheduling
|
||
|
||
**File**: `ios/Plugin/DailyNotificationPlugin.swift`
|
||
|
||
- **Class**: `DailyNotificationPlugin` - **Lines 24-532**
|
||
- Main Capacitor plugin class
|
||
- Uses `UNUserNotificationCenter.current()` - **Line 26**
|
||
- Uses `BGTaskScheduler.shared` - **Line 27**
|
||
|
||
- **Function**: `scheduleUserNotification()` - **Lines 506-529**
|
||
- Schedules notification using UNUserNotificationCenter
|
||
- Creates `UNMutableNotificationContent` - **Line 507**
|
||
- Creates `UNTimeIntervalNotificationTrigger` - **Line 514**
|
||
- Adds request via `notificationCenter.add()` - **Line 522**
|
||
|
||
- **Function**: `scheduleBackgroundFetch()` - **Lines 495-504**
|
||
- Schedules BGTaskScheduler background fetch
|
||
- Creates `BGAppRefreshTaskRequest` - **Line 496**
|
||
- Submits via `backgroundTaskScheduler.submit()` - **Line 502**
|
||
|
||
**File**: `ios/Plugin/DailyNotificationScheduler.swift`
|
||
|
||
- **Class**: `DailyNotificationScheduler` - **Lines 20-236+**
|
||
- Manages UNUserNotificationCenter scheduling
|
||
|
||
- **Function**: `scheduleNotification()` - **Lines 133-198**
|
||
- Schedules notification with calendar trigger
|
||
- Creates `UNCalendarNotificationTrigger` - **Lines 172-175**
|
||
- Creates `UNNotificationRequest` - **Lines 178-182**
|
||
- Adds via `notificationCenter.add()` - **Line 185**
|
||
|
||
- **Function**: `cancelNotification()` - **Lines 205-213**
|
||
- Cancels notification by ID
|
||
- Uses `notificationCenter.removePendingNotificationRequests()` - **Line 206**
|
||
|
||
#### Background Tasks
|
||
|
||
**File**: `ios/Plugin/DailyNotificationBackgroundTasks.swift`
|
||
|
||
- Background task handling for BGTaskScheduler
|
||
- Register background task identifiers
|
||
- Handle background fetch execution
|
||
|
||
#### Persistence
|
||
|
||
**File**: `ios/Plugin/DailyNotificationPlugin.swift**
|
||
|
||
- **Note**: Check for UserDefaults, CoreData, or file-based storage
|
||
- Storage component: `var storage: DailyNotificationStorage?` - **Line 35**
|
||
- Scheduler component: `var scheduler: DailyNotificationScheduler?` - **Line 36**
|
||
|
||
#### iOS-2 Branch
|
||
|
||
- **Note**: Check `ios-2` branch for alternative implementations:
|
||
```bash
|
||
git checkout ios-2
|
||
# Compare ios/Plugin/ implementations
|
||
```
|
||
|
||
---
|
||
|
||
## Testing Tools & Commands
|
||
|
||
### Android Testing
|
||
|
||
```bash
|
||
# Check scheduled alarms
|
||
adb shell dumpsys alarm | grep -i timesafari
|
||
|
||
# Force kill (not force-stop) - adjust package name based on test app
|
||
adb shell am kill com.timesafari.dailynotification
|
||
# Or for test apps:
|
||
# adb shell am kill com.timesafari.androidtestapp
|
||
# adb shell am kill <package-name-from-test-app-manifest>
|
||
|
||
# View logs
|
||
adb logcat | grep -i "DN\|DailyNotification"
|
||
|
||
# Check WorkManager tasks
|
||
adb shell dumpsys jobscheduler | grep -i timesafari
|
||
|
||
# Build and install test app
|
||
cd test-apps/android-test-app
|
||
./gradlew installDebug
|
||
```
|
||
|
||
### iOS Testing
|
||
|
||
```bash
|
||
# View device logs (requires Xcode)
|
||
xcrun simctl spawn booted log stream --predicate 'processImagePath contains "DailyNotification"'
|
||
|
||
# List pending notifications (requires app code)
|
||
# Use UNUserNotificationCenter.getPendingNotificationRequests()
|
||
|
||
# Build test app (from test-apps/ios-test-app)
|
||
# Use Xcode or:
|
||
cd test-apps/ios-test-app
|
||
# Follow build instructions in test app README
|
||
|
||
# Check ios-2 branch for alternative implementations
|
||
git checkout ios-2
|
||
# Compare ios/Plugin/ implementations between branches
|
||
```
|
||
|
||
---
|
||
|
||
## Next Steps After Exploration
|
||
|
||
Once this exploration is complete:
|
||
|
||
1. **Document findings** in the deliverables listed above
|
||
2. **Identify gaps** between current behavior and desired behavior
|
||
3. **Create implementation directives** to address gaps (if needed)
|
||
4. **Update plugin documentation** to accurately reflect platform limitations
|
||
5. **Update API documentation** with appropriate warnings and caveats
|
||
|