Files
crowd-funder-for-time-pwa/doc/daily-notification-plugin-architecture.md
Jose Olarte III 14ffcb5434 feat: integrate daily notification plugin for native iOS/Android
Add native notification support via @timesafari/daily-notification-plugin
while maintaining existing Web Push for web/PWA builds. Platform detection
automatically selects the appropriate notification system at runtime.

Key Changes:
- Created NotificationService abstraction layer with unified API
- Implemented NativeNotificationService for iOS/Android
- Stubbed WebPushNotificationService for future web integration
- Registered DailyNotificationPlugin in Capacitor plugin system

Android Configuration:
- Added notification permissions (POST_NOTIFICATIONS, SCHEDULE_EXACT_ALARM, etc.)
- Registered DailyNotificationReceiver for alarm-based notifications
- Registered BootReceiver to restore schedules after device restart
- Added Room, WorkManager, and Coroutines dependencies
- Registered plugin in MainActivity.java

iOS Configuration:
- Added UIBackgroundModes (fetch, processing) to Info.plist
- Configured BGTaskSchedulerPermittedIdentifiers
- Added NSUserNotificationAlertStyle

Documentation:
- Created comprehensive integration guide
- Added architecture overview with diagrams
- Created implementation checklist
- Documented platform-specific behavior

Manual Steps Required:
- iOS: Enable Background Modes capability in Xcode
- iOS: Run `pod install` to install CapacitorDailyNotification pod
- Run `npx cap sync` to sync native projects

Platform Support:
- iOS: Native UNUserNotificationCenter (requires Xcode setup)
- Android: Native NotificationManager with AlarmManager
- Web/PWA: Existing Web Push (coexists, not yet wired to service)
- Electron: Ready (uses native implementation)

Status: Phase 1 complete - infrastructure ready for UI integration
Next: Update PushNotificationPermission.vue to use NotificationService
2026-01-21 22:22:48 +08:00

313 lines
9.8 KiB
Markdown

