Files
daily-notification-plugin/docs/ios-implementation-directive.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
Raw Blame History

iOS Implementation Directive: App Launch Recovery & Missed Notification Detection

Author: Matthew Raymer
Date: 2025-12-08
Status: Active Implementation Directive - iOS Only
Version: 1.0.0
Last Synced With Plugin Version: v1.1.0

Purpose

This directive provides descriptive overview and integration guidance for iOS-specific recovery and missed notification detection:

  1. App Launch Recovery (cold/warm/terminated)
  2. Missed Notification Detection
  3. App Termination Detection
  4. Background Task Registration for Boot Recovery

⚠️ CRITICAL: This document is descriptive and integrative. The normative implementation instructions are in the Phase 13 directives below. If any code or behavior in this file conflicts with a Phase directive, the Phase directive wins.

Reference: See Plugin Requirements for requirements that Phase directives implement.

Reference: See Platform Capability Reference for iOS OS-level facts.

⚠️ IMPORTANT: For implementation, use the phase-specific directives (these are the canonical source of truth):

See Also: Unified Alarm Directive for master coordination document.


1. Implementation Overview

1.1 What Needs to Be Implemented

Feature Status Priority Location
App Launch Recovery Missing High DailyNotificationPlugin.swift - load() method
Missed Notification Detection ⚠️ Partial High DailyNotificationPlugin.swift - new method
App Termination Detection Missing High DailyNotificationPlugin.swift - recovery logic
Background Task Registration ⚠️ Partial Medium AppDelegate.swift - BGTaskScheduler registration

1.2 Implementation Strategy

Phase 1 Cold start recovery only

  • Missed notification detection + future notification verification
  • No termination detection, no boot handling
  • See Phase 1 directive for implementation

Phase 2 App termination detection & full recovery

  • Termination detection via UNUserNotificationCenter state comparison
  • Comprehensive recovery of all schedules (notify + fetch)
  • Past notifications marked as missed, future notifications rescheduled
  • See Phase 2 directive for implementation

Phase 3 Background task registration & boot recovery

  • BGTaskScheduler registration for boot recovery
  • Next occurrence rescheduled for repeating schedules
  • See Phase 3 directive for implementation

2. iOS-Specific Considerations

2.1 Key Differences from Android

