Files
daily-notification-plugin/ios/Plugin
Jose Olarte III d2a1041cc4 feat(ios): add missed rollover recovery for background/inactive app scenarios
Implement enhanced app launch recovery to detect and schedule missed rollover
notifications that occurred while the app was terminated, backgrounded, or
inactive.

Key improvements:
- Detect missed rollovers on app launch by checking for past notifications
  without next scheduled notification
- Add active rollover check when app becomes active (handles inactive app
  scenario where notifications fire silently)
- Calculate forward to future time when next scheduled time is in the past
  (handles delays > rollover interval)
- Enhance duplicate detection to exclude original notification from checks
- Retry rollover if previous attempt failed (rollover time set but no next
  notification exists)

Changes:
- DailyNotificationReactivationManager: Add detectAndProcessMissedRollovers()
  method and performActiveRolloverCheck() for app becoming active
- DailyNotificationReactivationManager: Enhance warm start scenario to check
  for missed rollovers
- DailyNotificationScheduler: Add forward calculation loop when next scheduled
  time is in the past
- DailyNotificationPlugin: Register observer for UIApplication.didBecomeActiveNotification
  to trigger rollover check when app becomes active

Fixes rollover scheduling for:
- App terminated: Rollover now detected and scheduled on next launch
- App inactive/backgrounded: Rollover detected when app becomes active
- Delayed recovery: Handles cases where app reopened after rollover interval
  has passed by calculating forward to next future time

All scenarios now properly schedule rollover notifications regardless of app
state when notification fires.
2026-01-09 20:02:40 +08:00
..

iOS Implementation

This directory contains the iOS-specific implementation of the DailyNotification plugin.

Last Updated: 2025-12-22
Version: 1.1.0

Current Implementation Status

IMPLEMENTED:

  • Basic plugin structure (DailyNotificationPlugin.swift)
  • UserDefaults for local data storage
  • Power management (DailyNotificationPowerManager.swift)
  • Battery optimization handling
  • iOS notification categories and actions
  • App Launch Recovery (DailyNotificationReactivationManager.swift)
    • Cold start recovery
    • Termination recovery
    • Boot recovery
    • Scenario detection
    • Missed notification detection
    • Future notification verification
  • Core Data Integration
    • NotificationContent, NotificationDelivery, NotificationConfig entities
    • DAO classes for all entities (CRUD operations)
    • Data type conversions (Date ↔ Int64, etc.)
    • PersistenceController with entity verification
  • Logging & Observability
    • Comprehensive recovery logging
    • Metrics recording in Core Data History
    • Execution time tracking
  • Error Handling
    • iOS-specific error codes
    • Graceful error handling (non-fatal)
    • Partial results on failures
  • API Methods
    • iOS-specific notification permission methods
    • Background task status methods
    • Pending notifications query

⚠️ PARTIALLY IMPLEMENTED:

  • BGTaskScheduler for background data fetching (basic registration)
  • Background task management (needs enhancement)

NOT IMPLEMENTED (Planned):

  • Silent push nudge support
  • Tlead prefetch logic (enhancement)

Implementation Details

The iOS implementation currently uses:

  • UNUserNotificationCenter for notification management
  • UserDefaults for local data storage
  • iOS notification categories and actions
  • Power management and battery optimization
  • Core Data for structured data persistence
  • BGTaskScheduler for background task registration
  • App Launch Recovery for notification reconciliation

Architecture:

  • ReactivationManager: Handles app launch recovery scenarios
  • DAO Layer: Core Data access objects for all entities
  • Data Conversions: Type conversion utilities (Date, Int, String, JSON)
  • History Recording: Core Data persistence for recovery metrics
  • Error Handling: Comprehensive error codes and graceful degradation

Planned additions:

  • Enhanced background task management
  • Silent push support

Native Code Location

The native iOS implementation is located in the ios/ directory at the project root.

