Hi, I have tried to observe HealthKit data (workouts) with background delivery, but I am faced with a problem - updates don't come when iPhone is locked by Face ID. Everything works fine with an unlocked device. I didn't find any references in the documentations. Is this the expected behavior?
Code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
HealthManager.shared.startObservingWorkouts {
/*
Don't receive updates
*/
}
return true
}
}
class HealthManager {
static let shared: HealthManager = .init()
private let hkStore = HKHealthStore()
init() { }
func startObservingWorkouts(handleUpdates: @escaping ([HKWorkout]) -> Void) {
hkStore.getRequestStatusForAuthorization(
toShare: [],
read: [.workoutType()])
{ [weak self] status, _ in
guard status == .unnecessary else {
return
}
let prediction = HKQuery.predicateForSamples(
withStart: Date().startOfDay,
end: Date().endOfDay,
options: [.strictStartDate, .strictEndDate]
)
let query = HKObserverQuery(
sampleType: .workoutType(),
predicate: prediction,
updateHandler: { [weak self] _, completionHandler, _ in
self?.getWorkouts {
handleUpdates($0 ?? [])
completionHandler()
}
}
)
self?.hkStore.execute(query)
self?.hkStore.enableBackgroundDelivery(
for: .workoutType(),
frequency: .immediate
) { _, error in
print(error)
}
}
}
private func getWorkouts(handleResult: @escaping ([HKWorkout]?) -> Void) {
let prediction = HKQuery.predicateForSamples(
withStart: Date().startOfDay,
end: Date().endOfDay,
options: [.strictStartDate, .strictEndDate]
)
let query = HKSampleQuery(
sampleType: .workoutType(),
predicate: prediction,
limit: HKObjectQueryNoLimit,
sortDescriptors: nil
) { query, samples, error in
if error != nil {
return
}
guard let samples = samples else {
fatalError("*** Invalid State: This can only fail if there was an error. ***")
}
guard let workouts = samples as? [HKWorkout] else {
return
}
handleResult(workouts)
}
hkStore.execute(query)
}
}
@main
struct HealthKitTestApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}