从 HealthKit 查询更新 SwiftUI

Posted

技术标签:

【中文标题】从 HealthKit 查询更新 SwiftUI【英文标题】:Updating SwiftUI from HealthKit Query 【发布时间】:2021-05-09 13:22:12 【问题描述】:

我想在 SwiftUI 中通过 ContentView 输出变量“healthStore.valueTest”。

类 healthStore 的结构如下:

class HealthStore 
    
    var healthStore: HKHealthStore?
    var query: HKStatisticsQuery?
    var valueTest: HKQuantity?
    
    
    init() 
        if HKHealthStore.isHealthDataAvailable() 
            healthStore = HKHealthStore()
        
    
    
    func calculateBloodPressureSystolic() 
        
        guard let bloodPressureSystolic = HKObjectType.quantityType(forIdentifier: .bloodPressureSystolic) else 
            // This should never fail when using a defined constant.
            fatalError("*** Unable to get the bloodPressure count ***")
        

        
//        let startDate = Calendar.current.date(byAdding: .day, value: -7, to: Date())
//        let anchorDate = Date.mondayAt12AM()
//        let daily = DateComponents(day: 1)
//        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictStartDate)
        
        query = HKStatisticsQuery(quantityType: bloodPressureSystolic,
                                                quantitySamplePredicate: nil,
                                                options: .discreteAverage) 
                                                query, statistics, error in
            
                                                DispatchQueue.main.async
                                                    self.valueTest = statistics?.averageQuantity()
                                                

                                                    
        
        
        healthStore!.execute(query!)
        
    

ContentView 构建如下:

import SwiftUI
import HealthKit

struct ContentView: View 
    
    private var healthStore: HealthStore?
               
    init() 
        healthStore = HealthStore()
    
    
    
    var body: some View 
        Text("Hello, world!")
            .padding().onAppear()
                
        if let healthStore = healthStore 
            healthStore.requestAuthorization  success in
                if success 
                    healthStore.calculateBloodPressureSystolic()
                    print(healthStore.query)
                    print(healthStore.valueTest)
                    
                
            
        
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    

变量 self.valueTest 的值在进程 DispatchQueue.main.async 中分配。尽管如此,当通过 ContentView 查询时,我只得到一个 nil。

【问题讨论】:

【参考方案1】:

您可以设置您的HealthStore 类并将其用作环境对象。假设您的应用使用 SwiftUI 生命周期,您可以在应用的 @main 入口点将 HealthStore 注入到环境中。

import SwiftUI

@main
struct NameOfYourHeathApp: App 

    let healthStore = HealthStore()

    var body: some Scene 
        WindowGroup 
            ContentView()
                .environmentObject(healthStore)
        
    

将您的 HealthStore 类更改为此。 (我在下面的示例中删除了您注释掉的代码)

import HealthKit

class HealthStore: ObservableObject 

    var healthStore: HKHealthStore?
    var query: HKStatisticsQuery?
    var valueTest: HKQuantity?

    init() 
        if HKHealthStore.isHealthDataAvailable() 
            healthStore = HKHealthStore()
        
    

    // I moved the HealthStore conditional check out of your View logic 
    // and placed it here instead.
    func setUpHealthStore() 
        let typesToRead: Set = [
            HKQuantityType.quantityType(forIdentifier: .bloodPressureSystolic)!
        ]

        // I left the `toShare` as nil as I did not dig into adding bloodpressure reading to HealthKit.
        healthStore?.requestAuthorization(toShare: nil, read: typesToRead, completion:  success, error in
            if success 
                self.calculateBloodPressureSystolic()
            
        )

    

    func calculateBloodPressureSystolic() 
        guard let bloodPressureSystolic = HKObjectType.quantityType(forIdentifier: .bloodPressureSystolic) else 
            // This should never fail when using a defined constant.
            fatalError("*** Unable to get the bloodPressure count ***")
        
        query = HKStatisticsQuery(quantityType: bloodPressureSystolic,
                                  quantitySamplePredicate: nil,
                                  options: .discreteAverage) 
            query, statistics, error in

            DispatchQueue.main.async
                self.valueTest = statistics?.averageQuantity()
            
        

        healthStore!.execute(query!)
    

然后像这样在你的ContentView 中使用它。

import SwiftUI

struct ContentView: View 

    @EnvironmentObject var healthStore: HealthStore

    var body: some View 
        Text("Hello, world!")
            .onAppear 
                healthStore.setUpHealthStore()
            
    

我没有在 .plist 文件中设置适当的权限,但您还需要设置健康共享使用说明和健康更新使用说明。我假设您已经这样做了,但我只是想提一下。

【讨论】:

当我在控制台打印变量 healthStore.valueTest 时,我只得到一个 nil。

以上是关于从 HealthKit 查询更新 SwiftUI的主要内容,如果未能解决你的问题,请参考以下文章

如何从 healthkit 框架中读取上次更新的洗手数据?

如何从 healthkit 框架中读取上次更新的洗手数据?

应用程序在后台时如何查询 HealthKit (HKWorkout) 更新?

HealthKit 读取数据心率和血压“同步后的最新更新”

HealthKit 读取数据心率和血压“同步后的最新更新”

从 HealthKit 查询游泳距离