I’m making a smart alarm for watchOS and I have it mostly functional however if the user was to set the alarm and then force close the app then my alarm fails to play at the scheduled time and instead of the alarm it’s just a notification “Alarm 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 in future?”. If the app is not force closed then the alarm will play wether the user has the app in the foreground or not.
Am I missing something here? My app has background modes (smart alarm) enabled and I know this functionality is achievable as apps such as “Sleep Cycle” alarm can be force closed on the watch and the alarm still goes off, my ExtendedRuntimeSessionDelegate looks like below:
`import WatchKit
class ExtendedRuntimeSessionDelegate: NSObject, WKExtendedRuntimeSessionDelegate {
var selectedVibration: String = “medium”
var vibrationRepeatDelay: Double = 3.0
let vibrationStrengths: [String: WKHapticType] = [
"very low": .click,
"low": .directionUp,
"medium": .success,
"high": .start,
"very high": .notification
]
func extendedRuntimeSessionWillExpire(_ extendedRuntimeSession: WKExtendedRuntimeSession) {
print("extendedRuntimeSessionWillExpire: Session about to expire")
}
func handle(_ extendedRuntimeSession: WKExtendedRuntimeSession) {
print("handle: Resuming extended runtime session")
extendedRuntimeSession.delegate = self
startVibration(session: extendedRuntimeSession)
}
func extendedRuntimeSessionDidStart(_ extendedRuntimeSession: WKExtendedRuntimeSession) {
print("extendedRuntimeSessionDidStart: runtime session started")
startVibration(session: extendedRuntimeSession)
}
func extendedRuntimeSession(_ extendedRuntimeSession: WKExtendedRuntimeSession, didInvalidateWith reason: WKExtendedRuntimeSessionInvalidationReason, error: Error?) {
print("Session invalidated: (reason)")
if let error = error {
print("Error: (error.localizedDescription)")
}
}
private func startVibration(session: WKExtendedRuntimeSession) {
print("Start Vibration called")
let hapticType = vibrationStrengths[selectedVibration] ?? .success
session.notifyUser(hapticType: hapticType) { outHapticType in
// Repeat the same haptic type based on the vibration repeat delay
outHapticType.pointee = hapticType
return self.vibrationRepeatDelay
}
// Set alarmState to active when the vibration starts
DispatchQueue.main.async {
UserDefaults.standard.set(AlarmState.active.rawValue, forKey: "alarmState")
print("startVibration: Alarm state saved as (AlarmState.active)")
}
}
func stopVibration(session: WKExtendedRuntimeSession) {
session.invalidate()
// Update the app's state when the vibration stops
DispatchQueue.main.async {
UserDefaults.standard.set(AlarmState.notSet.rawValue, forKey: "alarmState")
print("stopVibration: Alarm state saved as (AlarmState.notSet)")
}
}
}
`
I have read through the docs and it would seem “handle()” should be called on the delegate however this is not ever called.
https://developer.apple.com/documentation/watchkit/wkextendedruntimesession/3131068-start