swift - HealthKit 会不断更新模拟器上的样本数据,但不会更新 Apple Watch 上的实际数据
问题描述
我刚开始使用 WWDC 开源快速学习。我正在学习如何创建手表操作系统锻炼应用程序。当我在模拟器上运行它时,它会不断更新示例数据,但在我的 Apple Watch 上,当我运行它时,它不会不断更新实时锻炼数据。我确信我必须处理下面的代码,但是
extension WorkoutManager: HKLiveWorkoutBuilderDelegate {
func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) {
}
func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set<HKSampleType>) {
for type in collectedTypes {
guard let quantityType = type as? HKQuantityType else {
return // Nothing to do.
}
let statistics = workoutBuilder.statistics(for: quantityType)
// Update the published values.
updateForStatistics(statistics)
}
}
}
我不知道调用 HealthKit 时到底发生了什么,我从 WWDC 示例中获取了大部分代码。
import Foundation
import HealthKit
class WorkoutManager: NSObject, ObservableObject {
var selectedWorkout: HKWorkoutActivityType? {
didSet {
guard let selectedWorkout = selectedWorkout else { return }
startWorkout(workoutType: selectedWorkout)
}
}
@Published var showingSummaryView: Bool = false {
didSet {
if showingSummaryView == false {
resetWorkout()
}
}
}
let healthStore = HKHealthStore()
var session: HKWorkoutSession?
var builder: HKLiveWorkoutBuilder?
func startWorkout(workoutType: HKWorkoutActivityType) {
let configuration = HKWorkoutConfiguration()
configuration.activityType = workoutType
configuration.locationType = .outdoor
// Create the session and obtain the workout builder.
do {
session = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)
builder = session?.associatedWorkoutBuilder()
} catch {
// Handle any exceptions.
return
}
// Set the workout builder's data source.
builder?.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore,
workoutConfiguration: configuration)
session?.delegate = self
builder?.delegate = self
// Start the workout session and begin data collection.
let startDate = Date()
session?.startActivity(with: startDate)
builder?.beginCollection(withStart: startDate) { (success, error) in
// The workout has started.
}
}
func requestAuthorization() {
// The quantity type to write to the health store.
let typesToShare: Set = [
HKQuantityType.workoutType()
]
// The quantity types to read from the health store.
let typesToRead: Set = [
HKQuantityType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.activitySummaryType()
]
// Request authorization for those quantity types.
healthStore.requestAuthorization(toShare: typesToShare, read: typesToRead) { (success, error) in
// Handle error.
}
}
// MARK: - Session State Control
// The app's workout state.
@Published var running = false
func togglePause() {
if running == true {
self.pause()
} else {
resume()
}
}
func pause() {
session?.pause()
}
func resume() {
session?.resume()
}
func endWorkout() {
session?.end()
showingSummaryView = true
}
// MARK: - Workout Metrics
@Published var averageHeartRate: Double = 0
@Published var heartRate: Double = 0
@Published var workout: HKWorkout?
func updateForStatistics(_ statistics: HKStatistics?) {
guard let statistics = statistics else { return }
DispatchQueue.main.async {
switch statistics.quantityType {
case HKQuantityType.quantityType(forIdentifier: .heartRate):
let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
self.heartRate = statistics.mostRecentQuantity()?.doubleValue(for: heartRateUnit) ?? 0
self.averageHeartRate = statistics.averageQuantity()?.doubleValue(for: heartRateUnit) ?? 0
default:
return
}
}
}
func resetWorkout() {
selectedWorkout = nil
builder = nil
workout = nil
session = nil
averageHeartRate = 0
heartRate = 0
}
}
extension WorkoutManager: HKWorkoutSessionDelegate {
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState,
from fromState: HKWorkoutSessionState, date: Date) {
DispatchQueue.main.async {
self.running = toState == .running
}
// Wait for the session to transition states before ending the builder.
if toState == .ended {
builder?.endCollection(withEnd: date) { (success, error) in
self.builder?.finishWorkout { (workout, error) in
DispatchQueue.main.async {
self.workout = workout
}
}
}
}
}
func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) {
}
}
extension WorkoutManager: HKLiveWorkoutBuilderDelegate {
func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) {
}
func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set<HKSampleType>) {
for type in collectedTypes {
guard let quantityType = type as? HKQuantityType else {
return // Nothing to do.
}
let statistics = workoutBuilder.statistics(for: quantityType)
// Update the published values.
updateForStatistics(statistics)
}
}
}
解决方案
有没有Workout processing
开启后台模式Info.plist
?
推荐阅读
- azure - 如何从 Azure 安排部署在 Azure App Service Web App 上的 Http Post 服务
- active-directory - 添加了新的域控制器,但更改不会复制到现有服务器
- javascript - JavaScript小行星游戏的矢量文本?
- sql-server - 为什么在代码中使用 EF6 connectionString 时出现“System.Data.MetadataException:'无法加载指定的元数据资源。'”错误?
- javafx - 为什么我的 javaFX 代码在 cmd 上运行良好,但在 Visual Studio Code 中抛出错误?
- powershell - 使用 cmd 中的参数调用 PowerShell 命令
- rxjs - 调用其他可观察对象的条件可观察对象?
- git - 有没有办法存储当前的 git 索引,`git add -u`,然后将索引恢复到存储状态?
- c - 是否有可能知道从文件中读取的长文本在 C 中会有多少个字符?
- javascript - 在对象属性上使用事件侦听器是否合适/好主意?