Key Components

  1. DailyNotificationPlugin.swift: Main plugin class
  2. DailyNotificationPowerManager.swift: Power state management
  3. DailyNotificationConfig.swift: Configuration options
  4. DailyNotificationMaintenanceWorker.swift: Maintenance tasks
  5. DailyNotificationLogger.swift: Logging system
  6. DailyNotificationReactivationManager.swift: App launch recovery
  7. HistoryDAO.swift: Recovery history persistence
  8. NotificationContentDAO.swift: Notification content CRUD
  9. NotificationDeliveryDAO.swift: Delivery tracking CRUD
  10. NotificationConfigDAO.swift: Configuration CRUD
  11. DailyNotificationDataConversions.swift: Type conversion utilities
  12. DailyNotificationErrorCodes.swift: iOS-specific error codes
  13. DailyNotificationModel.swift: Core Data model & PersistenceController

Background Task Components:

  • DailyNotificationBackgroundTasks.swift: Background task handlers ⚠️ (basic)
  • DailyNotificationBackgroundTaskManager.swift: Task management ⚠️ (basic)

Implementation Notes

  • Uses UserDefaults for lightweight data storage
  • Uses Core Data for structured data persistence
  • Implements proper battery optimization handling
  • Supports iOS notification categories and actions
  • Handles background refresh limitations
  • App launch recovery with scenario detection
  • Comprehensive error handling (non-fatal)
  • Metrics recording and observability
  • BGTaskScheduler registration

Recovery Scenarios Supported:

  • Cold Start: App terminated, notifications may need verification
  • Termination: App terminated, all notifications cleared
  • Boot: Device rebooted, full recovery needed
  • Warm Start: No recovery needed (optimization)

Planned Features:

  • Enhanced background task budget management
  • Silent push notification support
  • Advanced prefetch logic

Schema Versioning Strategy

Current Schema Version: 1 (initial schema)

The iOS implementation uses explicit schema versioning to achieve parity with Android's Room database versioning approach. This provides observability and migration tracking without interfering with CoreData's automatic migration capabilities.

Versioning Approach

CoreData Auto-Migration Remains Authoritative

The schema version is a logical contract, not a forced migration trigger. CoreData auto-migration (shouldMigrateStoreAutomatically = true) remains the authoritative mechanism for schema changes. Version mismatches are logged, not blocked.

Version Tracking

Schema version is stored in CoreData persistent store metadata using NSPersistentStore metadata dictionary. This approach:

  • Non-intrusive (does not require schema changes)
  • Observable (version can be read at any time)
  • Compatible with CoreData auto-migration
  • Matches Android's explicit versioning pattern

Current Implementation

  • Schema Version: 1 (initial schema, established 2025-09-22)
  • Version Storage: NSPersistentStore metadata key "schema_version"
  • Version Check: Performed during PersistenceController initialization
  • Logging: Version logged on store load; mismatches logged as warnings

Migration Contract

When to Bump Schema Version

The schema version should be incremented when:

  1. Entity changes:

    • Adding new entities
    • Removing entities (rare, requires data migration)
    • Renaming entities (requires explicit migration)
  2. Attribute changes:

    • Adding new required attributes (requires default values or migration)
    • Removing attributes (requires data cleanup)
    • Changing attribute types (requires type conversion)
    • Renaming attributes (requires explicit migration)
  3. Relationship changes:

    • Adding/removing relationships
    • Changing relationship cardinality
    • Renaming relationships

When NOT to Bump

  • Adding optional attributes (CoreData handles automatically)
  • Adding optional relationships (CoreData handles automatically)
  • Changing default values (no schema change required)
  • Adding indexes (metadata change, not schema change)

Version Bump Process

  1. Update CoreData model in Xcode (add/remove/modify entities/attributes)
  2. Increment schema version constant in PersistenceController
  3. Update metadata on next store load
  4. Document migration in changelog
  5. Update parity matrix if versioning strategy changes

Android Parity

Android: Room database with explicit version = 2 and Migration objects
iOS: CoreData with explicit schema version 1 in metadata + auto-migration

Both platforms now have:

  • Explicit version tracking
  • Migration documentation
  • Version observability
  • Migration contract defined

Parity Status: Explicit versioning (P2.1 complete)

  • Android Schema Versioning: android/src/main/java/com/timesafari/dailynotification/DatabaseSchema.kt (Room version = 2)
  • CoreData Model: ios/Plugin/DailyNotificationModel.xcdatamodeld
  • PersistenceController: ios/Plugin/DailyNotificationModel.swift
  • Parity Matrix: docs/progress/04-PARITY-MATRIX.md

Testing

Run iOS-specific tests with:

npm run test:ios