# iOS Troubleshooting Guide

**Author**: Matthew Raymer  
**Date**: 2025-12-08  
**Status**: 🎯 **ACTIVE** - iOS Troubleshooting Reference  
**Version**: 1.0.0

## Purpose

This guide provides solutions to common iOS-specific issues when using the Daily Notification Plugin. It covers debugging techniques, common problems, and their solutions.

**Reference**: 
- [iOS Implementation Directive](./ios-implementation-directive.md) - Implementation details
- [Platform Capability Reference](./alarms/01-platform-capability-reference.md) - iOS OS behaviors
- [iOS Logging Guide](../doc/test-app-ios/IOS_LOGGING_GUIDE.md) - How to view logs

---

## 1. Common Issues

### 1.1 Notifications Not Firing

**Symptoms:**
- Notifications scheduled but don't appear
- No notification at scheduled time
- Notifications work in simulator but not on device

**Diagnosis Steps:**

1. **Check Notification Permission:**
   ```swift
   // In app code
   UNUserNotificationCenter.current().getNotificationSettings { settings in
       print("Authorization status: \(settings.authorizationStatus)")
   }
   ```
   
   Or check in Xcode Console:
   ```
   DNP-PLUGIN: Notification permission status: authorized
   ```

2. **Check Pending Notifications:**
   ```swift
   UNUserNotificationCenter.current().getPendingNotificationRequests { requests in
       print("Pending notifications: \(requests.count)")
   }
   ```

3. **Check Background App Refresh:**
   - Settings → [Your App] → Background App Refresh
   - Must be enabled for background tasks

4. **Check Notification Limit:**
   - iOS limits to 64 pending notifications
   - Check if limit is exceeded

**Solutions:**

- **Permission Denied:**
  - Request permission: `DailyNotification.requestNotificationPermission()`
  - Guide user to Settings → [Your App] → Notifications

- **Background App Refresh Disabled:**
  - Guide user to enable: Settings → [Your App] → Background App Refresh
  - Or use: `DailyNotification.openBackgroundAppRefreshSettings()`

- **Notification Limit Exceeded:**
  - Reduce number of scheduled notifications
  - Implement notification cleanup logic
  - Check rolling window implementation

- **Simulator vs Device:**
  - Simulator may not fire notifications reliably
  - Test on physical device for accurate behavior

---

### 1.2 Background Tasks Not Executing

**Symptoms:**
- Prefetch tasks don't run
- Background fetch never executes
- BGTaskScheduler tasks not firing

**Diagnosis Steps:**

1. **Check BGTaskScheduler Registration:**
   ```swift
   // Verify registration in AppDelegate
   BGTaskScheduler.shared.register(forTaskWithIdentifier: "org.timesafari.dailynotification.fetch", using: nil) { task in
       // Handler should be registered
   }
   ```

2. **Check Info.plist:**
   ```xml
   <key>BGTaskSchedulerPermittedIdentifiers</key>
   <array>
       <string>org.timesafari.dailynotification.fetch</string>
   </array>
   ```

3. **Check Background App Refresh:**
   - Must be enabled in Settings
   - System-controlled timing (not guaranteed)

4. **Check Logs:**
   ```
   DNP-FETCH-START: Background fetch task started
   ```

**Solutions:**

- **Not Registered:**
  - Verify registration in `AppDelegate.application(_:didFinishLaunchingWithOptions:)`
  - Check Info.plist has correct identifiers

- **Background App Refresh Disabled:**
  - User must enable in Settings
  - Cannot be programmatically enabled

- **System Not Executing:**
  - BGTaskScheduler is system-controlled
  - Execution timing is not guaranteed
  - System may defer or skip tasks
  - Use for prefetching only, not critical scheduling

- **Simulator Limitations:**
  - Background tasks may not execute in simulator
  - Test on physical device

---

### 1.3 Notifications Disappear After App Termination

**Symptoms:**
- Notifications scheduled but disappear when app is terminated
- Notifications don't persist across app restarts

**Diagnosis:**

**This should NOT happen on iOS** - notifications persist automatically (OS-guaranteed).

**If it happens, check:**

1. **Notification Trigger Type:**
   - Calendar/time triggers persist ✅
   - Location triggers do NOT persist ❌

2. **Notification Content:**
   - Ensure notification has valid content
   - Check for invalid trigger dates

3. **System Storage:**
   - iOS may clear notifications if device storage is full
   - Check available storage

**Solutions:**

- **Use Calendar Triggers:**
  ```swift
  // ✅ Persists across reboot
  let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: true)
  
  // ❌ Does NOT persist
  let trigger = UNLocationNotificationTrigger(region: region, repeats: true)
  ```

- **Check Device Storage:**
  - Free up storage if device is full
  - iOS may clear notifications when storage is critical

---

### 1.4 Recovery Not Working

**Symptoms:**
- Missed notifications not detected on app launch
- Future notifications not verified/rescheduled
- No recovery activity in logs

