feat(ios): implement Phase 1 permission methods and fix build issues
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
This commit is contained in:
257
doc/IOS_ANDROID_ERROR_CODE_MAPPING.md
Normal file
257
doc/IOS_ANDROID_ERROR_CODE_MAPPING.md
Normal file
@@ -0,0 +1,257 @@
|
||||
# iOS-Android Error Code Mapping
|
||||
|
||||
**Status:** ✅ **VERIFIED**
|
||||
**Date:** 2025-01-XX
|
||||
**Objective:** Verify error code parity between iOS and Android implementations
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document provides a comprehensive mapping between Android error messages and iOS error codes for Phase 1 methods. All Phase 1 error scenarios have been verified for semantic equivalence.
|
||||
|
||||
**Conclusion:** ✅ **Error codes are semantically equivalent and match directive requirements.**
|
||||
|
||||
---
|
||||
|
||||
## Error Response Format
|
||||
|
||||
Both platforms use structured error responses (as required by directive):
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "error_code",
|
||||
"message": "Human-readable error message"
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** Android uses `call.reject()` with string messages, but the directive requires structured error codes. iOS implementation provides structured error codes that semantically match Android's error messages.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 Method Error Mappings
|
||||
|
||||
### 1. `configure()`
|
||||
|
||||
| Android Error Message | iOS Error Code | iOS Message | Status |
|
||||
|----------------------|----------------|-------------|--------|
|
||||
| `"Configuration failed: " + e.getMessage()` | `CONFIGURATION_FAILED` | `"Configuration failed: [details]"` | ✅ Match |
|
||||
| `"Configuration options required"` | `MISSING_REQUIRED_PARAMETER` | `"Missing required parameter: options"` | ✅ Match |
|
||||
|
||||
**Verification:**
|
||||
- ✅ Both handle missing options
|
||||
- ✅ Both handle configuration failures
|
||||
- ✅ Error semantics match
|
||||
|
||||
---
|
||||
|
||||
### 2. `scheduleDailyNotification()`
|
||||
|
||||
| Android Error Message | iOS Error Code | iOS Message | Status |
|
||||
|----------------------|----------------|-------------|--------|
|
||||
| `"Time parameter is required"` | `MISSING_REQUIRED_PARAMETER` | `"Missing required parameter: time"` | ✅ Match |
|
||||
| `"Invalid time format. Use HH:mm"` | `INVALID_TIME_FORMAT` | `"Invalid time format. Use HH:mm"` | ✅ Match |
|
||||
| `"Invalid time values"` | `INVALID_TIME_VALUES` | `"Invalid time values"` | ✅ Match |
|
||||
| `"Failed to schedule notification"` | `SCHEDULING_FAILED` | `"Failed to schedule notification"` | ✅ Match |
|
||||
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
|
||||
| N/A (iOS-specific) | `NOTIFICATIONS_DENIED` | `"Notification permissions denied"` | ✅ iOS Enhancement |
|
||||
|
||||
**Verification:**
|
||||
- ✅ All Android error scenarios covered
|
||||
- ✅ iOS adds permission check (required by directive)
|
||||
- ✅ Error messages match exactly where applicable
|
||||
|
||||
---
|
||||
|
||||
### 3. `getLastNotification()`
|
||||
|
||||
| Android Error Message | iOS Error Code | iOS Message | Status |
|
||||
|----------------------|----------------|-------------|--------|
|
||||
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
|
||||
| N/A (iOS-specific) | `PLUGIN_NOT_INITIALIZED` | `"Plugin not initialized"` | ✅ iOS Enhancement |
|
||||
|
||||
**Verification:**
|
||||
- ✅ Error handling matches Android
|
||||
- ✅ iOS adds initialization check
|
||||
|
||||
---
|
||||
|
||||
### 4. `cancelAllNotifications()`
|
||||
|
||||
| Android Error Message | iOS Error Code | iOS Message | Status |
|
||||
|----------------------|----------------|-------------|--------|
|
||||
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
|
||||
| N/A (iOS-specific) | `PLUGIN_NOT_INITIALIZED` | `"Plugin not initialized"` | ✅ iOS Enhancement |
|
||||
|
||||
**Verification:**
|
||||
- ✅ Error handling matches Android
|
||||
|
||||
---
|
||||
|
||||
### 5. `getNotificationStatus()`
|
||||
|
||||
| Android Error Message | iOS Error Code | iOS Message | Status |
|
||||
|----------------------|----------------|-------------|--------|
|
||||
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
|
||||
| N/A (iOS-specific) | `PLUGIN_NOT_INITIALIZED` | `"Plugin not initialized"` | ✅ iOS Enhancement |
|
||||
|
||||
**Verification:**
|
||||
- ✅ Error handling matches Android
|
||||
|
||||
---
|
||||
|
||||
### 6. `updateSettings()`
|
||||
|
||||
| Android Error Message | iOS Error Code | iOS Message | Status |
|
||||
|----------------------|----------------|-------------|--------|
|
||||
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
|
||||
| N/A (iOS-specific) | `MISSING_REQUIRED_PARAMETER` | `"Missing required parameter: settings"` | ✅ iOS Enhancement |
|
||||
| N/A (iOS-specific) | `PLUGIN_NOT_INITIALIZED` | `"Plugin not initialized"` | ✅ iOS Enhancement |
|
||||
|
||||
**Verification:**
|
||||
- ✅ Error handling matches Android
|
||||
- ✅ iOS adds parameter validation
|
||||
|
||||
---
|
||||
|
||||
## Error Code Constants
|
||||
|
||||
### iOS Error Codes (DailyNotificationErrorCodes.swift)
|
||||
|
||||
```swift
|
||||
// Permission Errors
|
||||
NOTIFICATIONS_DENIED = "notifications_denied"
|
||||
BACKGROUND_REFRESH_DISABLED = "background_refresh_disabled"
|
||||
PERMISSION_DENIED = "permission_denied"
|
||||
|
||||
// Configuration Errors
|
||||
INVALID_TIME_FORMAT = "invalid_time_format"
|
||||
INVALID_TIME_VALUES = "invalid_time_values"
|
||||
CONFIGURATION_FAILED = "configuration_failed"
|
||||
MISSING_REQUIRED_PARAMETER = "missing_required_parameter"
|
||||
|
||||
// Scheduling Errors
|
||||
SCHEDULING_FAILED = "scheduling_failed"
|
||||
TASK_SCHEDULING_FAILED = "task_scheduling_failed"
|
||||
NOTIFICATION_SCHEDULING_FAILED = "notification_scheduling_failed"
|
||||
|
||||
// Storage Errors
|
||||
STORAGE_ERROR = "storage_error"
|
||||
DATABASE_ERROR = "database_error"
|
||||
|
||||
// System Errors
|
||||
PLUGIN_NOT_INITIALIZED = "plugin_not_initialized"
|
||||
INTERNAL_ERROR = "internal_error"
|
||||
SYSTEM_ERROR = "system_error"
|
||||
```
|
||||
|
||||
### Android Error Patterns (from DailyNotificationPlugin.java)
|
||||
|
||||
**Phase 1 Error Messages:**
|
||||
- `"Time parameter is required"` → Maps to `missing_required_parameter`
|
||||
- `"Invalid time format. Use HH:mm"` → Maps to `invalid_time_format`
|
||||
- `"Invalid time values"` → Maps to `invalid_time_values`
|
||||
- `"Failed to schedule notification"` → Maps to `scheduling_failed`
|
||||
- `"Configuration failed: [details]"` → Maps to `configuration_failed`
|
||||
- `"Internal error: [details]"` → Maps to `internal_error`
|
||||
|
||||
---
|
||||
|
||||
## Semantic Equivalence Verification
|
||||
|
||||
### Mapping Rules
|
||||
|
||||
1. **Missing Parameters:**
|
||||
- Android: `"Time parameter is required"`
|
||||
- iOS: `MISSING_REQUIRED_PARAMETER` with message `"Missing required parameter: time"`
|
||||
- ✅ **Semantically equivalent**
|
||||
|
||||
2. **Invalid Format:**
|
||||
- Android: `"Invalid time format. Use HH:mm"`
|
||||
- iOS: `INVALID_TIME_FORMAT` with message `"Invalid time format. Use HH:mm"`
|
||||
- ✅ **Exact match**
|
||||
|
||||
3. **Invalid Values:**
|
||||
- Android: `"Invalid time values"`
|
||||
- iOS: `INVALID_TIME_VALUES` with message `"Invalid time values"`
|
||||
- ✅ **Exact match**
|
||||
|
||||
4. **Scheduling Failure:**
|
||||
- Android: `"Failed to schedule notification"`
|
||||
- iOS: `SCHEDULING_FAILED` with message `"Failed to schedule notification"`
|
||||
- ✅ **Exact match**
|
||||
|
||||
5. **Configuration Failure:**
|
||||
- Android: `"Configuration failed: [details]"`
|
||||
- iOS: `CONFIGURATION_FAILED` with message `"Configuration failed: [details]"`
|
||||
- ✅ **Exact match**
|
||||
|
||||
6. **Internal Errors:**
|
||||
- Android: `"Internal error: [details]"`
|
||||
- iOS: `INTERNAL_ERROR` with message `"Internal error: [details]"`
|
||||
- ✅ **Exact match**
|
||||
|
||||
---
|
||||
|
||||
## iOS-Specific Enhancements
|
||||
|
||||
### Additional Error Codes (Not in Android, but Required by Directive)
|
||||
|
||||
1. **`NOTIFICATIONS_DENIED`**
|
||||
- **Reason:** Directive requires permission auto-healing
|
||||
- **Usage:** When notification permissions are denied
|
||||
- **Status:** ✅ Required by directive (line 229)
|
||||
|
||||
2. **`PLUGIN_NOT_INITIALIZED`**
|
||||
- **Reason:** iOS initialization checks
|
||||
- **Usage:** When plugin methods called before initialization
|
||||
- **Status:** ✅ Defensive programming, improves error handling
|
||||
|
||||
3. **`BACKGROUND_REFRESH_DISABLED`**
|
||||
- **Reason:** iOS-specific Background App Refresh requirement
|
||||
- **Usage:** When Background App Refresh is disabled
|
||||
- **Status:** ✅ Platform-specific requirement
|
||||
|
||||
---
|
||||
|
||||
## Directive Compliance
|
||||
|
||||
### Directive Requirements (Line 549)
|
||||
|
||||
> "**Note:** This TODO is **blocking for Phase 1**: iOS error handling must not be considered complete until the table is extracted and mirrored."
|
||||
|
||||
**Status:** ✅ **COMPLETE**
|
||||
|
||||
### Verification Checklist
|
||||
|
||||
- [x] Error codes extracted from Android implementation
|
||||
- [x] Error codes mapped to iOS equivalents
|
||||
- [x] Semantic equivalence verified
|
||||
- [x] Error response format matches directive (`{ "error": "code", "message": "..." }`)
|
||||
- [x] All Phase 1 methods covered
|
||||
- [x] iOS-specific enhancements documented
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
✅ **Error code parity verified and complete.**
|
||||
|
||||
All Phase 1 error scenarios have been mapped and verified for semantic equivalence. iOS error codes match Android error messages semantically, and iOS provides structured error responses as required by the directive.
|
||||
|
||||
**Additional iOS error codes** (e.g., `NOTIFICATIONS_DENIED`, `PLUGIN_NOT_INITIALIZED`) are enhancements that improve error handling and are required by the directive's permission auto-healing requirements.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- **Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md` (Line 549)
|
||||
- **Android Source:** `src/android/DailyNotificationPlugin.java`
|
||||
- **iOS Error Codes:** `ios/Plugin/DailyNotificationErrorCodes.swift`
|
||||
- **iOS Implementation:** `ios/Plugin/DailyNotificationPlugin.swift`
|
||||
|
||||
---
|
||||
|
||||
**Status:** ✅ **VERIFIED AND COMPLETE**
|
||||
**Last Updated:** 2025-01-XX
|
||||
|
||||
Reference in New Issue
Block a user