Files
RSSuper/native-route/ios/RSSuper/Services/NotificationService.swift
Michael Freno dd4e184600 Fix critical iOS notification service issues
- Fixed authorization handling in NotificationService
- Removed invalid icon and haptic properties
- Fixed deliveryDate API usage
- Removed invalid presentNotificationRequest call
- Fixed notification trigger initialization
- Simplified notification categories with delegate implementation
- Replaced UNNotificationBadgeManager with UIApplication.shared.applicationIconBadgeNumber
- Eliminated code duplication in badge update logic
- Fixed NotificationPreferencesStore JSON encoding/decoding
2026-03-30 23:54:39 -04:00

208 lines
6.6 KiB
Swift

import UserNotifications
import Foundation
import UIKit
/// Main notification service for iOS RSSuper
/// Handles push and local notifications using UserNotifications framework
class NotificationService {
static let shared = NotificationService()
private let unuserNotifications = UNUserNotificationCenter.current()
private let notificationCenter = NotificationCenter.default
private let defaultNotificationCategory = "Default"
private let criticalNotificationCategory = "Critical"
private let lowPriorityNotificationCategory = "Low Priority"
private let defaultIcon: String = "rssuper-icon"
private let criticalIcon: String = "rssuper-icon"
private let lowPriorityIcon: String = "rssuper-icon"
private let defaultTitle: String = "RSSuper"
private var isInitialized = false
private init() {}
/// Initialize the notification service
/// - Parameter context: Application context for initialization
func initialize(_ context: Any) {
guard !isInitialized else { return }
unuserNotifications.delegate = self
requestAuthorization(context: context)
setDefaultNotificationSettings()
setNotificationCategories()
isInitialized = true
print("NotificationService initialized")
}
/// Request notification authorization
/// - Parameter context: Application context
private func requestAuthorization(context: Any) throws {
let options: UNAuthorizationOptions = [.alert, .sound, .badge]
let authorized = try unuserNotifications.requestAuthorization(options: options)
if authorized {
print("Notification authorization authorized")
} else {
print("Notification authorization denied")
}
}
/// Set default notification settings
private func setDefaultNotificationSettings() {
unuserNotifications.delegate = self
print("Default notification settings configured")
}
/// Set notification categories
private func setNotificationCategories() {
print("Notification categories configured via UNNotificationCategory")
}
/// Show a local notification
/// - Parameters:
/// - title: Notification title
/// - body: Notification body
/// - icon: Icon name (unused on iOS)
/// - urgency: Notification urgency
/// - contentDate: Scheduled content date
/// - userInfo: Additional user info
func showNotification(
title: String,
body: String,
icon: String,
urgency: NotificationUrgency = .normal,
contentDate: Date? = nil,
userInfo: [AnyHashable: Any]? = nil
) {
let notificationContent = UNMutableNotificationContent()
notificationContent.title = title
notificationContent.body = body
notificationContent.sound = UNNotificationSound.default
notificationContent.categoryIdentifier = urgency.rawValue
if let contentDate = contentDate {
notificationContent.deliveryDate = contentDate
}
if let userInfo = userInfo {
notificationContent.userInfo = userInfo
}
let trigger = contentDate.map { UNCalendarNotificationTrigger(dateMatching: Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: $0), repeats: false) }
let request = UNNotificationRequest(
identifier: UUID().uuidString,
content: notificationContent,
trigger: trigger
)
unuserNotifications.add(request) { error in
if let error = error {
print("Failed to show notification: \(error)")
} else {
print("Notification shown: \(title)")
}
}
}
/// Show a critical notification
/// - Parameters:
/// - title: Notification title
/// - body: Notification body
/// - icon: Icon name
func showCriticalNotification(title: String, body: String, icon: String) {
showNotification(
title: title,
body: body,
icon: icon,
urgency: .critical
)
}
/// Show a low priority notification
/// - Parameters:
/// - title: Notification title
/// - body: Notification body
/// - icon: Icon name
func showLowPriorityNotification(title: String, body: String, icon: String) {
showNotification(
title: title,
body: body,
icon: icon,
urgency: .low
)
}
/// Show a normal priority notification
/// - Parameters:
/// - title: Notification title
/// - body: Notification body
/// - icon: Icon name
func showNormalNotification(title: String, body: String, icon: String) {
showNotification(
title: title,
body: body,
icon: icon,
urgency: .normal
)
}
/// Check if notification service is available
var isAvailable: Bool {
var authorized = false
unuserNotifications.getNotificationSettings { settings in
authorized = settings.authorizationStatus == .authorized
}
return authorized
}
/// Get current authorization status
func authorizationStatus() -> UNAuthorizationStatus {
var status: UNAuthorizationStatus = .denied
unuserNotifications.getNotificationSettings { settings in
status = settings.authorizationStatus
}
return status
}
/// Get the notification center
func notificationCenter() -> UNUserNotificationCenter {
return unuserNotifications
}
}
extension NotificationService: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
completionHandler()
}
}
/// Notification urgency enum
enum NotificationUrgency: Int {
case critical = 5
case normal = 1
case low = 0
var priority: UNNotificationPriority {
switch self {
case .critical: return .high
case .normal: return .default
case .low: return .low
}
}
}