**Diagnosis:**

**Recovery features are NOT yet implemented** (as of 2025-12-08).

**Expected Behavior (Once Implemented):**

1. **Check Logs for Recovery:**
   ```
   DNP-REACTIVATION: Starting app launch recovery
   DNP-REACTIVATION: Detected scenario: coldStart
   DNP-REACTIVATION: Missed notifications detected: 2
   DNP-REACTIVATION: Future notifications verified: 1
   ```

2. **Verify Recovery Logic:**
   - Should run in `DailyNotificationPlugin.load()`
   - Should detect missed notifications
   - Should verify future notifications

**Solutions:**

- **Implementation Pending:**
  - See [iOS Implementation Directive Phase 1](./ios-implementation-directive-phase1.md)
  - Recovery features need to be implemented

- **Manual Workaround:**
  - Check pending notifications manually
  - Reschedule if needed

---

### 1.5 Database/Storage Issues

**Symptoms:**
- Database errors in logs
- Data not persisting
- Core Data errors

**Diagnosis Steps:**

1. **Check Database Path:**
   ```swift
   let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
   let dbPath = documentsPath.appendingPathComponent("daily_notifications.db")
   print("Database path: \(dbPath.path)")
   ```

2. **Check Core Data Stack:**
   - Verify `NSPersistentContainer` initialization
   - Check for migration errors

3. **Check Logs:**
   ```
   DNP-STORAGE: Database opened successfully
   DNP-STORAGE: Error opening database: [error]
   ```

**Solutions:**

- **Database Path Issues:**
  - Verify app has write permissions
  - Check Documents directory is accessible
  - Ensure path is correct

- **Core Data Errors:**
  - Check Core Data model version
  - Verify migration policies
  - Check for schema mismatches

- **Storage Full:**
  - Free up device storage
  - iOS may clear app data if storage is critical

---

### 1.6 Permission Issues

**Symptoms:**
- Permission requests fail
- Permission status incorrect
- Cannot schedule notifications

**Diagnosis:**

1. **Check Current Status:**
   ```swift
   UNUserNotificationCenter.current().getNotificationSettings { settings in
       switch settings.authorizationStatus {
       case .authorized: // ✅ Can schedule
       case .denied: // ❌ User denied
       case .notDetermined: // ⚠️ Not requested yet
       case .provisional: // ⚠️ Provisional (iOS 12+)
       @unknown default: break
       }
   }
   ```

2. **Check Logs:**
   ```
   DNP-PLUGIN: Notification permission status: denied
   ```

**Solutions:**

- **Permission Denied:**
  - Cannot request again programmatically
  - Guide user to Settings → [Your App] → Notifications
  - Use: `DailyNotification.openNotificationSettings()`

- **Not Determined:**
  - Request permission: `DailyNotification.requestNotificationPermission()`
  - Show explanation before requesting

- **Provisional:**
  - iOS 12+ feature
  - Notifications delivered quietly
  - User can upgrade to full permission

---

## 2. Debugging Techniques

### 2.1 Viewing Logs

**Xcode Console (Recommended):**
1. Run app in Xcode (Cmd+R)
2. Open Debug Area (Cmd+Shift+Y)
3. Filter by: `DNP-` or `DailyNotification`

**Console.app:**
1. Open Console.app
2. Select device/simulator
3. Filter by process: `ios-test-app`

**Command Line:**
```bash
# Simulator logs
xcrun simctl spawn <device-id> log stream --level=debug --predicate 'processImagePath contains "ios-test-app"'

# Device logs (requires device connected)
xcrun devicectl device process monitor --device <device-id> --filter "ios-test-app"
```

### 2.2 Checking Pending Notifications

**Via Plugin Method:**
```typescript
const result = await DailyNotification.getPendingNotifications();
console.log(`Pending: ${result.count}`);
```

**Via Swift Code:**
```swift
UNUserNotificationCenter.current().getPendingNotificationRequests { requests in
    print("Pending notifications: \(requests.count)")
    for request in requests {
        print("  - \(request.identifier): \(request.content.title)")
    }
}
```

### 2.3 Checking Background Task Status

**Via Plugin Method:**
```typescript
const status = await DailyNotification.getBackgroundTaskStatus();
console.log(`Fetch task registered: ${status.fetchTaskRegistered}`);
console.log(`Background refresh enabled: ${status.backgroundRefreshEnabled}`);
```

**Via Swift Code:**
```swift
// Check registration
let registered = BGTaskScheduler.shared.registeredTaskIdentifiers
print("Registered tasks: \(registered)")

// Check Background App Refresh (requires entitlement)
// Cannot check programmatically - must guide user to Settings
```

### 2.4 Simulating Background Tasks (Simulator Only)

**LLDB Command in Xcode:**
```lldb
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"org.timesafari.dailynotification.fetch"]
```

**Note:** This only works in simulator, not on physical devices.

---

