diff --git a/NotificationService/NotificationService.swift b/NotificationService/NotificationService.swift index e88c0a7e..06971bac 100644 --- a/NotificationService/NotificationService.swift +++ b/NotificationService/NotificationService.swift @@ -24,7 +24,8 @@ class NotificationService: UNNotificationServiceExtension { var notificationActions: [UNNotificationAction] = [] let userInfo = bestAttemptContent.userInfo os_log("handleNotification userInfo %{PUBLIC}@", log: .default, type: .info, userInfo) - + + //Check if the user has defined custom actions in the payload if let actionsArray = parseActions(userInfo), let category = parseCategory(userInfo) { for actionDict in actionsArray { if let action = actionDict["action"], @@ -34,13 +35,11 @@ class NotificationService: UNNotificationServiceExtension { if action.hasPrefix("navigate") { options = [.foreground] } - let notificationAction = UNNotificationAction( identifier: action, title: title, options: options ) - notificationActions.append(notificationAction) } } @@ -53,13 +52,22 @@ class NotificationService: UNNotificationServiceExtension { intentIdentifiers: [], options: .customDismissAction ) - let notificationCategories: Set = [notificationCategory] - UNUserNotificationCenter.current().setNotificationCategories(notificationCategories) + UNUserNotificationCenter.current().getNotificationCategories { (existingCategories) in + // Check if the new category already exists, this is a hash of the actions string done by the cloud service + let existingCategoryIdentifiers = existingCategories.map(\.identifier) + if !existingCategoryIdentifiers.contains(category) { + var updatedCategories = existingCategories + os_log("handleNotification adding category %{PUBLIC}@", log: .default, type: .info, category) + updatedCategories.insert(notificationCategory) + UNUserNotificationCenter.current().setNotificationCategories(updatedCategories) + } + } } } - + + // check if there is an attachment to put on the notification // this should be last as we need to wait for media - // Retrieve the attachment URL from the payload + // TODO we should support relative paths and try the user's openHAB (local,remote) for content if let attachmentURLString = userInfo["attachment-url"] as? String, let attachmentURL = URL(string: attachmentURLString) { os_log("handleNotification downloading %{PUBLIC}@", log: .default, type: .info, attachmentURLString) downloadAndAttachMedia(url: attachmentURL) { attachment in @@ -88,8 +96,7 @@ class NotificationService: UNNotificationServiceExtension { private func parseActions(_ userInfo: [AnyHashable: Any]) -> [[String: String]]? { // Extract actions and convert it from JSON string to an array of dictionaries - if let actionsString = userInfo["actions"] as? String, - let actionsData = actionsString.data(using: .utf8) { + if let actionsString = userInfo["actions"] as? String, let actionsData = actionsString.data(using: .utf8) { do { if let actionsArray = try JSONSerialization.jsonObject(with: actionsData, options: []) as? [[String: String]] { return actionsArray @@ -109,7 +116,7 @@ class NotificationService: UNNotificationServiceExtension { } return nil } - + private func downloadAndAttachMedia(url: URL, completion: @escaping (UNNotificationAttachment?) -> Void) { let task = URLSession.shared.downloadTask(with: url) { localURL, response, error in guard let localURL else { diff --git a/openHAB/AppDelegate.swift b/openHAB/AppDelegate.swift index e574523d..81a3934a 100644 --- a/openHAB/AppDelegate.swift +++ b/openHAB/AppDelegate.swift @@ -170,7 +170,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD if actionIdentifier == UNNotificationDefaultActionIdentifier { notifyNotificationListeners(userInfo) } else if actionIdentifier == UNNotificationDismissActionIdentifier { - // Handle the dismissal action + // Handle the dismissal action, nothing } else { userInfo["actionIdentifier"] = actionIdentifier notifyNotificationListeners(userInfo) diff --git a/openHAB/OpenHABRootViewController.swift b/openHAB/OpenHABRootViewController.swift index e1d83a85..15dfa920 100644 --- a/openHAB/OpenHABRootViewController.swift +++ b/openHAB/OpenHABRootViewController.swift @@ -163,22 +163,23 @@ class OpenHABRootViewController: UIViewController { let theData = note?.userInfo if theData != nil { let prefsURL = Preferences.remoteUrl - if prefsURL.contains("openhab.org") { - guard let deviceId = theData?["deviceId"] as? String, let deviceToken = theData?["deviceToken"] as? String, let deviceName = theData?["deviceName"] as? String else { return } - os_log("Registering notifications with %{PUBLIC}@", log: .notifications, type: .info, prefsURL) - NetworkConnection.register(prefsURL: prefsURL, deviceToken: deviceToken, deviceId: deviceId, deviceName: deviceName) { response in - switch response.result { - case .success: - os_log("my.openHAB registration sent", log: .notifications, type: .info) - case let .failure(error): - os_log("my.openHAB registration failed %{PUBLIC}@ %d", log: .notifications, type: .error, error.localizedDescription, response.response?.statusCode ?? 0) - } + if prefsURL.contains("openhab.org") { + guard let deviceId = theData?["deviceId"] as? String, let deviceToken = theData?["deviceToken"] as? String, let deviceName = theData?["deviceName"] as? String else { return } + os_log("Registering notifications with %{PUBLIC}@", log: .notifications, type: .info, prefsURL) + NetworkConnection.register(prefsURL: prefsURL, deviceToken: deviceToken, deviceId: deviceId, deviceName: deviceName) { response in + switch response.result { + case .success: + os_log("my.openHAB registration sent", log: .notifications, type: .info) + case let .failure(error): + os_log("my.openHAB registration failed %{PUBLIC}@ %d", log: .notifications, type: .error, error.localizedDescription, response.response?.statusCode ?? 0) } } + } } } @objc func handleApnsMessage(notification: Notification) { + //actionIdentifier is the result of a action button being pressed if let action = notification.userInfo?["actionIdentifier"] as? String { if action.hasPrefix("navigate") { navigateCommandAction(action) @@ -187,12 +188,13 @@ class OpenHABRootViewController: UIViewController { sendCommandAction(action) } } else if let navigate = notification.userInfo?["navigate"] as? String { + //the user simply clicked on the notification, but indicated a navigation in the payload navigateCommandAction(navigate) } } - func navigateCommandAction(_ navigate: String) { - os_log("handleApnsMessage navigation: %{PUBLIC}@", log: .notifications, type: .info, navigate) + private func navigateCommandAction(_ navigate: String) { + os_log("navigateCommandAction: %{PUBLIC}@", log: .notifications, type: .info, navigate) if let index = navigate.firstIndex(of: ":") { let type = String(navigate[..