How to trigger haptic alert when inactive watch receives local notification
Asked Answered
A

3

6

I am working on a timer app for the Apple Watch.

At a specific time (end of timer) the iPhone fires a scheduled UILocalNotification which on the inactive Apple Watch should trigger a haptic alert to tell the user that the timer has ended.

I've done this since timers don't continue to run on Apple Watch once the watch is inactive.

The problem I am facing is:

a) the notification is sometimes shown on the iPhone rather than on the apple watch (based on other posts, I fear that this cannot be changed...)

b) no haptic alert is given on the watch (purely display of notification and this only at next time when the user is activating the watch, not at the time when the notification is actually triggered)

func sendAwakeNotification(nextTime:NSDate) {
    print("AppDelegate: - sendAwakeNotification")

    dispatch_async(dispatch_get_main_queue()) { () -> Void in

        let localNotification = UILocalNotification()
        localNotification.fireDate = nextTime
        localNotification.timeZone = NSTimeZone.defaultTimeZone()
        localNotification.alertBody = "Finished Step"
        localNotification.alertTitle = "Alert"

        localNotification.soundName = UILocalNotificationDefaultSoundName

        localNotification.category = "myTimer"
        let userInfo: [NSObject : AnyObject] = [
            "notification_id" : "myTimerNotification"
        ]
        localNotification.userInfo = userInfo

        UIApplication.sharedApplication().scheduleLocalNotification(localNotification)

    }
}

The code in Notification

override func didReceiveLocalNotification(localNotification: UILocalNotification, withCompletion completionHandler: ((WKUserNotificationInterfaceType) -> Void)) {

    print("received notification")

    dispatch_async(dispatch_get_main_queue()) { () -> Void in
        let notificationCenter = NSNotificationCenter.defaultCenter()
        notificationCenter.postNotificationName(NotificationAlertFromPhone, object: nil)
    }

    completionHandler(.Custom)
}

I've tried to trigger a haptic alert directly in NotificationController (WKInterfaceDevice.currentDevice().playHaptic(WKHapticType.Notification)), but it did not work. I therefore reverted to send notification which should be received by ExtensionDelegate to trigger the haptic.

Here is the code in ExtensionDelegate:

private func setupNotificationCenter() {
    print("ExtensionDelegate:  - setupNotificationCenter")

    notificationCenter.addObserverForName(NotificationAlertFromPhone, object: nil, queue: nil) { (notification:NSNotification) -> Void in
        WKInterfaceDevice.currentDevice().playHaptic(WKHapticType.Notification)
    }
}
Acromegaly answered 12/5, 2016 at 13:44 Comment(0)
M
3

Where notifications are shown

a) the notification is sometimes shown on the iPhone rather than on the apple watch (based on other posts, I fear that this cannot be changed...)

That's correct. It's up to iOS to determine where to show the notification.

  • If your iPhone is unlocked, you'll get notifications on your iPhone, instead of your Apple Watch.

  • If your iPhone is locked or asleep, you'll get notifications on your Apple Watch, unless your Apple Watch is locked with your passcode.

When your local notification fires in the future, it may be shown on the phone. In that case, the watch won't receive any notification at all.

When the notification is handled by the watch

b) no haptic alert is given on the watch (purely display of notification and this only at next time when the user is activating the watch, not at the time when the notification is actually triggered)

This is correct. You're expecting didReceiveLocalNotification to fire on the watch, but this only occurs when the watch is activated:

If a local notification arrives while your app is active, WatchKit calls this method to deliver the notification payload. Use this method to respond to the notification.

This is the reason why your haptic feedback doesn't happen when you expect, as the call to play the haptic feedback doesn't occur until later.

A workaround for your approach

You can conditionally play your haptic by first examining the local notification's fireDate. Only play your haptic feedback if the notification handling just triggered.

A better solution

It appears that you're trying to handle playing a haptic independent of the default feedback which already occurs when watchOS displays the notification for you.

You may want to skip your extension from playing its own haptic feedback, as the user has already been notified by the system.

Make a feature request

The real issue you're trying to work around is that only Apple's timer app can schedule its own local notifications.

If you haven't already, you may want to submit a feature request asking the Apple let third-party developers post local notifications on watchOS.

Matchless answered 13/5, 2016 at 4:41 Comment(4)
Dear PetahChristian, thanks for your answer. My problem is though that no haptic feedback is played at all. Neither the standard one when the notification is received, nor the one that I try to trigger programmatically.Acromegaly
Have you checked the iPhone's Watch app, under Sounds & Haptics? Make sure the Haptic Strength (and Alert Volume) settings aren't turned down. Also make sure your app has been granted appropriate user permission for local .Sound, .Alert, and .Badge notifications. Otherwise, notification sounds won't play. You'll find the app-specific preferences in the Settings app, under Notifications.Matchless
thanks PetahChristian, it is usually the most obvious mistakes ;-) had only granted permission for alert, not sound...Acromegaly
You're welcome :) Remember that it's more expedient to describe the actual problem -- no haptic feedback is played at all -- instead of the attempted solution.Matchless
D
1

For anyone else having this issue, it also could be that no sound is set. The official apple watch docs dont specify that you have to add a sound.

Make sure to add:

content.sound = UNNotificationSound.default

Deservedly answered 9/2, 2020 at 9:44 Comment(0)
F
0

Set identifier to UUID().uuidString instead of "localNotificatoin"

static func setLocalNotification(title: String, subtitle: String, body: String, when: Double) {
    let content = UNMutableNotificationContent()
    content.title = title
    content.subtitle = subtitle
    content.body = body
    content.sound = UNNotificationSound.default

    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: when, repeats: false)
    let request = UNNotificationRequest.init(identifier: UUID().uuidString, content: content, trigger: trigger)
    UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
Freestanding answered 6/3, 2023 at 23:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.