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:
670
docs/explore-alarm-behavior-directive.md
Normal file
670
docs/explore-alarm-behavior-directive.md
Normal file
@@ -0,0 +1,670 @@
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user