关于Apple Watch中Apple Workouts应用静态训练单一位置的添加逻辑、读写方法及互操作性的技术问询
关于Apple Watch静态训练单一位置的技术解答
嘿,这个问题我之前做HealthKit开发的时候特意研究过,刚好能给你说清楚细节:
1. Apple Workouts应用是如何为训练添加该单一位置的?
这个静态训练的单一位置,其实是存储在HKWorkout的metadata里的,对应的键是HKMetadataKeyWorkoutLocation(类型为CLLocation)。苹果官方文档虽然没专门把它拎出来讲,但它是HealthKit框架原生支持的元数据键。
Workouts应用的逻辑很直接:当你启动一个静态训练(比如力量训练、瑜伽)时,它会请求设备的位置权限,获取到当前的CLLocation后,就把这个对象塞进该训练对应的HKWorkout的metadata字典里。而跑步、骑行这类移动训练的路线数据,是存在独立的HKWorkoutRoute样本中的——和这个单一位置字段完全是两个不同的数据存储方式,所以你查HKWorkoutRoute会得到空列表,这很正常。
2. 作为开发者,如何读取该位置并在自有应用中展示带图钉的地图?
要实现这个功能,分四步走,我给你贴个Swift的示例代码,一看就懂:
步骤拆解:
- 申请HealthKit权限:先在Info.plist里添加位置和健康权限的描述,然后请求
HKObjectType.workoutType()的读取权限。 - 查询目标训练:用
HKSampleQuery获取你要的HKWorkout样本。 - 提取位置数据:从
HKWorkout的metadata中通过HKMetadataKeyWorkoutLocation取出CLLocation。 - 用MapKit展示图钉:创建
MKPointAnnotation并添加到地图上,调整视角聚焦到位置点。
代码示例:
import HealthKit import MapKit class WorkoutLocationManager { private let healthStore = HKHealthStore() private weak var mapView: MKMapView? init(mapView: MKMapView) { self.mapView = mapView } // 请求HealthKit权限 func requestPermissions() async throws { let workoutType = HKObjectType.workoutType() try await healthStore.requestAuthorization(toShare: [], read: [workoutType]) } // 提取最近一次力量训练的位置并展示 func fetchAndShowLatestWorkoutLocation() { let workoutType = HKObjectType.workoutType() // 筛选静态训练,这里以传统力量训练为例 let predicate = HKQuery.predicateForWorkouts(with: .traditionalStrengthTraining) // 按开始时间倒序,取最近的一条 let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false) let query = HKSampleQuery( sampleType: workoutType, predicate: predicate, limit: 1, sortDescriptors: [sortDescriptor] ) { [weak self] _, samples, error in guard let self = self, let workout = samples?.first as? HKWorkout, error == nil else { print("查询训练失败:\(error?.localizedDescription ?? "未知错误")") return } // 从metadata中提取位置 guard let location = workout.metadata?[HKMetadataKeyWorkoutLocation] as? CLLocation else { print("该训练没有存储位置数据") return } // 回到主线程更新UI DispatchQueue.main.async { self.displayPinOnMap(location: location) } } healthStore.execute(query) } // 在地图上展示图钉 private func displayPinOnMap(location: CLLocation) { guard let mapView = mapView else { return } let annotation = MKPointAnnotation() annotation.coordinate = location.coordinate annotation.title = "训练位置" mapView.addAnnotation(annotation) // 调整地图视角,让位置点居中 let region = MKCoordinateRegion( center: location.coordinate, latitudinalMeters: 1500, longitudinalMeters: 1500 ) mapView.setRegion(mapView.regionThatFits(region), animated: true) } }
3. 写入训练数据时,如何分配该位置保证与Apple Fitness等应用的互操作性?
核心就是用标准的HKMetadataKeyWorkoutLocation键把位置存入HKWorkout的metadata,这样Apple Fitness和其他遵循HealthKit规范的应用就能识别并正确显示这个位置的图钉了。
代码示例(写入带位置的训练数据):
func writeStaticWorkoutWithCurrentLocation() async throws { // 1. 先请求写入权限 let workoutType = HKObjectType.workoutType() try await healthStore.requestAuthorization(toShare: [workoutType], read: []) // 2. 获取当前位置(这里简化处理,实际要处理Core Location的权限和回调) let locationManager = CLLocationManager() guard let currentLocation = locationManager.location else { throw NSError(domain: "LocationError", code: 1, userInfo: [NSLocalizedDescriptionKey: "无法获取当前位置"]) } // 3. 构建HKWorkout对象,把位置加入metadata let startDate = Date() let endDate = startDate.addingTimeInterval(2700) // 45分钟训练 let workout = HKWorkout( activityType: .yoga, start: startDate, end: endDate, workoutEvents: nil, totalEnergyBurned: HKQuantity(unit: HKUnit.kilocalorie(), doubleValue: 250), totalDistance: nil, metadata: [HKMetadataKeyWorkoutLocation: currentLocation] // 关键:添加位置元数据 ) // 4. 写入HealthKit try await healthStore.save(workout) print("带位置的训练数据已成功写入") }
需要注意的是,写入前要确保用户授权了HealthKit的写入权限,以及Core Location的位置权限(如果要获取当前位置的话)。
内容的提问来源于stack exchange,提问作者Empty2k12
相关产品推荐
相关产品推荐

