Implement checkPermissionStatus() and requestNotificationPermissions() methods for iOS plugin, matching Android functionality. Fix compilation errors across plugin files and add comprehensive build/test infrastructure. Key Changes: - Add checkPermissionStatus() and requestNotificationPermissions() methods - Fix 13+ categories of Swift compilation errors (type conversions, logger API, access control, async/await, etc.) - Create DailyNotificationScheduler, DailyNotificationStorage, DailyNotificationStateActor, and DailyNotificationErrorCodes components - Fix CoreData initialization to handle missing model gracefully for Phase 1 - Add iOS test app build script with simulator auto-detection - Update directive with lessons learned from build and permission work Build Status: ✅ BUILD SUCCEEDED Test App: ✅ Ready for iOS Simulator testing Files Modified: - doc/directives/0003-iOS-Android-Parity-Directive.md (lessons learned) - ios/Plugin/DailyNotificationPlugin.swift (Phase 1 methods) - ios/Plugin/DailyNotificationModel.swift (CoreData fix) - 11+ other plugin files (compilation fixes) Files Added: - ios/Plugin/DailyNotificationScheduler.swift - ios/Plugin/DailyNotificationStorage.swift - ios/Plugin/DailyNotificationStateActor.swift - ios/Plugin/DailyNotificationErrorCodes.swift - scripts/build-ios-test-app.sh - scripts/setup-ios-test-app.sh - test-apps/ios-test-app/ (full test app) - Multiple Phase 1 documentation files
14 KiB
iOS Phase 1 Testing Guide
Status: ✅ READY FOR TESTING
Phase: Phase 1 - Core Infrastructure Parity
Target: iOS Simulator (primary) or Physical Device
Quick Start Testing
Prerequisites
- Xcode Version: 15.0 or later
- macOS Version: 13.0 (Ventura) or later
- iOS Deployment Target: iOS 15.0 or later
- Test App:
test-apps/ios-test-app/(to be created)
Testing Environment Setup
-
Build Test App:
# From repo root ./scripts/build-ios-test-app.sh --simulatorNote: If build script doesn't exist yet, see "Manual Build Steps" below.
-
Open in Xcode:
cd test-apps/ios-test-app open App.xcworkspace # or App.xcodeproj -
Run on Simulator:
- Select target device (iPhone 15, iPhone 15 Pro, etc.)
- Press Cmd+R to build and run
- Or use Xcode menu: Product → Run
Phase 1 Test Cases
Test Case 1: Plugin Initialization
Objective: Verify plugin loads and initializes correctly
Steps:
- Launch test app on iOS Simulator
- Check Console.app logs for:
DNP-PLUGIN: Daily Notification Plugin loaded on iOS - Verify no initialization errors
Expected Results:
- Plugin loads without errors
- Storage and scheduler components initialized
- State actor created (iOS 13+)
Logs to Check:
DNP-PLUGIN: Daily Notification Plugin loaded on iOS
DailyNotificationStorage: Database opened successfully at [path]
DailyNotificationScheduler: Notification category setup complete
Test Case 2: Configure Method
Objective: Test plugin configuration
JavaScript Test Code:
import { DailyNotification } from '@capacitor-community/daily-notification';
// Test configure
await DailyNotification.configure({
options: {
storage: 'tiered',
ttlSeconds: 3600,
prefetchLeadMinutes: 5,
maxNotificationsPerDay: 1,
retentionDays: 7
}
});
Steps:
- Call
configure()with options - Check Console.app for:
DNP-PLUGIN: Plugin configuration completed successfully - Verify settings stored in UserDefaults
Expected Results:
- Configuration succeeds without errors
- Settings stored correctly
- Database path set correctly
Verification:
// In Xcode debugger or Console.app
po UserDefaults.standard.dictionary(forKey: "DailyNotificationPrefs")
Test Case 3: Schedule Daily Notification
Objective: Test main scheduling method with prefetch
JavaScript Test Code:
// Schedule notification for 5 minutes from now
const now = new Date();
const scheduleTime = new Date(now.getTime() + 5 * 60 * 1000);
const hour = scheduleTime.getHours();
const minute = scheduleTime.getMinutes();
const timeString = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
await DailyNotification.scheduleDailyNotification({
options: {
time: timeString,
title: "Test Notification",
body: "This is a Phase 1 test notification",
sound: true,
url: null
}
});
Steps:
- Schedule notification 5 minutes from now
- Verify prefetch scheduled 5 minutes before notification time
- Check Console.app logs
- Wait for notification to appear
Expected Results:
- Notification scheduled successfully
- Prefetch BGTask scheduled 5 minutes before notification
- Notification appears at scheduled time (±180s tolerance)
Logs to Check:
DNP-PLUGIN: Scheduling daily notification
DNP-PLUGIN: Daily notification scheduled successfully
DNP-FETCH-SCHEDULE: Background fetch scheduled for [date]
DailyNotificationScheduler: Notification scheduled successfully for [date]
Verification Commands:
# Check pending notifications (in Xcode debugger)
po UNUserNotificationCenter.current().pendingNotificationRequests()
# Check BGTask scheduling (simulator only)
# Use LLDB command in Xcode debugger:
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
Test Case 4: Get Last Notification
Objective: Test last notification retrieval
JavaScript Test Code:
const lastNotification = await DailyNotification.getLastNotification();
console.log('Last notification:', lastNotification);
Steps:
- Schedule a notification
- Wait for it to fire (or manually trigger)
- Call
getLastNotification() - Verify returned data structure
Expected Results:
- Returns notification object with:
id,title,body,timestamp,url - Returns empty object
{}if no notifications exist - Thread-safe retrieval via state actor
Expected Response:
{
"id": "daily_1234567890",
"title": "Test Notification",
"body": "This is a Phase 1 test notification",
"timestamp": 1234567890000,
"url": null
}
Test Case 5: Cancel All Notifications
Objective: Test cancellation of all scheduled notifications
JavaScript Test Code:
// Schedule multiple notifications first
await DailyNotification.scheduleDailyNotification({...});
await DailyNotification.scheduleDailyNotification({...});
// Then cancel all
await DailyNotification.cancelAllNotifications();
Steps:
- Schedule 2-3 notifications
- Verify they're scheduled:
getNotificationStatus() - Call
cancelAllNotifications() - Verify all cancelled
Expected Results:
- All notifications cancelled
- Storage cleared
- Pending count = 0
Logs to Check:
DNP-PLUGIN: All notifications cancelled successfully
DailyNotificationScheduler: All notifications cancelled
DailyNotificationStorage: All notifications cleared
Test Case 6: Get Notification Status
Objective: Test status retrieval
JavaScript Test Code:
const status = await DailyNotification.getNotificationStatus();
console.log('Status:', status);
Steps:
- Call
getNotificationStatus() - Verify response structure
- Check permission status
- Check pending count
Expected Results:
- Returns complete status object
- Permission status accurate
- Pending count accurate
- Next notification time calculated
Expected Response:
{
"isEnabled": true,
"isScheduled": true,
"lastNotificationTime": 1234567890000,
"nextNotificationTime": 1234567895000,
"pending": 1,
"settings": {
"storageMode": "tiered",
"ttlSeconds": 3600
}
}
Test Case 7: Update Settings
Objective: Test settings update
JavaScript Test Code:
await DailyNotification.updateSettings({
settings: {
sound: false,
priority: "high",
timezone: "America/New_York"
}
});
Steps:
- Call
updateSettings()with new settings - Verify settings stored
- Retrieve settings and verify changes
Expected Results:
- Settings updated successfully
- Changes persisted
- Thread-safe update via state actor
Test Case 8: BGTask Miss Detection
Objective: Test BGTask miss detection and rescheduling
Steps:
- Schedule a notification with prefetch
- Note the BGTask
earliestBeginDatefrom logs - Simulate missing the BGTask window:
- Wait 15+ minutes after
earliestBeginDate - Ensure no successful run recorded
- Wait 15+ minutes after
- Launch app (triggers
checkForMissedBGTask()) - Verify BGTask rescheduled
Expected Results:
- Miss detection triggers on app launch
- BGTask rescheduled for 1 minute from now
- Logs show:
DNP-FETCH: BGTask missed window; rescheduling
Logs to Check:
DNP-FETCH: BGTask missed window; rescheduling
DNP-FETCH: BGTask rescheduled for [date]
Manual Trigger (Simulator Only):
# In Xcode debugger (LLDB)
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
Test Case 9: Permission Auto-Healing
Objective: Test automatic permission request
Steps:
- Reset notification permissions (Settings → [App] → Notifications → Off)
- Call
scheduleDailyNotification() - Verify permission request dialog appears
- Grant permissions
- Verify scheduling succeeds
Expected Results:
- Permission request dialog appears automatically
- Scheduling succeeds after granting
- Error returned if permissions denied
Logs to Check:
DailyNotificationScheduler: Permission request result: true
DailyNotificationScheduler: Scheduling notification: [id]
Test Case 10: Error Handling
Objective: Test error code responses
Test Scenarios:
-
Missing Parameters:
await DailyNotification.scheduleDailyNotification({ options: {} // Missing 'time' parameter });Expected Error:
{ "error": "missing_required_parameter", "message": "Missing required parameter: time" } -
Invalid Time Format:
await DailyNotification.scheduleDailyNotification({ options: { time: "invalid" } });Expected Error:
{ "error": "invalid_time_format", "message": "Invalid time format. Use HH:mm" } -
Notifications Denied:
- Deny notification permissions
- Try to schedule notification
- Verify error code returned
Expected Error:
{
"error": "notifications_denied",
"message": "Notification permissions denied"
}
Manual Build Steps (If Build Script Not Available)
Step 1: Install Dependencies
cd ios
pod install
Step 2: Open in Xcode
open DailyNotificationPlugin.xcworkspace
# or
open DailyNotificationPlugin.xcodeproj
Step 3: Configure Build Settings
- Select project in Xcode
- Go to Signing & Capabilities
- Add Background Modes:
- Background fetch
- Background processing
- Add to Info.plist:
<key>BGTaskSchedulerPermittedIdentifiers</key> <array> <string>com.timesafari.dailynotification.fetch</string> <string>com.timesafari.dailynotification.notify</string> </array>
Step 4: Build and Run
- Select target device (Simulator or Physical Device)
- Press Cmd+R or Product → Run
Debugging Tools
Console.app Logging
View Logs:
- Open Console.app (Applications → Utilities)
- Select your device/simulator
- Filter by:
DNP-orDailyNotification
Key Log Prefixes:
DNP-PLUGIN:- Main plugin operationsDNP-FETCH:- Background fetch operationsDNP-FETCH-SCHEDULE:- BGTask schedulingDailyNotificationStorage:- Storage operationsDailyNotificationScheduler:- Scheduling operations
Xcode Debugger Commands
Check Pending Notifications:
po UNUserNotificationCenter.current().pendingNotificationRequests()
Check Permission Status:
po await UNUserNotificationCenter.current().notificationSettings()
Check BGTask Status (Simulator Only):
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
Check Storage:
po UserDefaults.standard.dictionary(forKey: "DailyNotificationPrefs")
Common Issues & Solutions
Issue 1: BGTaskScheduler Not Running
Symptoms:
- BGTask never executes
- No logs from
handleBackgroundFetch()
Solutions:
- Verify Info.plist has
BGTaskSchedulerPermittedIdentifiers - Check task registered in
setupBackgroundTasks() - Simulator workaround: Use LLDB command to manually trigger (see above)
Issue 2: Notifications Not Delivering
Symptoms:
- Notification scheduled but never appears
- No notification in notification center
Solutions:
- Check permissions:
UNUserNotificationCenter.current().getNotificationSettings() - Verify notification scheduled:
getPendingNotificationRequests() - Check notification category registered
- Verify time hasn't passed (iOS may deliver immediately if time passed)
Issue 3: Build Failures
Symptoms:
- Xcode build errors
- Missing dependencies
Solutions:
- Run
pod installinios/directory - Clean build folder: Product → Clean Build Folder (Cmd+Shift+K)
- Verify Capacitor plugin path in
capacitor.plugins.json - Check Xcode scheme matches workspace
Issue 4: Background Tasks Expiring
Symptoms:
- BGTask starts but expires before completion
- Logs show:
Background fetch task expired
Solutions:
- Ensure
task.setTaskCompleted(success:)called before expiration - Keep processing efficient (< 30 seconds)
- Schedule next task immediately after completion
Testing Checklist
Phase 1 Core Methods
configure()- Configuration succeedsscheduleDailyNotification()- Notification schedules correctlygetLastNotification()- Returns correct notificationcancelAllNotifications()- All notifications cancelledgetNotificationStatus()- Status accurateupdateSettings()- Settings updated correctly
Background Tasks
- BGTask scheduled 5 minutes before notification
- BGTask executes successfully
- BGTask miss detection works
- BGTask rescheduling works
Error Handling
- Missing parameter errors returned
- Invalid time format errors returned
- Permission denied errors returned
- Error codes match Android format
Thread Safety
- No race conditions observed
- State actor used for all storage operations
- Background tasks use state actor
Next Steps After Testing
- Document Issues: Create GitHub issues for any bugs found
- Update Test Cases: Add test cases for edge cases discovered
- Performance Testing: Test with multiple notifications
- Phase 2 Preparation: Begin Phase 2 advanced features
References
- Directive:
doc/directives/0003-iOS-Android-Parity-Directive.md - Phase 1 Summary:
doc/PHASE1_COMPLETION_SUMMARY.md - Android Testing:
docs/notification-testing-procedures.md - Comprehensive Testing:
docs/comprehensive-testing-guide-v2.md
Status: ✅ READY FOR TESTING
Last Updated: 2025-01-XX