Files
daily-notification-plugin/docs/ios-troubleshooting-guide.md
Matthew dd8d67462f docs(ios): add comprehensive iOS implementation documentation
Adds complete iOS documentation suite to support iOS implementation
parity with Android features. Includes implementation directives,
recovery scenario mappings, database migration guide, troubleshooting
guide, and test scripts.

New Documentation:
- iOS Implementation Directive: Phase-based implementation guide
  mirroring Android structure with iOS-specific considerations
- iOS Recovery Scenario Mapping: Maps Android recovery scenarios
  to iOS equivalents with detection logic comparisons
- iOS Core Data Migration Guide: Complete Room → Core Data entity
  mappings with implementation checklist for missing entities
- iOS Troubleshooting Guide: Common issues, debugging techniques,
  and error code reference

Enhanced Documentation:
- API.md: Added iOS-only methods (permissions, background tasks,
  pending notifications), platform differences table, and iOS-specific
  error types. Updated version to 2.3.0.

Test Infrastructure:
- iOS test scripts for Phase 1 (cold start), Phase 2 (termination),
  and Phase 3 (boot recovery) testing scenarios

All documentation addresses gaps identified in iOS Implementation
Documentation Review and provides foundation for iOS recovery feature
implementation (currently pending).

Note: iOS recovery features (ReactivationManager, scenario detection)
are NOT yet implemented. Documentation is ready to guide implementation.
2025-12-08 23:36:30 -08:00

14 KiB

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:


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:

    // 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:

    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:

    // Verify registration in AppDelegate
    BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.timesafari.dailynotification.fetch", using: nil) { task in
        // Handler should be registered
    }
    
  2. Check Info.plist:

    <key>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
        <string>com.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:

    // ✅ 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:

  • 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:

    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:

    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:

# 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:

const result = await DailyNotification.getPendingNotifications();
console.log(`Pending: ${result.count}`);

Via Swift Code:

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:

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

Via Swift Code:

// 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:

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:

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


7. Quick Reference

7.1 Common Commands

Check Pending Notifications:

# Via plugin method (recommended)
# Or check logs for scheduling activity

View Logs:

# Xcode Console (Cmd+Shift+Y)
# Filter: DNP-

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

Check Permissions:

const status = await DailyNotification.getNotificationPermissionStatus();

Open Settings:

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