Swift如何获取Health Kit按设备类型区分的每日运动分类步数
实现方案
核心逻辑是在HealthKit查询时获取每一条步数样本的来源设备信息、关联运动属性,再自行按维度聚合,不需要依赖系统的时间区间分组能力。
1. 前置权限确认
确保你已经提前向用户申请了步数数据的读取权限,示例代码如下:
import HealthKit let healthStore = HKHealthStore() let stepType = HKObjectType.quantityType(forIdentifier: .stepCount)! // 请求授权 healthStore.requestAuthorization(toShare: nil, read: [stepType]) { success, error in guard success else { // 处理权限拒绝逻辑 return } // 权限获取成功后执行查询 }
2. 构造步数样本查询
直接查询目标日期内的所有步数原始样本,获取每个样本的设备来源、关联运动信息:
// 构造当日的查询时间范围 let calendar = Calendar.current let startOfDay = calendar.startOfDay(for: Date()) let endOfDay = calendar.date(byAdding: .day, value: 1, to: startOfDay)! let predicate = HKQuery.predicateForSamples(withStart: startOfDay, end: endOfDay, options: .strictStartDate) // 构造查询对象 let query = HKSampleQuery( sampleType: stepType, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil ) { _, samples, error in guard let samples = samples as? [HKQuantitySample], error == nil else { return } // 处理样本数据做分组聚合 self.groupStepData(samples: samples) } healthStore.execute(query)
3. 按设备+运动组别分组聚合
自定义分组逻辑,分别按设备类型、运动类型两层维度拆分统计:
// 自定义分组结果结构 struct GroupedStepData { let deviceType: String // 设备类型:iPhone / Apple Watch let activityGroup: String // 运动组别:日常活动/步行/跑步/其他运动 let totalSteps: Int // 该组总步数 } func groupStepData(samples: [HKQuantitySample]) { var result: [GroupedStepData] = [] // 第一层:按设备来源分组 let deviceGrouped = Dictionary(grouping: samples) { sample -> String in let source = sample.source if source.name.contains("Apple Watch") || source.bundleIdentifier.contains("com.apple.health.watch") { return "Apple Watch" } else { return "iPhone" } } // 第二层:按运动组别分组并统计步数 for (device, deviceSamples) in deviceGrouped { let activityGrouped = Dictionary(grouping: deviceSamples) { sample -> String in // 检查样本是否关联了运动记录 if let workout = sample.workout { switch workout.workoutActivityType { case .walking: return "步行" case .running: return "跑步" case .hiking: return "徒步" case .cycling: return "骑行" default: return "其他运动" } } else { return "日常活动" } } // 计算每组总步数 for (activity, activitySamples) in activityGrouped { let totalSteps = activitySamples.reduce(0) { partialResult, sample in partialResult + Int(sample.quantity.doubleValue(for: HKUnit.count())) } result.append(GroupedStepData( deviceType: device, activityGroup: activity, totalSteps: totalSteps )) } } // result 即为最终需要的分组数据,可直接使用 }
注意事项
- 如果需要排除第三方App写入的步数,可在分组时加判断过滤非苹果官方来源的样本
- 数据量较大时可以改用
HKStatisticsCollectionQuery配合groupBySource参数直接按设备聚合,查询效率更高 - iOS16及以上系统可直接使用
HKSourceRevision的productType属性更精准判断设备型号
内容的提问来源于stack exchange,提问作者dqualias
相关产品推荐
相关产品推荐

