1

I have create a smart alarm which relies on WKExtendedRuntimeSession. There should be a possibility to manually stop the background session by, for example navigating back in the view hierarchy.

class BackgroundSessionController {
    private var session: WKExtendedRuntimeSession?
    
    func start() {
        guard session?.state != .running else { return }
        if nil == session || session?.state == .invalid {
            session = WKExtendedRuntimeSession()
        }
        print("session started")
        session?.start(at: Date())
    }
    
    func stopManual() {
        session?.invalidate()
    }
    
    func stopByAlarm() {
        session?.notifyUser(hapticType: .stop)
        session?.invalidate()
    }
}

When firing the function stopManual, and so invalidating the session I receive the message:

App has been running in the background but failed to play a scheduled alarm. Would you like to disable the app's ability to run background tasks ...

Seems that manually invalidating a session requires a haptic notification as well ? How can I invalidate the session without the haptic feedback ?

added example:

let's say i'm a terrorist and i'm making a secret bomb which fires when movement stops. So you need to keep moving or else a timer starts counting down.

  1. I Activate the app, I need to enable background modes, else the sensors stop working when the app goes into the background.
  2. When movement stops, a smart alarm timer will fire .start(at:) which counts down from 10 minutes.
  3. I'm using smart alarm as functionality, which allows me to use 30 minutes of background modes. When these 30 minutes are finished and the person is still moving, i want to invalidate and then restart the session without sending any haptic feedback (the person will notice something isn'tright and deactivates the bomb)

What to use in this case then? This example is a bit weird but almost the same functionality I want.

Bjorn Morrhaye
  • 687
  • 9
  • 30
  • I laughed at your added example "Let's say I'm a terrorist and I'm making a secret bomb". Out of all possible examples why choose one that may put you on the FBI watch list?? Good luck with the hopefully non-bomb project though – Ryan Nov 04 '22 at 01:21

1 Answers1

1

The documentation of WKExtendedRuntimeSession clearly states this behaviour:

For sessions started with start(at:), you can only call invalidate() when the app is active. For all other sessions, you can call invalidate() to end a session at any time.

Since you are passing the current date for start(at:), why don't you just use start() instead and then you can call invalidate() even while your app is inactive. If you actually call start(at:) with a future date, then you don't have any alternatives.

The docs also state that you must play a haptic during your session. So if your session has started, you cannot invalidate it without playing a haptic. If your session hasn't started yet, you can invalidate it.

During the session, your app must trigger the alarm by calling the session’s notifyUser(hapticType:repeatHandler:) method.

If you fail to play a haptic during the session, the system displays a warning and offers to disable future sessions.

Bear in mind, this is probably a designed feature of watchOS. Due to the battery constraints of Apple Watches, watchOS puts an even bigger emphasis on apps being energy efficient, so if your app uses a background mode and the system thinks it might be abusing it (by declaring a smart alarm background mode, but not playing an alarm), it will alert the user.

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • For my app which actually is an alarm, I'm using the smart alarm function, which requires you to use start(at:) instead of start(). I can use other behaviors like mindfulness, but I feel they don't fit the function I'm using it for ? – Bjorn Morrhaye Feb 26 '21 at 10:35
  • @BjornMorrhaye if you are actually using it for a smart alarm, don't change the background mode, since using an incorrect background mode might get your app rejected from the AppStore. However, as I've said, this behaviour is by design. You cannot do anything about it. – Dávid Pásztor Feb 26 '21 at 10:38
  • I have added an example – Bjorn Morrhaye Feb 26 '21 at 11:22
  • @BjornMorrhaye as I've said before, this is currently not supported by watchOS. You either have to send the haptic via `notifyUser` or accept that they'll get the system notification asking them if they want to disable background mode or not. This is a limitation of watchOS that you can't get around. – Dávid Pásztor Feb 26 '21 at 11:28
  • Ok, suppose i got to live with it ? Or is there another possibility? How do sleep tracking app's detect when you fall asleep and then monitor light and deep sleep phases without waking up somebody with an alert ? – Bjorn Morrhaye Feb 26 '21 at 11:32