chore: synch diretive before starting
This commit is contained in:
@@ -36,6 +36,50 @@ This directive outlines the plan to upgrade the iOS implementation of the Daily
|
||||
|
||||
---
|
||||
|
||||
## Minimal Viable Parity Definition
|
||||
|
||||
**Objective:** Define the exact minimal scope iOS must meet before Android parity is considered achieved for Phase 1.
|
||||
|
||||
### Required Method Implementations (Phase 1)
|
||||
|
||||
- `configure()` - Plugin configuration with database/storage options
|
||||
- `scheduleDailyNotification()` - Schedule single daily notification (one prefetch + one notification)
|
||||
- `getLastNotification()` - Get last delivered notification
|
||||
- `cancelAllNotifications()` - Cancel all scheduled notifications
|
||||
- `getNotificationStatus()` - Get current notification status
|
||||
- `updateSettings()` - Update notification settings
|
||||
|
||||
### Required Background Task Behavior
|
||||
|
||||
- **Prefetch Task:** Scheduled 5 minutes before notification time via BGTaskScheduler
|
||||
- **Notification:** Scheduled at user-specified time via UNUserNotificationCenter
|
||||
- **Fallback:** If BGTaskScheduler task not run within 15 minutes of `earliestBeginDate`, trigger reschedule
|
||||
- **Error Handling:** Return same error codes as Android (see Error Code Matching section)
|
||||
|
||||
### Required Durability Guarantees
|
||||
|
||||
- **Storage:** Content cached in UserDefaults or CoreData
|
||||
- **Persistence:** Schedule survives app termination
|
||||
- **Recovery:** On app launch, reschedule today's schedule from persisted settings
|
||||
- Full reboot detection and status reporting is introduced in **Phase 2**
|
||||
- Phase 1 uses simple "reschedule on launch" approach
|
||||
|
||||
### Required Error Handling Surface
|
||||
|
||||
- All methods must return same error keys as Android
|
||||
- All methods must return same JSON shape as Android
|
||||
- All methods must log using same categories as Android
|
||||
|
||||
### Required JSON Return Structure
|
||||
|
||||
Each method must match Android's return structure exactly:
|
||||
- Same field names
|
||||
- Same data types
|
||||
- Same nullability rules
|
||||
- Same error response format
|
||||
|
||||
---
|
||||
|
||||
## Current State Assessment
|
||||
|
||||
### Android Implementation (Reference)
|
||||
@@ -162,140 +206,156 @@ This directive outlines the plan to upgrade the iOS implementation of the Daily
|
||||
|
||||
### Phase 1: Core Infrastructure Parity
|
||||
|
||||
**Objective:** Implement core notification scheduling and management methods with simplified daily schedule
|
||||
**Objective:** Implement core notification scheduling with single daily schedule (one prefetch + one notification).
|
||||
|
||||
**Tasks:**
|
||||
1. **Storage Layer Enhancement**
|
||||
- Enhance `DailyNotificationStorage` (Swift equivalent) to match Android `DailyNotificationStorage.java`
|
||||
- Support both UserDefaults and SQLite (CoreData) storage modes
|
||||
- Implement content caching and retrieval
|
||||
**Deliverables:**
|
||||
1. Storage layer (UserDefaults/CoreData) with content caching
|
||||
2. Scheduler (UNUserNotificationCenter) with timing tolerance (±180s) and permission auto-healing
|
||||
3. Background fetching (BGTaskScheduler) with fallback rescheduling (15 min window)
|
||||
4. Core methods: `configure()`, `scheduleDailyNotification()`, `getLastNotification()`, `cancelAllNotifications()`, `getNotificationStatus()`, `updateSettings()`
|
||||
|
||||
2. **Scheduler Implementation**
|
||||
- Create `DailyNotificationScheduler.swift` equivalent to `DailyNotificationScheduler.java`
|
||||
- Use `UNUserNotificationCenter` for notification scheduling
|
||||
- **Initial:** Support single daily notification (one prefetch + one notification per day)
|
||||
- Rolling window logic deferred to Phase 2
|
||||
**Key Constraints:**
|
||||
- Phase 1 uses dummy/static content fetcher (no JWT/ETag - deferred to Phase 3)
|
||||
- Timing tolerance: iOS notifications may drift up to 180 seconds
|
||||
- BGTaskScheduler fallback: Auto-reschedule if task missed within 15 min window (see BGTask Miss Detection below)
|
||||
- Concurrency: Use Swift `actor` or serial queue for DB/cache access (see Concurrency & Reentrancy Rules section)
|
||||
|
||||
3. **Background Fetching**
|
||||
- Enhance `DailyNotificationBackgroundTaskManager.swift` to match Android `DailyNotificationFetcher.java`
|
||||
- Implement `BGTaskScheduler` registration and execution
|
||||
- **Initial:** Support single daily prefetch task (scheduled 5 minutes before notification)
|
||||
- Add content fetching with ETag support
|
||||
**Permission Auto-Healing:**
|
||||
|
||||
4. **Core Methods Implementation**
|
||||
- `scheduleDailyNotification()` - Main scheduling method (single daily schedule)
|
||||
- `getLastNotification()` - Last notification retrieval
|
||||
- `cancelAllNotifications()` - Cancel all
|
||||
- `getNotificationStatus()` - Status retrieval
|
||||
- `updateSettings()` - Settings update
|
||||
On every call to `scheduleDailyNotification()`:
|
||||
|
||||
**Platform Adaptations:**
|
||||
- Android `AlarmManager` → iOS `UNUserNotificationCenter` with `UNCalendarNotificationTrigger`
|
||||
- Android `WorkManager` → iOS `BGTaskScheduler` with `BGAppRefreshTaskRequest`
|
||||
- Android `SharedPreferences` → iOS `UserDefaults` (with SQLite option via CoreData)
|
||||
1. Read current `UNUserNotificationCenter.getNotificationSettings()`
|
||||
2. If `authorizationStatus == .denied`:
|
||||
- Return error: `{ error: "notifications_denied", message: "Notification permissions denied" }`
|
||||
- Log: `[DNP-PLUGIN] notifications_denied for scheduleDailyNotification`
|
||||
- **DO NOT schedule** (prevents ghost schedules)
|
||||
3. If `authorizationStatus == .notDetermined`:
|
||||
- **Option A (test app):** Call `requestAuthorization()` then retry once
|
||||
- **Option B (library):** Fail fast with `notifications_denied` and let host request permissions
|
||||
4. **Never silently "succeed"** when notifications are denied
|
||||
|
||||
**Test App Readiness:** Phase 1 test app should be ready for testing on iOS Simulator after core methods are implemented
|
||||
**BGTask Miss Detection:**
|
||||
|
||||
On every app launch and every plugin entry point that touches scheduling:
|
||||
|
||||
1. Read the last scheduled BGTask `earliestBeginDate` from storage
|
||||
2. Read the last successful run timestamp from storage
|
||||
3. If `now > earliestBeginDate + 15 minutes` **and no successful run timestamp is recorded**, treat the task as "missed":
|
||||
- Log: `[DNP-FETCH] BGTask missed window; rescheduling`
|
||||
- Schedule a new BGTask with `earliestBeginDate = now + 1 minute`
|
||||
- Update stored `earliestBeginDate` in storage
|
||||
|
||||
**Successful Run Definition:**
|
||||
|
||||
A "successful run" is defined as: BGTask handler invoked, content fetch completed (even if 304 Not Modified), and next schedule successfully submitted; only then update `lastSuccessfulRunTimestamp`. Do not set the timestamp on handler entry or partial completion.
|
||||
|
||||
**Completion Criteria:**
|
||||
- All Phase 1 methods implemented and tested
|
||||
- Single daily schedule working (prefetch 5 min before notification)
|
||||
- Test app ready for iOS Simulator testing
|
||||
|
||||
### Phase 2: Advanced Features Parity
|
||||
|
||||
**Objective:** Implement advanced features matching Android capabilities
|
||||
**Objective:** Implement rolling window, TTL enforcement, exact alarm equivalent, reboot recovery, and power management.
|
||||
|
||||
**Tasks:**
|
||||
1. **Rolling Window Management**
|
||||
- Enhance `DailyNotificationRollingWindow.swift` to match Android implementation
|
||||
- Implement iOS-specific limits (64 pending notifications)
|
||||
- Add maintenance scheduling
|
||||
- **Note:** Expands beyond single daily schedule to support rolling window
|
||||
**Deliverables:**
|
||||
1. Rolling window (expand beyond single daily schedule, enforce iOS 64 limit)
|
||||
2. TTL enforcement (check at notification fire time, discard stale content)
|
||||
3. Exact alarm equivalent (UNCalendarNotificationTrigger with tolerance, document iOS constraints)
|
||||
4. Reboot recovery (uptime comparison strategy, auto-reschedule on app launch)
|
||||
5. Power management (battery status, Background App Refresh status)
|
||||
|
||||
2. **TTL Enforcement**
|
||||
- Enhance `DailyNotificationTTLEnforcer.swift` to match Android implementation
|
||||
- Implement TTL checking at notification fire time
|
||||
- Add stale content handling
|
||||
**Key Constraints:**
|
||||
- **iOS cannot guarantee exact delivery** like Android's `setExact()`; TimeSafari must treat ±180s as the design target, not a bug
|
||||
- iOS notifications are "best effort" not "exact" (may drift, batch, or delay)
|
||||
- Rolling window must respect iOS 64 pending notification limit
|
||||
- Reboot detection via system uptime comparison (no BOOT_COMPLETED equivalent)
|
||||
|
||||
3. **Exact Alarm Equivalent**
|
||||
- Implement iOS equivalent of Android exact alarm management
|
||||
- Use `UNTimeIntervalNotificationTrigger` for precise timing
|
||||
- Handle iOS notification delivery guarantees
|
||||
|
||||
4. **Reboot Recovery**
|
||||
- Create `DailyNotificationRebootRecoveryManager.swift` equivalent
|
||||
- Use iOS app launch detection to reschedule notifications
|
||||
- Implement recovery status tracking
|
||||
|
||||
5. **Power Management**
|
||||
- Enhance `DailyNotificationPowerManager.swift` to match Android capabilities
|
||||
- Implement battery status checking
|
||||
- Add background refresh status checking
|
||||
|
||||
**Platform Adaptations:**
|
||||
- Android exact alarms → iOS notification delivery with time-based triggers
|
||||
- Android battery optimization → iOS Background App Refresh settings
|
||||
- Android reboot recovery → iOS app launch detection and rescheduling
|
||||
|
||||
**Test App Readiness:** Phase 2 test app should be ready for testing rolling window and advanced features on iOS Simulator
|
||||
**Completion Criteria:**
|
||||
- Rolling window functional with iOS limits enforced
|
||||
- TTL validation working at notification delivery
|
||||
- Reboot recovery tested and working
|
||||
- Test app ready for advanced feature testing
|
||||
|
||||
### Phase 3: TimeSafari Integration Parity
|
||||
|
||||
**Objective:** Implement TimeSafari-specific integration features
|
||||
**Objective:** Implement JWT authentication, ETag caching, and TimeSafari API integration.
|
||||
|
||||
**Tasks:**
|
||||
1. **JWT Management**
|
||||
- Create `DailyNotificationJWTManager.swift` equivalent
|
||||
- Implement JWT token generation and caching
|
||||
- Add token refresh logic
|
||||
**Deliverables:**
|
||||
1. JWT management (ES256K signing, token generation/caching, refresh logic)
|
||||
2. ETag management (conditional requests, caching, invalidation)
|
||||
3. Enhanced fetcher (TimeSafari API integration, activeDid support)
|
||||
4. Integration methods: `setActiveDidFromHost()`, `refreshAuthenticationForNewIdentity()`, `clearCacheForNewIdentity()`, `updateBackgroundTaskIdentity()`, `testJWTGeneration()`, `testEndorserAPI()`
|
||||
|
||||
2. **ETag Management**
|
||||
- Enhance `DailyNotificationETagManager.swift` to match Android
|
||||
- Implement ETag caching and conditional requests
|
||||
- Add ETag invalidation logic
|
||||
**Key Constraints:**
|
||||
- Replace Phase 1 dummy fetcher with JWT-signed fetcher
|
||||
- Use same JWT algorithm as Android (ES256K)
|
||||
- ETag validation must match Android behavior
|
||||
|
||||
3. **Enhanced Fetcher**
|
||||
- Create `EnhancedDailyNotificationFetcher.swift` equivalent
|
||||
- Implement TimeSafari API integration
|
||||
- Add activeDid support
|
||||
|
||||
4. **Phase 1 Methods**
|
||||
- `setActiveDidFromHost()` - ActiveDid management
|
||||
- `refreshAuthenticationForNewIdentity()` - Auth refresh
|
||||
- `clearCacheForNewIdentity()` - Cache clearing
|
||||
- `updateBackgroundTaskIdentity()` - Background task identity
|
||||
- `testJWTGeneration()` - JWT testing
|
||||
- `testEndorserAPI()` - API testing
|
||||
|
||||
**Platform Adaptations:**
|
||||
- Android WorkManager background tasks → iOS BGTaskScheduler background tasks
|
||||
- Android SharedPreferences for config → iOS UserDefaults for config
|
||||
- Android JWT signing → iOS JWT signing (same algorithm, different implementation)
|
||||
|
||||
**TimeSafari Integration Readiness:** Library ready for TimeSafari integration after Phase 3 completion
|
||||
**Test App Readiness:** Phase 3 test app should be ready for testing TimeSafari integration features on iOS Simulator
|
||||
**Completion Criteria:**
|
||||
- JWT authentication working with TimeSafari API
|
||||
- ETag caching reducing unnecessary network requests
|
||||
- Library ready for TimeSafari integration
|
||||
- Test app ready for integration testing
|
||||
|
||||
### Phase 4: Background Coordination Parity
|
||||
|
||||
**Objective:** Implement background task coordination features
|
||||
**Objective:** Implement background task coordination with TimeSafari PlatformServiceMixin.
|
||||
|
||||
**Tasks:**
|
||||
1. **Background Coordination**
|
||||
- Implement `coordinateBackgroundTasks()` method
|
||||
- Add TimeSafari PlatformServiceMixin integration
|
||||
- Coordinate BGTaskScheduler with app lifecycle
|
||||
**Deliverables:**
|
||||
1. Background coordination (`coordinateBackgroundTasks()` method)
|
||||
2. Lifecycle management (`handleAppLifecycleEvent()` for app background/foreground)
|
||||
3. Coordination status (`getCoordinationStatus()` for debugging)
|
||||
|
||||
2. **Lifecycle Management**
|
||||
- Implement `handleAppLifecycleEvent()` method
|
||||
- Handle app background/foreground events
|
||||
- Sync state with app lifecycle
|
||||
**Key Constraints:**
|
||||
- Coordinate BGTaskScheduler with app lifecycle events
|
||||
- Sync state between plugin and TimeSafari PlatformServiceMixin
|
||||
- Track coordination state for debugging
|
||||
|
||||
3. **Coordination Status**
|
||||
- Implement `getCoordinationStatus()` method
|
||||
- Track coordination state
|
||||
- Provide debugging information
|
||||
**Completion Criteria:**
|
||||
- Background tasks coordinated with app lifecycle
|
||||
- Full library ready for production TimeSafari integration
|
||||
- Test app ready for full coordination testing
|
||||
|
||||
**Platform Adaptations:**
|
||||
- Android app lifecycle callbacks → iOS app lifecycle notifications
|
||||
- Android WorkManager coordination → iOS BGTaskScheduler coordination
|
||||
---
|
||||
|
||||
**TimeSafari Integration Readiness:** Full library ready for production TimeSafari integration after Phase 4 completion
|
||||
**Test App Readiness:** Phase 4 test app should be ready for testing full background coordination on iOS Simulator
|
||||
## Cross-Platform Method Equivalence Table
|
||||
|
||||
**Canonical source of truth for all @PluginMethod implementations**
|
||||
|
||||
**Note:** TypeScript signatures in this table are illustrative; the **source of truth** is `src/definitions.ts`. Any changes in `definitions.ts` must be reflected here and in the iOS implementation. Verify signatures match `definitions.ts` before implementation.
|
||||
|
||||
| Android Method | TypeScript Interface | iOS Swift Method | iOS File | Phase | Status |
|
||||
|----------------|---------------------|------------------|----------|-------|--------|
|
||||
| `configure()` | `configure(options: ConfigureOptions): Promise<void>` | `@objc func configure(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 1 | ✅ Partial |
|
||||
| `scheduleDailyNotification()` | `scheduleDailyNotification(options: NotificationOptions): Promise<void>` | `@objc func scheduleDailyNotification(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 1 | ❌ Missing |
|
||||
| `getLastNotification()` | `getLastNotification(): Promise<NotificationResponse \| null>` | `@objc func getLastNotification(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 1 | ❌ Missing |
|
||||
| `cancelAllNotifications()` | `cancelAllNotifications(): Promise<void>` | `@objc func cancelAllNotifications(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 1 | ❌ Missing |
|
||||
| `getNotificationStatus()` | `getNotificationStatus(): Promise<NotificationStatus>` | `@objc func getNotificationStatus(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 1 | ❌ Missing |
|
||||
| `updateSettings()` | `updateSettings(settings: NotificationSettings): Promise<void>` | `@objc func updateSettings(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 1 | ❌ Missing |
|
||||
| `getBatteryStatus()` | `getBatteryStatus(): Promise<BatteryStatus>` | `@objc func getBatteryStatus(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 2 | ❌ Missing |
|
||||
| `requestBatteryOptimizationExemption()` | `requestBatteryOptimizationExemption(): Promise<void>` | `@objc func requestBatteryOptimizationExemption(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 2 | ❌ Missing |
|
||||
| `setAdaptiveScheduling()` | `setAdaptiveScheduling(options: { enabled: boolean }): Promise<void>` | `@objc func setAdaptiveScheduling(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 2 | ❌ Missing |
|
||||
| `getPowerState()` | `getPowerState(): Promise<PowerState>` | `@objc func getPowerState(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 2 | ❌ Missing |
|
||||
| `maintainRollingWindow()` | `maintainRollingWindow(): Promise<void>` | `@objc func maintainRollingWindow(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 2 | ❌ Missing |
|
||||
| `getRollingWindowStats()` | `getRollingWindowStats(): Promise<{stats: string, ...}>` | `@objc func getRollingWindowStats(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 2 | ❌ Missing |
|
||||
| `getExactAlarmStatus()` | `getExactAlarmStatus(): Promise<{supported: boolean, ...}>` | `@objc func getExactAlarmStatus(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 2 | ❌ Missing |
|
||||
| `requestExactAlarmPermission()` | `requestExactAlarmPermission(): Promise<void>` | `@objc func requestExactAlarmPermission(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 2 | ❌ Missing |
|
||||
| `openExactAlarmSettings()` | `openExactAlarmSettings(): Promise<void>` | `@objc func openExactAlarmSettings(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 2 | ❌ Missing |
|
||||
| `getRebootRecoveryStatus()` | `getRebootRecoveryStatus(): Promise<{inProgress: boolean, ...}>` | `@objc func getRebootRecoveryStatus(_ call: CAPPluginCall)` | `DailyNotificationRebootRecoveryManager.swift` | 2 | ❌ Missing |
|
||||
| `setActiveDidFromHost()` | `setActiveDidFromHost(options: {activeDid: string}): Promise<void>` | `@objc func setActiveDidFromHost(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 3 | ❌ Missing |
|
||||
| `refreshAuthenticationForNewIdentity()` | `refreshAuthenticationForNewIdentity(options: {activeDid: string}): Promise<void>` | `@objc func refreshAuthenticationForNewIdentity(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 3 | ❌ Missing |
|
||||
| `clearCacheForNewIdentity()` | `clearCacheForNewIdentity(): Promise<void>` | `@objc func clearCacheForNewIdentity(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 3 | ❌ Missing |
|
||||
| `updateBackgroundTaskIdentity()` | `updateBackgroundTaskIdentity(options: {activeDid: string}): Promise<void>` | `@objc func updateBackgroundTaskIdentity(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 3 | ❌ Missing |
|
||||
| `testJWTGeneration()` | `testJWTGeneration(options?: {activeDid?: string}): Promise<{...}>` | `@objc func testJWTGeneration(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 3 | ❌ Missing |
|
||||
| `testEndorserAPI()` | `testEndorserAPI(options?: {activeDid?: string, apiServer?: string}): Promise<{...}>` | `@objc func testEndorserAPI(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 3 | ❌ Missing |
|
||||
| `coordinateBackgroundTasks()` | `coordinateBackgroundTasks(): Promise<void>` | `@objc func coordinateBackgroundTasks(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 4 | ❌ Missing |
|
||||
| `handleAppLifecycleEvent()` | `handleAppLifecycleEvent(options: {lifecycleEvent: string}): Promise<void>` | `@objc func handleAppLifecycleEvent(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 4 | ❌ Missing |
|
||||
| `getCoordinationStatus()` | `getCoordinationStatus(): Promise<{...}>` | `@objc func getCoordinationStatus(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | 4 | ❌ Missing |
|
||||
| `scheduleDailyReminder()` | `scheduleDailyReminder(options: ReminderOptions): Promise<void>` | `@objc func scheduleDailyReminder(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | - | ✅ Complete |
|
||||
| `cancelDailyReminder()` | `cancelDailyReminder(options: {reminderId: string}): Promise<void>` | `@objc func cancelDailyReminder(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | - | ✅ Complete |
|
||||
| `getScheduledReminders()` | `getScheduledReminders(): Promise<{reminders: ReminderInfo[]}>` | `@objc func getScheduledReminders(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | - | ✅ Complete |
|
||||
| `updateDailyReminder()` | `updateDailyReminder(options: ReminderOptions): Promise<void>` | `@objc func updateDailyReminder(_ call: CAPPluginCall)` | `DailyNotificationPlugin.swift` | - | ✅ Complete |
|
||||
|
||||
---
|
||||
|
||||
@@ -345,6 +405,9 @@ This directive outlines the plan to upgrade the iOS implementation of the Daily
|
||||
- [ ] `cancelAllNotifications()` - Cancel all notifications
|
||||
- [ ] `getNotificationStatus()` - Status retrieval
|
||||
- [ ] `updateSettings(settings: NotificationSettings)` - Settings update
|
||||
|
||||
### Power Management Methods (Phase 2)
|
||||
|
||||
- [ ] `getBatteryStatus()` - Battery status
|
||||
- [ ] `requestBatteryOptimizationExemption()` - Battery optimization (iOS: Background App Refresh)
|
||||
- [ ] `setAdaptiveScheduling(options: { enabled: boolean })` - Adaptive scheduling
|
||||
@@ -404,6 +467,22 @@ This directive outlines the plan to upgrade the iOS implementation of the Daily
|
||||
- **Simulator Testing:** All features should be testable on iOS Simulator
|
||||
- **Physical Device Testing:** Optional for final validation
|
||||
|
||||
### iOS Simulator vs Real Device Differences
|
||||
|
||||
| Behavior | Simulator | Real Device |
|
||||
|----------|-----------|-------------|
|
||||
| BGTaskScheduler | Runs instantly when forced | Often delayed, may not run at all |
|
||||
| Notifications | Always delivered immediately | Delivery may be delayed or batched |
|
||||
| Battery state | Always "unplugged" simulation | Real battery impacts scheduling |
|
||||
| App kill behavior | More predictable | iOS kills background tasks aggressively |
|
||||
| Background App Refresh | Always enabled | User may disable in Settings |
|
||||
| Low Power Mode | Not available | May delay/disable background tasks |
|
||||
|
||||
**Testing Strategy:**
|
||||
- Develop and test primarily on iOS Simulator
|
||||
- Validate critical paths on physical device before release
|
||||
- Document simulator limitations in test results
|
||||
|
||||
### iOS Notification Limits
|
||||
|
||||
- **Maximum Pending Notifications:** 64 (system limit)
|
||||
@@ -430,9 +509,68 @@ This directive outlines the plan to upgrade the iOS implementation of the Daily
|
||||
- **Background App Refresh:** Required for background fetching
|
||||
- **Strategy:** Request permissions early, provide clear explanations
|
||||
|
||||
### Concurrency & Reentrancy Rules
|
||||
|
||||
**Critical:** All access to shared state must be serialized to prevent race conditions.
|
||||
|
||||
**Implementation Requirements:**
|
||||
|
||||
1. **Single Actor/Queue for State Access:**
|
||||
- All access to `DailyNotificationDatabase`, `DailyNotificationStorage`, `DailyNotificationRollingWindow`, and `DailyNotificationTTLEnforcer` **must go through** a single `actor` (e.g., `DailyNotificationStateActor`) or a dedicated serial `DispatchQueue`
|
||||
- No direct CoreData access from CAP bridge methods; they must delegate into the actor/queue
|
||||
- Background tasks and plugin method calls must never touch the DB concurrently outside this actor/queue
|
||||
|
||||
2. **Actor Pattern (Recommended):**
|
||||
```swift
|
||||
actor DailyNotificationStateActor {
|
||||
private let database: DailyNotificationDatabase
|
||||
// All DB operations here
|
||||
}
|
||||
```
|
||||
|
||||
3. **Serial Queue Pattern (Alternative):**
|
||||
```swift
|
||||
private let stateQueue = DispatchQueue(label: "com.timesafari.dailynotification.state", attributes: .serial)
|
||||
```
|
||||
|
||||
4. **Enforcement:**
|
||||
- All plugin methods must call through actor/queue
|
||||
- All background task handlers must call through actor/queue
|
||||
- No direct property access to shared state from multiple threads
|
||||
|
||||
### Error Code Matching with Android
|
||||
|
||||
**Requirement:** iOS must return the same error codes and JSON structure as Android.
|
||||
|
||||
**Authoritative Source:** The **authoritative list of error codes** is defined in Android's `DailyNotificationErrorHandler` (or equivalent error handling class). iOS must mirror that list exactly, including semantics.
|
||||
|
||||
**TODO:** Extract full error code table from Android implementation (`src/android/DailyNotificationErrorHandler.java` or equivalent) and paste here as a normative reference.
|
||||
|
||||
**Note:** This TODO is **blocking for Phase 1**: iOS error handling must not be considered complete until the table is extracted and mirrored. Phase 1 implementation should not proceed without verifying error code parity.
|
||||
|
||||
**Error Response Format:**
|
||||
```json
|
||||
{
|
||||
"error": "error_code",
|
||||
"message": "Human-readable error message"
|
||||
}
|
||||
```
|
||||
|
||||
**Common Error Codes (examples - verify against Android source):**
|
||||
- `notifications_denied` - Notification permissions not granted
|
||||
- `invalid_time_format` - Time parameter format invalid
|
||||
- `scheduling_failed` - Failed to schedule notification
|
||||
- `background_refresh_disabled` - Background App Refresh disabled
|
||||
- `task_scheduling_failed` - BGTaskScheduler submission failed
|
||||
|
||||
**Implementation:**
|
||||
- Use same error keys as Android implementation (from authoritative source)
|
||||
- Use same JSON shape for all error responses
|
||||
- Log using same categories as Android (`DNP-PLUGIN`, `DNP-SCHEDULER`, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
## Validation & QA Plan
|
||||
|
||||
### Unit Tests
|
||||
|
||||
@@ -453,7 +591,8 @@ This directive outlines the plan to upgrade the iOS implementation of the Daily
|
||||
|
||||
### Manual Testing
|
||||
|
||||
- [ ] Test on physical iOS devices
|
||||
- [ ] Test on iOS Simulator (primary)
|
||||
- [ ] Test on physical iOS devices (validation)
|
||||
- [ ] Test Background App Refresh settings
|
||||
- [ ] Test notification permissions
|
||||
- [ ] Test battery optimization scenarios
|
||||
@@ -461,431 +600,6 @@ This directive outlines the plan to upgrade the iOS implementation of the Daily
|
||||
|
||||
---
|
||||
|
||||
## iOS Test App Requirements
|
||||
|
||||
### UI Parity with Android
|
||||
|
||||
**Objective:** Create iOS test app with identical UI/UX to Android test app, using iOS plugin implementation
|
||||
|
||||
**Reference App:** `test-apps/android-test-app/` (Standalone Android with HTML/JS UI)
|
||||
|
||||
**Requirements:**
|
||||
1. **Same UI as Android Test App**
|
||||
- Reuse exact HTML/JavaScript from `android-test-app/app/src/main/assets/public/index.html`
|
||||
- Same button layout and functionality
|
||||
- Same status display area
|
||||
- Same visual design and styling
|
||||
- Platform detection to use iOS plugin methods instead of Android
|
||||
|
||||
2. **Platform Detection**
|
||||
- Detect iOS platform and use iOS plugin methods
|
||||
- Show iOS-specific status indicators
|
||||
- Display iOS-specific permission states
|
||||
- Adapt Android-specific methods to iOS equivalents (e.g., `openExactAlarmSettings` → `openNotificationSettings`)
|
||||
|
||||
3. **iOS Plugin Integration**
|
||||
- Use iOS `DailyNotificationPlugin` instead of Android version
|
||||
- All method calls route to iOS native implementation
|
||||
- Error handling adapted for iOS-specific errors
|
||||
|
||||
**File Structure:**
|
||||
```
|
||||
test-apps/ios-test-app/
|
||||
├── App/
|
||||
│ ├── AppDelegate.swift # App delegate with plugin setup
|
||||
│ ├── Info.plist # iOS permissions and config
|
||||
│ ├── SceneDelegate.swift # Scene management (if needed)
|
||||
│ └── Main.storyboard # Main storyboard (if needed)
|
||||
├── App.xcodeproj/ # Xcode project
|
||||
├── App.xcworkspace/ # Xcode workspace (if using CocoaPods)
|
||||
├── Podfile # CocoaPods dependencies
|
||||
└── www/ # Web assets (HTML/JS/CSS)
|
||||
├── index.html # Same UI as android-test-app
|
||||
├── capacitor.config.json # Capacitor config
|
||||
└── capacitor.plugins.json # Plugin registration
|
||||
```
|
||||
|
||||
### iOS Permissions and Requirements
|
||||
|
||||
**Required Permissions (Info.plist):**
|
||||
|
||||
1. **Notification Permissions**
|
||||
```xml
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>remote-notification</string>
|
||||
<string>fetch</string>
|
||||
<string>processing</string>
|
||||
</array>
|
||||
```
|
||||
|
||||
2. **Background Task Identifiers**
|
||||
```xml
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>com.timesafari.dailynotification.fetch</string>
|
||||
<string>com.timesafari.dailynotification.notify</string>
|
||||
</array>
|
||||
```
|
||||
|
||||
3. **Usage Descriptions**
|
||||
```xml
|
||||
<key>NSUserNotificationsUsageDescription</key>
|
||||
<string>TimeSafari needs notification permissions to deliver daily updates</string>
|
||||
```
|
||||
|
||||
**Runtime Permission Handling:**
|
||||
|
||||
1. **Notification Permissions**
|
||||
- Request via `UNUserNotificationCenter.requestAuthorization()`
|
||||
- Check status via `UNUserNotificationCenter.getNotificationSettings()`
|
||||
- Display permission status in test app UI
|
||||
- Provide "Open Settings" button if denied
|
||||
|
||||
2. **Background App Refresh**
|
||||
- Check status via `UIApplication.shared.backgroundRefreshStatus`
|
||||
- Display status in test app UI
|
||||
- Provide guidance for enabling in Settings
|
||||
|
||||
3. **Permission Status Display**
|
||||
- Show notification permission state (authorized/denied/not determined)
|
||||
- Show background refresh state (available/restricted/denied)
|
||||
- Show battery optimization status (iOS equivalent)
|
||||
- Provide actionable buttons to request/enable permissions
|
||||
|
||||
**iOS-Specific Requirements:**
|
||||
|
||||
1. **Background Task Registration**
|
||||
- Register BGTaskScheduler tasks in `AppDelegate.application(_:didFinishLaunchingWithOptions:)`
|
||||
- Register handlers before app finishes launching
|
||||
- Handle task expiration gracefully
|
||||
|
||||
2. **Notification Categories**
|
||||
- Define notification categories for actions
|
||||
- Register categories with UNUserNotificationCenter
|
||||
- Handle notification actions in delegate
|
||||
|
||||
3. **App Lifecycle Integration**
|
||||
- Handle app background/foreground events
|
||||
- Reschedule notifications on app launch
|
||||
- Sync state on app resume
|
||||
|
||||
### Build Options
|
||||
|
||||
**Objective:** Support both Xcode GUI and command-line builds with straightforward setup
|
||||
|
||||
#### Xcode Build (GUI)
|
||||
|
||||
**Setup:**
|
||||
1. Open `test-apps/ios-test-app/App.xcworkspace` (if using CocoaPods) or `App.xcodeproj` in Xcode
|
||||
2. Select target device (simulator or physical device)
|
||||
3. Build and run via Xcode interface
|
||||
|
||||
**Xcode Configuration:**
|
||||
- **Scheme:** ios-test-app (or similar)
|
||||
- **Configuration:** Debug (development) / Release (production)
|
||||
- **Signing:** Automatic signing with development team
|
||||
- **Capabilities:**
|
||||
- Push Notifications
|
||||
- Background Modes (Remote notifications, Background fetch, Background processing)
|
||||
|
||||
**Xcode Build Steps:**
|
||||
1. Clean build folder (Cmd+Shift+K)
|
||||
2. Build project (Cmd+B)
|
||||
3. Run on device/simulator (Cmd+R)
|
||||
4. Attach debugger for debugging
|
||||
|
||||
#### Console Build (Command Line)
|
||||
|
||||
**Objective:** Enable straightforward command-line builds matching Android test app pattern
|
||||
|
||||
**Build Script Pattern:**
|
||||
- Follow pattern from `scripts/build-native.sh`
|
||||
- Create `scripts/build-ios-test-app.sh` for iOS test app
|
||||
- Support both simulator and device builds
|
||||
- Include dependency installation (CocoaPods)
|
||||
- Include code signing configuration
|
||||
|
||||
**Build Commands (via Script):**
|
||||
|
||||
1. **Build iOS Test App (Debug - Simulator)**
|
||||
```bash
|
||||
./scripts/build-ios-test-app.sh --simulator
|
||||
```
|
||||
|
||||
2. **Build iOS Test App (Debug - Device)**
|
||||
```bash
|
||||
./scripts/build-ios-test-app.sh --device
|
||||
```
|
||||
|
||||
3. **Build iOS Test App (Release)**
|
||||
```bash
|
||||
./scripts/build-ios-test-app.sh --release
|
||||
```
|
||||
|
||||
**Direct xcodebuild Commands (if needed):**
|
||||
|
||||
1. **Install Dependencies**
|
||||
```bash
|
||||
cd test-apps/ios-test-app
|
||||
pod install # If using CocoaPods
|
||||
```
|
||||
|
||||
2. **Build iOS App (Debug - Simulator)**
|
||||
```bash
|
||||
xcodebuild -workspace App.xcworkspace \
|
||||
-scheme ios-test-app \
|
||||
-configuration Debug \
|
||||
-sdk iphonesimulator \
|
||||
-destination 'platform=iOS Simulator,name=iPhone 15' \
|
||||
build
|
||||
```
|
||||
|
||||
3. **Build iOS App (Debug - Device)**
|
||||
```bash
|
||||
xcodebuild -workspace App.xcworkspace \
|
||||
-scheme ios-test-app \
|
||||
-configuration Debug \
|
||||
-sdk iphoneos \
|
||||
-destination 'generic/platform=iOS' \
|
||||
build
|
||||
```
|
||||
|
||||
4. **Build iOS App (Release)**
|
||||
```bash
|
||||
xcodebuild -workspace App.xcworkspace \
|
||||
-scheme ios-test-app \
|
||||
-configuration Release \
|
||||
-sdk iphoneos \
|
||||
-archivePath build/ios-test-app.xcarchive \
|
||||
archive
|
||||
```
|
||||
|
||||
**Build Script Requirements:**
|
||||
- Check for required tools (xcodebuild, pod if using CocoaPods)
|
||||
- Install dependencies automatically
|
||||
- Support both simulator and device builds
|
||||
- Provide clear error messages
|
||||
- Follow same pattern as `scripts/build-native.sh` (colors, logging, error handling)
|
||||
|
||||
### Debugging Strategy
|
||||
|
||||
**Objective:** Make debugging easily accessible and comprehensive
|
||||
|
||||
#### Console Logging
|
||||
|
||||
**Structured Logging:**
|
||||
1. **Log Levels**
|
||||
- `DEBUG`: Detailed diagnostic information
|
||||
- `INFO`: General informational messages
|
||||
- `WARN`: Warning messages for potential issues
|
||||
- `ERROR`: Error messages for failures
|
||||
|
||||
2. **Log Format**
|
||||
```
|
||||
[DNP-PLUGIN] [LEVEL] [TIMESTAMP] [METHOD] Message
|
||||
```
|
||||
Example:
|
||||
```
|
||||
[DNP-PLUGIN] [INFO] [2025-11-13 10:30:45 UTC] [scheduleDailyNotification] Scheduling notification for 09:00
|
||||
```
|
||||
|
||||
3. **Log Categories**
|
||||
- `DNP-PLUGIN`: Main plugin operations
|
||||
- `DNP-SCHEDULER`: Scheduling operations
|
||||
- `DNP-FETCHER`: Background fetching
|
||||
- `DNP-STORAGE`: Storage operations
|
||||
- `DNP-TTL`: TTL enforcement
|
||||
- `DNP-ROLLING-WINDOW`: Rolling window maintenance
|
||||
|
||||
**Logging Implementation:**
|
||||
- Use `os_log` for system-level logging (visible in Console.app)
|
||||
- Use `print()` for Xcode console output
|
||||
- Include file/line information in debug builds
|
||||
- Support log level filtering
|
||||
|
||||
#### Xcode Debugging
|
||||
|
||||
**Breakpoints:**
|
||||
1. **Strategic Breakpoints**
|
||||
- Plugin method entry points
|
||||
- Background task handlers
|
||||
- Notification scheduling logic
|
||||
- Error handling paths
|
||||
|
||||
2. **Conditional Breakpoints**
|
||||
- Break on specific notification IDs
|
||||
- Break on error conditions
|
||||
- Break on specific activeDid values
|
||||
|
||||
3. **Logging Breakpoints**
|
||||
- Log method entry/exit without stopping
|
||||
- Log variable values
|
||||
- Log call stack
|
||||
|
||||
**Debugging Tools:**
|
||||
1. **LLDB Commands**
|
||||
- Inspect Swift objects
|
||||
- Print variable values
|
||||
- Execute Swift expressions
|
||||
- View call stack
|
||||
|
||||
2. **View Hierarchy Debugger**
|
||||
- Inspect UI components
|
||||
- Debug layout issues
|
||||
- Verify UI state
|
||||
|
||||
3. **Network Debugging**
|
||||
- Monitor API calls
|
||||
- Inspect request/response
|
||||
- Debug authentication issues
|
||||
|
||||
#### Test App Debugging UI
|
||||
|
||||
**Debug Panel in Test App:**
|
||||
1. **Log Viewer**
|
||||
- Real-time log display
|
||||
- Filter by log level
|
||||
- Filter by category
|
||||
- Search functionality
|
||||
- Export logs to file
|
||||
|
||||
2. **Status Dashboard**
|
||||
- Plugin initialization status
|
||||
- Permission status
|
||||
- Background task status
|
||||
- Notification schedule status
|
||||
- Storage status
|
||||
|
||||
3. **Diagnostic Tools**
|
||||
- Test individual plugin methods
|
||||
- View stored data (UserDefaults, CoreData)
|
||||
- Trigger manual background tasks
|
||||
- Force notification delivery
|
||||
- Clear caches
|
||||
|
||||
4. **Error Display**
|
||||
- Show recent errors
|
||||
- Error details and stack traces
|
||||
- Error reporting functionality
|
||||
|
||||
**Debug View Implementation:**
|
||||
```vue
|
||||
<!-- DebugView.vue -->
|
||||
<template>
|
||||
<div class="debug-view">
|
||||
<h2>🔍 Debug Tools</h2>
|
||||
|
||||
<!-- Log Viewer -->
|
||||
<LogViewer :logs="logs" />
|
||||
|
||||
<!-- Status Dashboard -->
|
||||
<StatusDashboard :status="pluginStatus" />
|
||||
|
||||
<!-- Diagnostic Tools -->
|
||||
<DiagnosticTools @test-method="testMethod" />
|
||||
|
||||
<!-- Error Display -->
|
||||
<ErrorDisplay :errors="errors" />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### Console.app Integration
|
||||
|
||||
**System Logs:**
|
||||
- Use `os_log` for system-level logging
|
||||
- View logs in Console.app on macOS
|
||||
- Filter by subsystem: `com.timesafari.dailynotification`
|
||||
- Export logs for analysis
|
||||
|
||||
**Log Export:**
|
||||
- Export logs from test app UI
|
||||
- Export via Xcode Organizer
|
||||
- Export via Console.app
|
||||
- Include timestamps and log levels
|
||||
|
||||
#### Background Task Debugging
|
||||
|
||||
**BGTaskScheduler Debugging:**
|
||||
1. **Task Registration Verification**
|
||||
- Log task registration in AppDelegate
|
||||
- Verify task identifiers match Info.plist
|
||||
- Check task handler registration
|
||||
|
||||
2. **Task Execution Monitoring**
|
||||
- Log task start/completion
|
||||
- Log task expiration
|
||||
- Monitor task execution time
|
||||
- Track task success/failure
|
||||
|
||||
3. **Task Scheduling Debugging**
|
||||
- Log scheduled task times
|
||||
- Verify earliestBeginDate
|
||||
- Check task submission success
|
||||
- Monitor task cancellation
|
||||
|
||||
**Debug Commands:**
|
||||
```swift
|
||||
// In test app or debug build
|
||||
func debugBackgroundTasks() {
|
||||
// List registered tasks
|
||||
// Show scheduled tasks
|
||||
// Trigger test tasks
|
||||
// View task history
|
||||
}
|
||||
```
|
||||
|
||||
#### Notification Debugging
|
||||
|
||||
**Notification Delivery Debugging:**
|
||||
1. **Scheduled Notifications**
|
||||
- List all pending notifications
|
||||
- Show notification content
|
||||
- Display trigger times
|
||||
- Verify notification limits
|
||||
|
||||
2. **Notification Delivery**
|
||||
- Log notification delivery
|
||||
- Track delivery success/failure
|
||||
- Monitor notification actions
|
||||
- Debug notification display
|
||||
|
||||
3. **Permission Debugging**
|
||||
- Check permission status
|
||||
- Log permission requests
|
||||
- Track permission changes
|
||||
- Debug permission denials
|
||||
|
||||
**Debug Methods:**
|
||||
```swift
|
||||
// Debug notification state
|
||||
func debugNotifications() {
|
||||
// Get pending notifications
|
||||
// Get delivered notifications
|
||||
// Check notification settings
|
||||
// Verify notification categories
|
||||
}
|
||||
```
|
||||
|
||||
### Test App Implementation Checklist
|
||||
|
||||
- [ ] Create `ios-test-app` directory structure (equivalent to `android-test-app`)
|
||||
- [ ] Copy HTML/JS UI from `android-test-app/app/src/main/assets/public/index.html`
|
||||
- [ ] Adapt JavaScript to use iOS plugin methods
|
||||
- [ ] Configure Info.plist with required permissions
|
||||
- [ ] Implement AppDelegate with plugin setup
|
||||
- [ ] Set up Xcode project/workspace
|
||||
- [ ] Configure CocoaPods (if needed) or direct dependencies
|
||||
- [ ] Create build script `scripts/build-ios-test-app.sh`
|
||||
- [ ] Test Xcode GUI builds
|
||||
- [ ] Test command-line builds via script
|
||||
- [ ] Implement comprehensive logging
|
||||
- [ ] Add Console.app integration
|
||||
- [ ] Create debugging documentation
|
||||
|
||||
---
|
||||
|
||||
## File Organization
|
||||
|
||||
### New Files to Create
|
||||
@@ -933,9 +647,11 @@ test-apps/ios-test-app/ # New iOS test app (equivalent to an
|
||||
```
|
||||
scripts/
|
||||
└── build-ios-test-app.sh # iOS test app build script (new)
|
||||
# Location: Root-level script (scripts/build-ios-test-app.sh)
|
||||
# Pattern: Similar to scripts/build-native.sh
|
||||
# Features:
|
||||
# - Check environment (xcodebuild, pod)
|
||||
# - cd into test-apps/ios-test-app internally
|
||||
# - Install dependencies (pod install)
|
||||
# - Build for simulator or device
|
||||
# - Clear error messages and logging
|
||||
@@ -1124,6 +840,7 @@ scripts/
|
||||
|
||||
- `doc/implementation-roadmap.md` - Implementation roadmap
|
||||
- `doc/INTEGRATION_CHECKLIST.md` - Integration checklist
|
||||
- `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md` - iOS test app detailed requirements (must be created in Phase 1)
|
||||
- `README.md` - Project documentation
|
||||
|
||||
---
|
||||
@@ -1188,6 +905,120 @@ scripts/
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## Validation Matrix
|
||||
|
||||
**Cross-platform feature validation checklist**
|
||||
|
||||
| Feature | Android Behavior | iOS Equivalent | Verified By | Phase |
|
||||
|---------|-----------------|----------------|-------------|-------|
|
||||
| Daily notification | Exact ±0s | ±180s tolerance¹ | Test case: verify **observed** delivery within 3 min window | 1 |
|
||||
| Daily prefetch | Worker at exact time | BGTask within 15 min window | Logs + UI: check fetch timestamp | 1 |
|
||||
| Rolling window | 2 days ahead | iOS 64 limit enforced | Stats call: verify pending count ≤ 64 | 2 |
|
||||
| TTL enforcement | Discard stale at fire | Same: discard stale at fire | Deliver-time check: verify TTL validation | 2 |
|
||||
| Reboot recovery | BOOT_COMPLETED | Uptime comparison | App launch: verify reschedule after reboot | 2 |
|
||||
| JWT authentication | ES256K signing | Same algorithm | Test method: verify token generation | 3 |
|
||||
| ETag caching | Conditional requests | Same: If-None-Match headers | Network logs: verify 304 responses | 3 |
|
||||
| Background coordination | WorkManager sync | BGTaskScheduler sync | Lifecycle events: verify coordination | 4 |
|
||||
|
||||
¹ **Note:** If drift exceeds 180s, log `[DNP-SCHEDULER] notification drift > 180s` and capture in diagnostics; retry logic is not required for v1.
|
||||
|
||||
---
|
||||
|
||||
## Glossary
|
||||
|
||||
**ETag:** HTTP entity tag used for conditional requests. Allows server to return 304 Not Modified if content unchanged.
|
||||
|
||||
**Rolling Window:** Strategy of scheduling notifications for today and tomorrow to ensure delivery even if system delays occur.
|
||||
|
||||
**Prefetch:** Background task that fetches notification content before the notification is scheduled to fire.
|
||||
|
||||
**ActiveDID:** Decentralized identifier (DID) representing the currently active user identity in TimeSafari.
|
||||
|
||||
**Exact Alarm:** Android feature allowing precise scheduling at exact time. iOS equivalent uses calendar triggers with tolerance.
|
||||
|
||||
**TTL (Time To Live):** Maximum age of cached content. Content older than TTL is considered stale and discarded.
|
||||
|
||||
**BGTaskScheduler:** iOS framework for scheduling background tasks (fetch, processing) that run when system conditions allow.
|
||||
|
||||
**UNUserNotificationCenter:** iOS framework for scheduling and delivering local notifications to users.
|
||||
|
||||
---
|
||||
|
||||
## Developer Onboarding
|
||||
|
||||
### Required Environment
|
||||
|
||||
- **Xcode Version:** 15.0 or later (for iOS 17+ features)
|
||||
- **macOS Version:** 13.0 (Ventura) or later
|
||||
- **Swift Version:** 5.9 or later
|
||||
- **iOS Deployment Target:** iOS 15.0 or later
|
||||
|
||||
### Running the Plugin from Test App
|
||||
|
||||
1. **Build Test App:**
|
||||
```bash
|
||||
# From repo root
|
||||
./scripts/build-ios-test-app.sh --simulator
|
||||
```
|
||||
Note: The build script handles `cd` into `test-apps/ios-test-app` internally.
|
||||
|
||||
2. **Open in Xcode:**
|
||||
```bash
|
||||
cd test-apps/ios-test-app
|
||||
open App.xcworkspace # or App.xcodeproj
|
||||
```
|
||||
|
||||
3. **Run on Simulator:**
|
||||
- Select target device (iPhone 15, etc.)
|
||||
- Press Cmd+R to build and run
|
||||
|
||||
### Common Failure Modes
|
||||
|
||||
1. **BGTaskScheduler Not Running:**
|
||||
- Check Info.plist has `BGTaskSchedulerPermittedIdentifiers`
|
||||
- Verify task registered in AppDelegate before app finishes launching
|
||||
- **Simulator-only debugging trick:** Use LLDB command to manually trigger: `e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]`
|
||||
- Note: This is for simulator testing only, not available in production
|
||||
|
||||
2. **Notifications Not Delivering:**
|
||||
- Check notification permissions: `UNUserNotificationCenter.current().getNotificationSettings()`
|
||||
- Verify notification scheduled: `UNUserNotificationCenter.current().getPendingNotificationRequests()`
|
||||
- Check notification category registered
|
||||
|
||||
3. **Build Failures:**
|
||||
- Ensure CocoaPods installed: `pod install`
|
||||
- Check Capacitor plugin path in `capacitor.plugins.json`
|
||||
- Verify Xcode scheme matches workspace
|
||||
|
||||
4. **Background Tasks Expiring:**
|
||||
- BGTaskScheduler tasks have ~30 second execution window
|
||||
- Must call `task.setTaskCompleted(success:)` before expiration
|
||||
- Schedule next task immediately after completion
|
||||
|
||||
---
|
||||
|
||||
## iOS Test App Requirements
|
||||
|
||||
**Note:** Detailed test app requirements have been moved to a separate document for clarity.
|
||||
|
||||
**Reference:** See `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md` for:
|
||||
- UI parity requirements
|
||||
- iOS permissions configuration
|
||||
- Build options (Xcode GUI and command-line)
|
||||
- Debugging strategy
|
||||
- Test app implementation checklist
|
||||
|
||||
**Important:** If `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md` does not yet exist, it **MUST be created as part of Phase 1** before implementation starts.
|
||||
|
||||
**Quick Reference:**
|
||||
- Test app location: `test-apps/ios-test-app/`
|
||||
- Build script: `scripts/build-ios-test-app.sh` (root-level)
|
||||
- Same UI as `android-test-app` (HTML/JS)
|
||||
|
||||
---
|
||||
|
||||
**Status:** 🎯 **READY FOR IMPLEMENTATION**
|
||||
**Next Steps:** Begin Phase 1 implementation after directive approval
|
||||
|
||||
|
||||
Reference in New Issue
Block a user