Michał Ziobro
Michał Ziobro

Reputation: 11752

watchOS, not receiving remote notifications

I am developing app on WatchOS 6 but I cannot receive remote notification

Here is my registration code for push notifications in ExtensionDelegate I am getting valid device token.

extension ExtensionDelegate {

    func setupRemoteNotifications() {

        UNUserNotificationCenter.current().delegate = self

        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in

            print("[WATCH PUSH NOTIFICATIONS] Permission granted: \(granted)")

            guard granted else {
                DispatchQueue.main.async {
                    self.showNotificationsNotGrantedAlert()
                    return
                }
                return
            }

            self.getNotificationSettings()
        }
    }

    private func getNotificationSettings() {

        UNUserNotificationCenter.current().getNotificationSettings { settings in

            print("[WATCH PUSH NOTIFICATIONS] Notification settings: \(settings)")

            guard settings.authorizationStatus == .authorized else { return }

            DispatchQueue.main.async {
                WKExtension.shared().registerForRemoteNotifications()
                self.onRemoteNotificationRegistration()
            }
        }
    }

    private func onRemoteNotificationRegistration() { }

    func didRegisterForRemoteNotifications(withDeviceToken deviceToken: Data) {

        // Convert token to string
        let deviceTokenString = deviceToken.map { data in String(format: "%02.2hhx", data) }.joined()

        print("[WATCH PUSH NOTIFICACTIONS] Device Token: \(deviceTokenString)")

        UserSettings.shared.deviceToken = deviceTokenString
    }

    func didFailToRegisterForRemoteNotificationsWithError(_ error: Error) {
        print("[WATCH PUSH NOTIFICATIONS] Failed to register device: \(error)")
        UserSettings.shared.deviceToken = nil
    }

    func didReceiveRemoteNotification(_ userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (WKBackgroundFetchResult) -> Void) {

        print("[WATCH PUSH NOTIFICATIONS] Push notification received: \(userInfo)")

        let aps = userInfo["aps"] as! [String: AnyObject]

        completionHandler(.noData)
    }
}

extension ExtensionDelegate: UNUserNotificationCenterDelegate {

    // show notification also when in foreground
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

        print("[WATCH PUSH NOTIFICATION] Will present notification...")

        let categoryIdentifier = notification.request.content.categoryIdentifier
        let category = NotificationCategory(rawValue: categoryIdentifier)

        if category == NotificationCategory.NotificationCategory {

        } else if category == NotificationCategory.ActivityCategory {

        }

        completionHandler([.alert, .badge, .sound])
    }


    // called when tapped onto notification banner
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print("[WATCH PUSH NOTIFICATION] Did receive notification response")

        let userInfo = response.notification.request.content.userInfo as! [String: AnyObject]

        let aps = userInfo["aps"] as! [String: AnyObject]

        let categoryIdentifier = response.notification.request.content.categoryIdentifier
        let category = NotificationCategory(rawValue: categoryIdentifier)

        if category == NotificationCategory.NotificationCategory {

        } else if category == NotificationCategory.ActivityCategory {

        }

        handleNotificationAction(response.actionIdentifier)
        openNotification(userInfo: userInfo)

        completionHandler()
    }

}

extension ExtensionDelegate {

    private func handleNotificationAction(_ actionIdentifier: String) {

        let action = NotificationAction(rawValue: actionIdentifier)
        if action == NotificationAction.Call {
            print("Action: Call handled!")
        } else if action == NotificationAction.Email {
            print("Action: Email handled!")
        } else if action == NotificationAction.Message {
            print("Action: Message handled!")
        }
    }

    private func openNotification(userInfo: [String: AnyObject]) {
        // let something = userInfo["something"] ...
    }
}

extension ExtensionDelegate {

    private func showNotificationsNotGrantedAlert() {

        let settingsActionTitle = NSLocalizedString("Settings", comment: "")
        let cancelActionTitle = NSLocalizedString("Cancel", comment: "")
        let message = NSLocalizedString("You need to grant a permission from notification settings.", comment: "")
        let title = NSLocalizedString("Push Notifications Off", comment: "")

        let settingsAction = WKAlertAction(title: settingsActionTitle, style: .default) {

            print("[WATCH PUSH NOTIFICATIONS] Go to Notification Settings")
        }

        let cancelAction = WKAlertAction(title: cancelActionTitle, style: .cancel) {
            print("[WATCH PUSH NOTIFICATIONS] Cancel to go to Notification Settings")
        }

        WKExtension.shared().rootInterfaceController?.presentAlert(withTitle: title, message: message, preferredStyle: .alert, actions: [settingsAction, cancelAction])
    }
}

I've added Push notification Entitlement in WatchExtensions

I am sending notification from Push Notification Tester app using valid TeamId, P8 cert, P8 key, bundle Id -> where I am getting success.

I am sending default test notification nothing special

{
    "aps": {
        "alert": {
            "title": "Silver Salmon Creek",
            "body": "You are within 5 miles of Silver Salmon Creek."
        },
        "category": "Notification"
    }
}

I have similar code for iOS and there notification are delivered correctly on iPhone.

UPDATE

I've tested a little bit more

And I have application added to my iPhone app but iPhone app is for iOS 13 and Watch app is for WatchOS 6

So as I understand this WatchOS app can be install as standalone application.

I have checked "Support running without iOS App installation"

So as I understand my server should send this notification to both Watch device Token and iOS device token. And there APNS/iOS/watchOS take the decision if there is duplicated notification where to deliver this notification i.e. to iPhone / watchOS. If there is only watchOS app I think it will be delivered to watch Device token If there is both watch/iOS app then it will send to iOS and then device whether user is using iPhone/Watch in given moment and deliver it to currently used device.

So now if I send notification to iPhone device token with iOS bundle identifier, and have locked iPhone and watch on wrist I am getting notification on my WatchOS and even can look at long notifications with dynamic content.

But when I've uninstall iOS version of application, and send notification with iPhone or watch device token and appropriate bundle id iOS/watchOS then for standalone app I am not getting this notification delivered again.

Upvotes: 3

Views: 1602

Answers (2)

Michał Ziobro
Michał Ziobro

Reputation: 11752

I found the issue. It was related with the way Push Notification is send from the server using node-apns. I also have old Push Notification Tester app. 3.0 version of node-apns is required. there is additonal Header field send to APNS server

apns-push-type

Upvotes: 1

JohnC
JohnC

Reputation: 11

I encountered a similar issue, be sure your p8 Bundle ID is using the explicit WatchkitApp ID and not the Extension's ID.

Once I dropped the .watchkitextension and uninstalled (the app), reinstalled, reregistered the device, it worked.

Upvotes: 1

Related Questions