从 HealthKit 获取昨天的步骤

Posted

技术标签:

【中文标题】从 HealthKit 获取昨天的步骤【英文标题】:Getting yesterdays steps from HealthKit 【发布时间】:2016-09-23 05:48:56 【问题描述】:

我正在构建一个供个人使用的应用程序,但我目前正纠结于如何准确地从 healthkit 中获取昨天的步骤。然后从那里,将它放入一个变量中(应该很容易,我知道)。

我有一个 HealthKitManager 类,它从视图内部调用该函数,然后将其附加到同一视图中的变量。

我已经搜索了大多数 healthKit 问题,并获得了数据,但我认为这不是准确的数据。我昨天的手机数据是 1442 步,但它返回 2665 步。最重要的是,当我尝试将数据放入变量时,它会打印为 0。

HealthKitManagerClass

import Foundation
import HealthKit

class HealthKitManager 
let storage = HKHealthStore()

init()

    checkAuthorization()


func checkAuthorization() -> Bool

    // Default to assuming that we're authorized
    var isEnabled = true

    // Do we have access to HealthKit on this device?
    if HKHealthStore.isHealthDataAvailable()
    
        // We have to request each data type explicitly
        let steps = NSSet(object: HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)!)

        // Now we can request authorization for step count data
        storage.requestAuthorizationToShareTypes(nil, readTypes: steps as? Set<HKObjectType>)  (success, error) -> Void in
            isEnabled = success
        
    
    else
    
        isEnabled = false
    

    return isEnabled


func yesterdaySteps(completion: (Double, NSError?) -> ())

    // The type of data we are requesting (this is redundant and could probably be an enumeration
    let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)

    // Our search predicate which will fetch data from now until a day ago
    // (Note, 1.day comes from an extension
    // You'll want to change that to your own NSDate

    let calendar = NSCalendar.currentCalendar()
    let yesterday = calendar.dateByAddingUnit(.Day, value: -1, toDate: NSDate(), options: [])

    //this is probably why my data is wrong
    let predicate = HKQuery.predicateForSamplesWithStartDate(yesterday, endDate: NSDate(), options: .None)

    // The actual HealthKit Query which will fetch all of the steps and sub them up for us.
    let query = HKSampleQuery(sampleType: type!, predicate: predicate, limit: 0, sortDescriptors: nil)  query, results, error in
        var steps: Double = 0

        if results?.count > 0
        
            for result in results as! [HKQuantitySample]
            
                steps += result.quantity.doubleValueForUnit(HKUnit.countUnit())
            
        

        //I'm unsure if this is correct as well
        completion(steps, error)
        print("\(steps) STEPS FROM HEALTH KIT")
        //this adds the steps to my character (is this in the right place)
        Player.User.Gold.addSteps(Int(steps))
    
    //not 100% on what this does, but I know it is necessary
    storage.executeQuery(query)

ViewControllerClass

import UIKit
import Foundation

class UpdateViewController: UIViewController 

@IBOutlet var back: UIButton!

let HKM = HealthKitManager()
var stepsFromPhone = Double()


override func viewDidLoad() 
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    back.transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))


    HKM.yesterdaySteps() steps, error in
       self.stepsFromPhone = steps
    

    Player.User.Gold.addSteps(Int(stepsFromPhone))
    print(Player.User.Gold.getSteps(), "IN PLAYER")



override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.




来自

的输出
print(Player.User.Gold.getSteps(), "IN PLAYER")

0 IN PLAYER

输出

print("\(steps) STEPS FROM HEALTH KIT")

2665.0 STEPS FROM HEALTH KIT

所以,基本上我的问题是:

    昨天的整个过程我需要什么 NSDate()? 如何从昨天的Steps() 中获取步骤并将它们正确放入 UpdateViewController 中的变量中?

感谢您的帮助!

【问题讨论】:

您的手机是否连接了第三方追踪器? 您的实际要求是什么?例如,如果用户手动将步骤添加到 healthkit,您是否也要阅读? 我的手机没有第三方追踪器,只需阅读手机健康应用程序中的步骤即可。也不需要手动添加步骤 所以你只想得到iphone自动检测到的步骤? 基本上,是的!以后如果我想让它变得更好,我会尝试使用 fitbit API,但现在我需要围绕 HealthKit 啊哈! 【参考方案1】:

