# 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 org.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