# Daily Notification Plugin - Architecture Overview
## System Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ Vue Components │
│ (PushNotificationPermission.vue, AccountViewView.vue, etc.) │
└───────────────────────────┬─────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ NotificationService (Factory) │
│ - Platform detection via Capacitor API │
│ - Singleton pattern │
│ - Returns appropriate implementation │
└───────────────────────────┬─────────────────────────────────────┘
┌───────────┴────────────┐
▼ ▼
┌───────────────────────────┐ ┌────────────────────────────┐
│ NativeNotificationService │ │ WebPushNotificationService │
│ │ │ │
│ iOS/Android │ │ Web/PWA │
│ - UNUserNotificationCenter│ │ - Web Push API │
│ - NotificationManager │ │ - Service Workers │
│ - AlarmManager │ │ - VAPID keys │
│ - Background tasks │ │ - Push server │
└─────────────┬─────────────┘ └────────────┬───────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌──────────────────────────────┐
│ DailyNotificationPlugin│ │ Existing Web Push Logic │
│ (Capacitor Plugin) │ │ (PushNotificationPermission)│
│ │ │ │
│ - Native iOS code │ │ - Service worker │
│ - Native Android code │ │ - VAPID subscription │
│ - SQLite storage │ │ - Push server integration │
└─────────────────────────┘ └──────────────────────────────┘
```
## Platform Decision Flow
```
User Action: Schedule Notification
NotificationService.getInstance()
├──> Check: Capacitor.isNativePlatform()
┌────┴─────┐
│ │
YES NO
│ │
▼ ▼
Native Web/PWA
Service Service
│ │
▼ ▼
Plugin Web Push
```
## Data Flow Example: Scheduling a Notification
### Native Platform (iOS/Android)
```
1. User clicks "Enable Notifications"
2. PushNotificationPermission.vue
└─> NotificationService.getInstance()
└─> Returns NativeNotificationService (detected iOS/Android)
└─> nativeService.requestPermissions()
└─> DailyNotification.requestPermissions() [Capacitor Plugin]
└─> Native code requests OS permissions
└─> Returns: { granted: true/false }
3. User sets time & message
4. nativeService.scheduleDailyNotification({ time: '09:00', ... })
└─> DailyNotification.scheduleDailyReminder({ ... })
└─> Native code:
- Stores in SQLite
- Schedules AlarmManager (Android) or UNNotificationRequest (iOS)
- Returns: success/failure
5. At 9:00 AM:
- Android: AlarmManager triggers → DailyNotificationReceiver
- iOS: UNUserNotificationCenter triggers notification
- Notification appears even if app is closed
```
### Web Platform
```
1. User clicks "Enable Notifications"
2. PushNotificationPermission.vue
└─> NotificationService.getInstance()
└─> Returns WebPushNotificationService (detected web)
└─> webService.requestPermissions()
└─> Notification.requestPermission() [Browser API]
└─> Returns: 'granted'/'denied'/'default'
3. User sets time & message
4. webService.scheduleDailyNotification({ ... })
└─> [TODO] Subscribe to push service with VAPID
└─> Send subscription to server with schedule time
└─> Server sends push at scheduled time
└─> Service worker receives → shows notification
```
## File Organization
```
src/
├── plugins/
│ └── DailyNotificationPlugin.ts [Plugin registration]
├── services/
│ └── notifications/
│ ├── index.ts [Barrel export]
│ ├── NotificationService.ts [Factory + Interface]
│ ├── NativeNotificationService.ts [iOS/Android impl]
│ └── WebPushNotificationService.ts [Web impl stub]
├── components/
│ └── PushNotificationPermission.vue [UI - to be updated]
└── views/
└── AccountViewView.vue [Settings UI]
```
## Key Design Decisions
### 1. **Unified Interface**
- Single `NotificationServiceInterface` for all platforms
- Consistent API regardless of underlying implementation
- Type-safe across TypeScript codebase
### 2. **Runtime Platform Detection**
- No build-time configuration needed
- Same code bundle for all platforms
- Factory pattern selects implementation automatically
### 3. **Coexistence Strategy**
- Web Push and Native run on different platforms
- No conflicts - mutually exclusive at runtime
- Allows gradual migration and testing
### 4. **Singleton Pattern**
- One service instance per app lifecycle
- Efficient resource usage
- Consistent state management
## Permission Flow
### Android
```
App Launch
Check if POST_NOTIFICATIONS granted (API 33+)
├─> YES: Ready to schedule
└─> NO: Request runtime permission
Show system dialog
User grants/denies
Schedule notifications (if granted)
```
### iOS
```
App Launch
Check notification authorization status
├─> authorized: Ready to schedule
├─> notDetermined: Request permission
│ ↓
│ Show system dialog
│ ↓
│ User grants/denies
└─> denied: Guide user to Settings
```
### Web
```
App Load
Check Notification.permission
├─> "granted": Ready to subscribe
├─> "default": Request permission
│ ↓
│ Show browser prompt
│ ↓
│ User grants/denies
└─> "denied": Cannot show notifications
```
## Error Handling Strategy
```typescript
// All methods return promises with success/failure
try {
const granted = await service.requestPermissions();
if (granted) {
const success = await service.scheduleDailyNotification({...});
if (success) {
// Show success message
} else {
// Show scheduling error
}
} else {
// Show permission denied message
}
} catch (error) {
// Log error and show generic error message
logger.error('Notification error:', error);
}
```
## Background Execution
### Native (iOS/Android)
- ✅ Full background support
- ✅ Survives app termination
- ✅ Survives device reboot (with BootReceiver)
- ✅ Exact alarm scheduling
- ✅ Works offline
### Web/PWA
- ⚠️ Limited background support
- ⚠️ Requires active service worker
- ⚠️ Browser/OS dependent
- ❌ Needs network for delivery
- ⚠️ iOS: Only on Home Screen PWAs (16.4+)
## Storage
### Native
```
DailyNotificationPlugin
SQLite Database (Room/Core Data)
Stores:
- Schedule configurations
- Content cache
- Delivery history
- Callback registrations
```
### Web
```
Web Push
IndexedDB (via Dexie)
Stores:
- Settings (notifyingNewActivityTime, etc.)
- Push subscription info
- VAPID keys
```
## Testing Strategy
### Unit Testing
- Mock `Capacitor.isNativePlatform()` to test both paths
- Test factory returns correct implementation
- Test each service implementation independently
### Integration Testing
- Test on actual devices (iOS/Android)
- Test in browsers (Chrome, Safari, Firefox)
- Verify notification delivery
- Test permission flows
### E2E Testing
- Schedule notification → Wait → Verify delivery
- Test app restart scenarios
- Test device reboot scenarios
- Test permission denial recovery
---
**Key Takeaway**: The architecture provides a clean separation between platforms while maintaining a unified API for Vue components. Platform detection happens automatically at runtime, and the appropriate notification system is used transparently.