这是我在 healthStore 类中使用的方法

    func TodayTotalSteps(completion: (stepRetrieved: Double) -> Void) 

    let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) // The type of data we are requesting

    let calendar = NSCalendar.currentCalendar()
    let interval = NSDateComponents()
    interval.day = 1

    let anchorComponents = calendar.components([.Day , .Month , .Year], fromDate: NSDate())
    anchorComponents.hour = 0
    let anchorDate = calendar.dateFromComponents(anchorComponents)

    let stepsQuery = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: nil, options: .CumulativeSum, anchorDate: anchorDate!, intervalComponents: interval)

    stepsQuery.initialResultsHandler = query, results, error in
        let endDate = NSDate()

        var steps = 0.0
        let startDate = calendar.dateByAddingUnit(.Day, value: 0, toDate: endDate, options: [])
        if let myResults = results  myResults.enumerateStatisticsFromDate(startDate!, toDate: endDate)  statistics, stop in
            if let quantity = statistics.sumQuantity()
                let date = statistics.startDate
                steps = quantity.doubleValueForUnit(HKUnit.countUnit())
               // print("\(date): steps = \(steps)")
            

            completion(stepRetrieved: steps)
            
         else 

            completion(stepRetrieved: steps)
        
    
    executeQuery(stepsQuery)

这是我的使用方法

func getStepsData() 

   // I am sendng steps to my server thats why using this variable
    var stepsToSend = 0

        MyHealthStore.sharedHealthStore.todayManuallyAddedSteps( (steps , error) in
            if error != nil
                // handle error
            
            else
                // truncating manuall steps
                MyHealthStore.sharedHealthStore.TodayTotalSteps( (stepRetrieved) in
                    stepsToSend =  Int(stepRetrieved - steps)
                )
            
        )

这是上面用于手动添加步骤的函数,我们正在截断这些步骤以获得准确的步骤

    func todayManuallyAddedSteps(completion: (Double, NSError?) -> () )

    let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) // The type of data we are requesting

    let date = NSDate()
    let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
    let newDate = cal.startOfDayForDate(date)
    let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: .None) // Our search predicate which will fetch all steps taken today

    // The actual HealthKit Query which will fetch all of the steps and add them up for us.

    let query = HKSampleQuery(sampleType: type!, predicate: predicate, limit: 0, sortDescriptors: nil)  query, results, error in
        var steps: Double = 0

        if results?.count > 0
        
            for result in results as! [HKQuantitySample]
            

                // checking and adding manually added steps
                if result.sourceRevision.source.name == "Health" 
                    // these are manually added steps

                    steps += result.quantity.doubleValueForUnit(HKUnit.countUnit())
                
                else
                    // these are auto detected steps which we do not want from using HKSampleQuery
                
            
            completion(steps, error)
         else 
            completion(steps, error)
        
    
    executeQuery(query)

我希望它有所帮助。如果您遇到任何问题,请告诉我。

【讨论】:

完美运行!只是对可能遇到相同问题的其他人的警告:如果您在获取数据的函数之后将标签连接到正在更新的变量,它们可能会在查询完成之前刷新,因此看起来它没有更新.添加 2 秒后更新标签的 NSTimer 对我有用 使用计时器不如将更新放在查询的完成块中(电源/CPU 使用)——Healthkit 查询基本上是异步的,您必须使用它。【参考方案2】:

您可以使用HKStatisticsQuery

let quantityType = HKSampleType.quantityType(forIdentifier: .stepCount)!

let predicate = HKQuery.predicateForSamples(
  withStart: startDate,
  end: endDate,
  options: [.strictStartDate, .strictEndDate]
)

let query = HKStatisticsQuery(
  quantityType: quantityType,
  quantitySamplePredicate: predicate,
  options: .cumulativeSum)  (query, result, error) in
    guard let result = result, error == nil else 
      print("HeathService error \(String(describing: error))")
      return
    

    callback(result)

【讨论】:

以上是关于从 HealthKit 获取昨天的步骤的主要内容,如果未能解决你的问题,请参考以下文章

从 HealthKit 获取设备

HealthKit Swift 获取今天的步骤

从 Health Kit 获取一夜之间燃烧的卡路里

仅从 healthkit 获取 AutoDetected 活动

仅从 healthkit 获取 AutoDetected 活动

以编程方式获取/刷新 Health Kit 数据?