iOS Advantages:

  • Notifications persist across app termination (OS-guaranteed)
  • Notifications persist across device reboot (OS-guaranteed)
  • No force stop equivalent (iOS doesn't have user-facing force stop)

iOS Challenges:

  • App code does NOT run when notification fires (only if user taps)
  • Background execution severely limited (BGTaskScheduler only)
  • Cannot rely on background execution for recovery
  • Must detect missed notifications on app launch

Platform Reference: See Platform Capability Reference §3 for complete iOS behavior matrix.

2.2 Recovery Scenario Mapping

Android → iOS Mapping:

Android Scenario iOS Equivalent Detection Method
COLD_START App Launch After Termination Check if notifications exist vs DB state
FORCE_STOP App Terminated by System Check if notifications missing vs DB state
BOOT Device Reboot BGTaskScheduler registration (Phase 3)
WARM_START App Resume (Foreground) Check app state on resume

Note: iOS doesn't have a user-facing "force stop" equivalent. System termination is detected by comparing UNUserNotificationCenter state with database state.

2.3 iOS APIs Used

Notification Management:

  • UNUserNotificationCenter.current() - Notification center
  • UNUserNotificationCenter.getPendingNotificationRequests() - Check scheduled notifications
  • UNUserNotificationCenter.add() - Schedule notifications

Background Tasks:

  • BGTaskScheduler.shared - Background task scheduler
  • BGTaskScheduler.register() - Register background task handlers
  • BGAppRefreshTaskRequest - Background fetch requests

App Lifecycle:

  • applicationWillTerminate - App termination notification
  • applicationDidBecomeActive - App foreground notification
  • applicationDidEnterBackground - App background notification

3. Implementation: ReactivationManager (iOS)

⚠️ Illustrative only See Phase 1 and Phase 2 directives for canonical implementation.

ReactivationManager Responsibilities by Phase:

Phase Responsibilities
1 Cold start only (missed detection + verify/reschedule future)
2 Adds termination detection & recovery
3 Background task registration & boot recovery

For implementation details, see:

3.1 Create New File

File: ios/Plugin/DailyNotificationReactivationManager.swift

Purpose: Centralized recovery logic for app launch scenarios

3.2 Class Structure

⚠️ Illustrative only See Phase 1 for canonical implementation.

import Foundation
import UserNotifications

/**
 * Manages recovery of notifications on app launch
 * Handles cold start, warm start, and termination recovery scenarios
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */
class DailyNotificationReactivationManager {
    
    private static let TAG = "DNP-REACTIVATION"
    private let notificationCenter = UNUserNotificationCenter.current()
    private let database: DailyNotificationDatabase
    private let storage: DailyNotificationStorage
    
    init(database: DailyNotificationDatabase, storage: DailyNotificationStorage) {
        self.database = database
        self.storage = storage
    }
    
    /**
     * Perform recovery on app launch
     * Detects scenario (cold/warm/termination) and handles accordingly
     */
    func performRecovery() async {
        do {
            NSLog("\(Self.TAG): Starting app launch recovery")
            
            // Step 1: Detect scenario
            let scenario = try await detectScenario()
            NSLog("\(Self.TAG): Detected scenario: \(scenario)")
            
            // Step 2: Handle based on scenario
            switch scenario {
            case .termination:
                try await handleTerminationRecovery()
            case .coldStart:
                try await handleColdStartRecovery()
            case .warmStart:
                try await handleWarmStartRecovery()
            case .none:
                NSLog("\(Self.TAG): No recovery needed")
            }
            
            NSLog("\(Self.TAG): App launch recovery completed")
        } catch {
            NSLog("\(Self.TAG): Error during app launch recovery: \(error)")
        }
    }
    
    // ... implementation methods below ...
}

4. Recovery Scenario Detection

4.1 Scenario Detection Algorithm

Platform Reference: iOS §3.1.1 - Notifications survive app termination

Detection Logic:

enum RecoveryScenario {
    case none          // No recovery needed (first launch or warm resume)
    case coldStart     // App launched after termination, notifications may exist
    case termination   // App terminated, notifications missing vs DB
    case warmStart     // App resumed from background (optimization only)
}

func detectScenario() async throws -> RecoveryScenario {
    // Step 1: Check if database has schedules
    let schedules = try database.getEnabledSchedules()
    if schedules.isEmpty {
        return .none  // First launch
    }
    
    // Step 2: Get pending notifications from UNUserNotificationCenter
    let pendingNotifications = try await notificationCenter.pendingNotificationRequests()
    
    // Step 3: Compare DB state with notification center state
    let dbNotificationIds = Set(schedules.flatMap { $0.getScheduledNotificationIds() })
    let pendingIds = Set(pendingNotifications.map { $0.identifier })
    
    // Step 4: Determine scenario
    if pendingIds.isEmpty && !dbNotificationIds.isEmpty {
        // DB has schedules but no notifications scheduled
        return .termination
    } else if !pendingIds.isEmpty && !dbNotificationIds.isEmpty {
        // Both have data - check if they match
        if dbNotificationIds != pendingIds {
            return .coldStart  // Mismatch indicates recovery needed
        } else {
            return .warmStart  // Match indicates warm resume
        }
    }
    
    return .none
}

For complete implementation, see: Phase 1 directive


5. Missed Notification Detection

5.1 Detection Logic

Platform Reference: iOS §3.2.1 - App code does not run when notification fires

iOS Behavior: When a notification fires, the app code does NOT execute. The notification is displayed, but the app must detect missed notifications on the next app launch.

Detection Steps:

  1. Query database for notifications with scheduled_time < currentTime
  2. Filter for notifications with delivery_status != 'delivered'
  3. Mark as 'missed' in database
  4. Record in history table

For complete implementation, see: Phase 1 directive


6. Background Task Registration

6.1 BGTaskScheduler Registration

Platform Reference: iOS §3.1.3 - Background tasks for prefetching

iOS Limitation: BGTaskScheduler cannot be used for critical scheduling. It's system-controlled and not guaranteed.

Use Case: BGTaskScheduler is used for:

  • Prefetching content (not critical timing)
  • Boot recovery (system may defer)
  • Background maintenance (best effort)

Registration Location: AppDelegate.swift or SceneDelegate.swift

For complete implementation, see: Phase 3 directive


7. Testing Strategy

7.1 iOS Testing Tools

Simulator Testing:

  • xcrun simctl - Simulator control
  • Xcode Instruments - Performance profiling
  • Console.app - System log viewing

Device Testing:

  • Xcode Device Console - Real device logs
  • Settings → Developer → Background App Refresh - Control background execution

7.2 Test Scenarios

Phase 1 Tests:

  • Cold start recovery
  • Missed notification detection
  • Future notification verification

Phase 2 Tests:

  • App termination detection
  • Comprehensive recovery
  • Multiple schedules recovery

Phase 3 Tests:

  • Background task registration
  • Boot recovery (simulated)
  • Background task execution

For complete test procedures, see: iOS Test Scripts


8. Platform-Specific Notes

8.1 Notification Persistence

iOS Advantage: Notifications persist automatically across:

  • App termination
  • Device reboot (for calendar/time triggers)

App Responsibility: Must still:

  • Detect missed notifications on app launch
  • Reschedule future notifications if needed
  • Track delivery status in database

8.2 Background Execution Limits

iOS Limitation: Background execution is severely limited:

  • BGTaskScheduler is system-controlled
  • Cannot rely on background execution for recovery
  • Must handle recovery on app launch

Workaround: Use BGTaskScheduler for prefetching only, not for critical scheduling.

8.3 Timing Tolerance

iOS Limitation: Calendar-based notifications have ±180 second tolerance.

Impact: Notifications may fire up to 3 minutes early or late.

Mitigation: Account for tolerance in missed notification detection logic.


9. Next Steps

  1. Start with Phase 1: Implement cold start recovery

    • See Phase 1 directive
    • Focus on missed notification detection
    • Verify future notifications are scheduled
  2. Proceed to Phase 2: Add termination detection

  3. Complete Phase 3: Background task registration


10. References


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