575 lines
14 KiB
Markdown
575 lines
14 KiB
Markdown
# 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
|
|
|