# 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: "com.timesafari.dailynotification.fetch", using: nil) { task in
// Handler should be registered
}
```
2. **Check Info.plist:**
```xml
BGTaskSchedulerPermittedIdentifiers
com.timesafari.dailynotification.fetch
```
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 log stream --level=debug --predicate 'processImagePath contains "ios-test-app"'
# Device logs (requires device connected)
xcrun devicectl device process monitor --device --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:@"com.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