如何从HealthKit训练样本元数据中读取HKMetadataKeyWeatherCondition?
解决HKWorkout无法获取HKMetadataKeyWeatherCondition的问题
核心原因与解决方向
Apple Fitness中显示的训练天气状况,通常并非直接存储在HKWorkout的metadata字典中,而是以独立的HKWeatherSample类型存在,需要单独查询并关联到对应的训练记录。以下是具体的解决步骤:
1. 单独查询HKWeatherSample样本
添加针对天气样本的查询逻辑,通过训练的时间范围匹配对应的天气数据:
func asyncWorkout() async throws { let workoutTypeValue: HKWorkoutActivityType = .running // 原有训练查询逻辑不变 let predicate1 = HKQuery.predicateForSamples(withStart: Date().addingTimeInterval(-5*24*60*60), end: Date().addingTimeInterval(-3*24*60*60), options: .strictStartDate) let predicate2 = HKQuery.predicateForWorkouts(with: workoutTypeValue) let predicate = NSCompoundPredicate(type: .and, subpredicates: [predicate1, predicate2]) var myAnchor: HKQueryAnchor? let anchorDescriptor = HKAnchoredObjectQueryDescriptor( predicates: [.workout(predicate)], anchor: myAnchor ) let results = try await anchorDescriptor.result(for: healthStore) let addedSamples = results.addedSamples // 新增:查询天气样本 guard let weatherType = HKObjectType.weatherSampleType() else { throw NSError(domain: "HealthKitError", code: -1, userInfo: [NSLocalizedDescriptionKey: "天气样本类型不可用"]) } for workout in addedSamples { print("sample meta: \(String(describing: workout.metadata))") // 匹配训练时间范围的天气样本 let weatherPredicate = HKQuery.predicateForSamples(withStart: workout.startDate, end: workout.endDate, options: .strictStartDate) let weatherDescriptor = HKSampleQueryDescriptor( predicate: weatherPredicate, sortDescriptors: [], limit: HKObjectQueryNoLimit, resultsType: weatherType ) let weatherSamples = try await weatherDescriptor.result(for: healthStore) for weatherSample in weatherSamples { // 解析天气状况枚举 if let conditionRawValue = weatherSample.metadata?[HKMetadataKeyWeatherCondition] as? Int, let condition = HKWeatherCondition(rawValue: conditionRawValue) { print("训练\(workout.uuid)对应的天气状况:\(condition.rawValue)") } } } myAnchor = results.newAnchor }
2. 确认权限配置
- 在
Info.plist中添加HealthKit权限描述:NSHealthShareUsageDescription:说明应用需要分享健康数据的原因NSHealthUpdateUsageDescription:说明应用需要读取健康数据的原因
- 请求天气样本的读取权限:
let typesToRead: Set<HKObjectType> = [ HKObjectType.workoutType(), HKObjectType.weatherSampleType() // 必须添加这个权限 ] try await healthStore.requestAuthorization(toShare: nil, read: typesToRead)
3. 直接验证元数据键(备选方案)
如果怀疑枚举映射问题,可以直接用字符串键取值:
// 在遍历HKWorkout时尝试直接读取 if let conditionRawValue = workout.metadata?["HKWeatherCondition"] as? Int { let condition = HKWeatherCondition(rawValue: conditionRawValue) ?? .unknown print("天气状况:\(condition)") }
4. 校验时间与时区匹配
检查Apple Fitness中显示的天气时间是否与训练的startDate/endDate完全匹配,避免时区差异导致查询范围遗漏数据。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

