私はApple Watch用のトレーニングアプリを開発中で、実際の時計にHealthKitを使用していくつかの問題が発生しました。HealthKit認可はシミュレータで許可されていますが、実際のデバイスでは動作しません
リクエスト認証は、シミュレータとデバイスの両方で動作し、すべての起動時に成功したと表示されます。しかし、サンプルを照会して読み込むのは私のデバイスでは失敗しますが、シミュレータでは失敗します。
認証が成功した後、トレーニングをクエリまたは保存する必要があるときに、「認可が決定されていません」と表示されます。
両方のエンタイトルメントでHealthKitがYESに設定され、HealthKitとBackgroundの機能が有効になり、NSHealthShareUsageDescriptionキーとNSHealthUpdateUsageDescriptionキーがiOS Info.plistで提供されます。
認証コード
// Configure write values
let writeTypes: Set<HKSampleType> = [.workoutType(),
HKSampleType.quantityType(forIdentifier: .heartRate)!,
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKSampleType.quantityType(forIdentifier: .stepCount)!,
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
HKSampleType.quantityType(forIdentifier: .distanceSwimming)!,
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
HKSampleType.quantityType(forIdentifier: .swimmingStrokeCount)!]
// Configure read values
let readTypes: Set<HKObjectType> = [.activitySummaryType(), .workoutType(),
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .distanceCycling)!,
HKObjectType.quantityType(forIdentifier: .distanceSwimming)!,
HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!,
HKObjectType.quantityType(forIdentifier: .swimmingStrokeCount)!]
// Create health store
let healthStore = HKHealthStore()
// Use it to request authorization for our types
healthStore.requestAuthorization(toShare: writeTypes, read: readTypes) { (success, error) in
if success {
print("Success: authorization granted")
} else {
print("Error: \(error?.localizedDescription ?? "")")
}
}
クエリコード(Udemyコース)
func startQuery(_ quantityTypeIdentifier: HKQuantityTypeIdentifier) {
// We only want data points after our workout start date
let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil, options: .strictStartDate)
// And from our current device
let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])
// Combine them
let queryPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [datePredicate, devicePredicate])
// Write code to receive results from our query
let updateHandler: (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> Void = { query, samples, deletedObjects, queryAnchor, error in
//safely typecast to a quantity sample so we can read values
guard let samples = samples as? [HKQuantitySample] else { return }
//process the samples
print("Start processing samples")
self.process(samples, type: quantityTypeIdentifier)
}
// Create the query out of our type (e.g. heart rate), predicate and result handling code
let quantityType = HKObjectType.quantityType(forIdentifier: quantityTypeIdentifier)!
let query = HKAnchoredObjectQuery(type: quantityType, predicate: queryPredicate, anchor: nil, limit: HKObjectQueryNoLimit, resultsHandler: updateHandler)
// Tell HealthKit to re-run the code every time new data is available
query.updateHandler = updateHandler
// Start the query running
healthStore.execute(query)
// Stach it away so we can stop it later
activeDataQueries.append(query)
}