## 3. Platform-Specific Considerations

### 3.1 Simulator vs Device

**Simulator Limitations:**
- Background tasks may not execute reliably
- Notifications may not fire at exact time
- Some features require physical device

**Device Testing:**
- More accurate behavior
- Background tasks execute (system-controlled)
- Notifications fire reliably

**Recommendation:** Test critical features on physical device.

### 3.2 iOS Version Differences

**iOS 12+:**
- Provisional notification authorization
- Background task improvements

**iOS 13+:**
- State actor support (concurrency)
- Improved background execution

**iOS 14+:**
- Notification interruption levels
- Focus modes (may affect notifications)

**iOS 15+:**
- Notification summary
- Focus mode integration

### 3.3 Background Execution Limits

**iOS Constraints:**
- BGTaskScheduler is system-controlled
- Execution timing not guaranteed
- Minimum intervals between tasks (hours)
- Tasks may be deferred or skipped

**Workaround:**
- Use BGTaskScheduler for prefetching only
- Don't rely on it for critical scheduling
- Use UNUserNotificationCenter for notifications (more reliable)

---

## 4. Error Codes

### 4.1 Common Error Codes

| Error Code | Description | Solution |
| ---------- | ----------- | -------- |
| `NOTIFICATION_PERMISSION_DENIED` | User denied notification permission | Guide user to Settings |
| `BACKGROUND_REFRESH_DISABLED` | Background App Refresh disabled | Guide user to enable in Settings |
| `PENDING_NOTIFICATION_LIMIT_EXCEEDED` | Exceeded 64 notification limit | Reduce scheduled notifications |
| `BG_TASK_NOT_REGISTERED` | Background task not registered | Check Info.plist and AppDelegate |
| `BG_TASK_EXECUTION_FAILED` | Background task execution failed | Check logs for specific error |

### 4.2 Checking Error Details

**Via Logs:**
```
DNP-ERROR: [Error Code] [Error Message]
DNP-ERROR: NOTIFICATION_PERMISSION_DENIED: User denied notification permission
```

**Via Plugin:**
```typescript
try {
    await DailyNotification.scheduleDailyNotification({...});
} catch (error) {
    console.error('Error code:', error.code);
    console.error('Error message:', error.message);
}
```

---

## 5. Performance Issues

### 5.1 Slow Notification Scheduling

**Symptoms:**
- Scheduling takes too long
- App freezes during scheduling

**Solutions:**
- Schedule notifications asynchronously
- Batch operations when possible
- Use background queue for heavy operations

### 5.2 High Memory Usage

**Symptoms:**
- App memory usage high
- Memory warnings in logs

**Solutions:**
- Implement notification cleanup
- Limit cached notifications
- Use efficient data structures

### 5.3 Battery Drain

**Symptoms:**
- Battery drains quickly
- Background activity high

**Solutions:**
- Limit background task frequency
- Optimize prefetch operations
- Use efficient scheduling algorithms

---

## 6. Getting Help

### 6.1 Log Collection

**Collect Logs:**
1. Reproduce the issue
2. Collect logs from Xcode Console or Console.app
3. Filter by `DNP-` prefix
4. Include relevant error messages

**Log Format:**
```
DNP-PLUGIN: [Message]
DNP-ERROR: [Error Code] [Error Message]
DNP-REACTIVATION: [Recovery Activity]
```

### 6.2 Issue Reporting

**Include:**
- iOS version
- Device model (or simulator)
- Plugin version
- Steps to reproduce
- Relevant logs
- Expected vs actual behavior

### 6.3 Documentation References

- [iOS Implementation Directive](./ios-implementation-directive.md)
- [Platform Capability Reference](./alarms/01-platform-capability-reference.md)
- [API Reference](../API.md)
- [iOS Logging Guide](../doc/test-app-ios/IOS_LOGGING_GUIDE.md)

---

## 7. Quick Reference

### 7.1 Common Commands

**Check Pending Notifications:**
```bash
# Via plugin method (recommended)
# Or check logs for scheduling activity
```

**View Logs:**
```bash
# Xcode Console (Cmd+Shift+Y)
# Filter: DNP-

# Console.app
# Filter: ios-test-app
```

**Check Permissions:**
```typescript
const status = await DailyNotification.getNotificationPermissionStatus();
```

**Open Settings:**
```typescript
await DailyNotification.openNotificationSettings();
await DailyNotification.openBackgroundAppRefreshSettings();
```

### 7.2 Checklist

**Before Reporting Issue:**
- [ ] Checked notification permissions
- [ ] Verified Background App Refresh is enabled
- [ ] Checked pending notification count (< 64)
- [ ] Reviewed logs for errors
- [ ] Tested on physical device (not just simulator)
- [ ] Verified iOS version compatibility
- [ ] Checked device storage availability

---

**Document Version**: 1.0.0  
**Last Updated**: 2025-12-08  
**Next Review**: After Phase 1 implementation

