作者:ANUSHK MITTAL,时间:2016/6/18
翻译:BigNerdCoding, 如有错误欢迎指出。原文链接
当今关于睡眠革命的话题的讨论非常热烈,人们也比以往任何时候都更加的好奇。他们关心的内容不仅有在什么时候他们睡着了,还有那些通过分析过去一段时间以来自身睡眠数据所揭示出来的睡眠趋势。随着包括硬件等技术的进步,尤其是智能手机的普及将这个看似正在不断升温的话题带到了一个全新的境界。
苹果公司提供了一种非常酷的方式来安全的与个人健康信息进行交互并且通过预装的内置Health应用将这些健康信息存储起来。通过HealthKit框架你不仅可以创建一个身体素质的应用,还可以访问到用户的睡眠分析数据。
在这篇教程中,我会对HealthKit框架做一个简介,并且演示如果使用该框架创建一个睡眠分析的简单应用。
简介
HealthKit框架提供了数据结构以便我们能够将数据存储到名为HealthKit store的加密数据库中。我们可以通过HKHealthStore类来对该加密数据库进行访问。iPhone和iWatch都有自己的HealthKit store,两者之间的健康数据会进行同步。然而,对iWatch中的老旧数据进行定时清理有助于节省iWatch的空间。HealthKit和Health应用并不存在于iPad中。
如果你想创建一个iOS或者watchOS上基于健康数据的应用话,HealthKit对你来说将是一个强大的工具。该框架被设计用来管理那些来源广泛的数据,并且基于用户的偏爱对这些来源不同的数据进行合并。应用也可以访问这些来源不同的元素数据,并自身对其进行合并处理操作。除了用于对身体的测量、体质和营养的分析,这些数据还可以用来对用户的睡眠进行分析。
在本文的剩余部分,我将会为你演示在iOS平台上如何使用HealthKit框架来保存和访问睡眠分析数据。这些方法同样适用于watchOS平台。请注意教程中的实例Xcode7上面使用Swift2.0实现的,所以在跟随我脚步之前请确保你的Xcode是7以上的版本。
在我们进行下一步之前,请先下载起始工程并将其解压。我已经在工程里面为你创建好了带有基本功能的用户界面。当你运行工程的时候,你将会看见一个计时功能的UI界面(当你按下开始按键的时候会统计时间)。
使用HealthKit框架
我们应用的目标是通过Start和Stop按键保持睡眠分析信息并取回该数据。为了使用HealthKit,首先你必须让你的应用获得授权。在你的app工程里面选中当前目标,然后选择capabilities并打开HealthKit功能。
下一步你需要使用下面的代码在ViewController类里面创建HKHealthStore类实例:
let healthStore = HKHealthStore()
在后面你将会使用这个HKHealthStore实例来访问HealthKit store。
正如前面提到的,HealthKit需要用户授权才可以控制他们的健康数据。所以在获得对用访问(读写)用户的健康数据之前,我们首先需要请求用户的授权同意。为了实现目的,我们首先导入HealthKit框架然后如下修改viewDidLoad函数里面的代码:
override func viewDidLoad() { super.viewDidLoad() let typestoRead = Set([HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)!]) let typestoShare = Set([HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)!]) self.healthStore.requestAuthorizationToShareTypes(typestoShare,readTypes: typestoRead) { (success,error) -> Void in if success == false { NSLog(" Display not allowed") } } }
这段代码将会提示用户允许或者拒绝用户的授权请求。在completion block里面你可以对成功或者错误进行处理并且得到最终的结果。并不是所有的用户都会给予你相应的权限,你需要妥善的处理好用户拒绝的情况。
但是为了测试的目的,你必须选择允许应用获得访问设备中健康数据的的权限。
写入睡眠分析数据
首先,我们如何检索到睡眠分析数据呢?根据苹果官方的文档,每一个睡眠分析样本都有一个唯一值。为了表示用户在床上和睡觉两种状态,HealthKit使用了两个以上时间可能重叠的样本。通过比较这些样本的起始和终止时间,app可以计算出下面这些相关的统计数据:
简单来说,你可以通过下面的方法来将睡眠数据保存到HealthKit store:
我们定义两个对应开始时间和结束时间的NSDate对象。
使用HKCategoryTypeIdentifierSleepAnalysis来创建一个HKObjectType实例
我们需要创建一个HKCategorySample类型的对象。你通常会使用类别样本来纪录这些睡眠数据。使用单个样本来表示用户在床上或者睡着了的时间段。所以我们创建一个在床上以及一个睡着了的样本,两种的时间段有重叠。
最后,我们使用HKHealthStore中的saveObject方法来保存对象。
编辑提醒:针对样本的类型,你可以查看HealthKit Constants Reference来了解。
如果你将上面的方法转化为Swift语言,下面就是实现上面保存在床上和睡着了两个样本数据的代码片段。请将这些方法插入到ViewController类中:
func saveSleepAnalysis() { //alarmTime and endTime are NSDate objects if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) { // we create our new object we want to push in Health app let object = HKCategorySample(type:sleepType,value: HKCategoryValueSleepAnalysis.InBed.rawValue,startDate: self.alarmTime,endDate: self.endTime) //at the end,we save it healthStore.saveObject(object,withCompletion: { (success,error) -> Void in if error != nil { //something happened return } if success { print("My new data was saved in HealthKit") } else { //something happened again } }) let object2 = HKCategorySample(type:sleepType,value: HKCategoryValueSleepAnalysis.Asleep.rawValue,endDate: self.endTime) healthStore.saveObject(object2,error) -> Void in if error != nil { //something happened return } if success { print("My new data (2) was saved in HealthKit") } else { //something happened again } }) } }
这个函数可以在我们需要将睡眠分析数据保存到HealthKit中的时候调用。
读取睡眠分析数据
为了读取出睡眠分析数据,我们需要创造一个队列。首先你需要定义一个HKCategoryTypeIdentifierSleepAnalysis类别的HKObjectType对象。你可能会使用起始和结束数据作为条件来筛选位于这段时间的数据。你还需要创建一个sortDescriptor来对查询出来的数据进行排序。
检索睡眠数据的代码如下:
func retrieveSleepAnalysis() { //first,we define the object type we want if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) { //Use a sortDescriptor to get the recent data first let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate,ascending: false) //we create our query with a block completion to execute let query = HKSampleQuery(sampleType: sleepType,predicate: nil,limit: 30,sortDescriptors: [sortDescriptor]) { (query,tmpResult,error) -> Void in if error != nil { //something happened return } if let result = tmpResult { //do something with my data for item in result { if let sample = item as? HKCategorySample { let value = (sample.value == HKCategoryValueSleepAnalysis.InBed.rawValue) ? "InBed" : "Asleep" print("Healthkit sleep: \(sample.startDate) \(sample.endDate) - value: \(value)") } } } } //finally,we execute our query healthStore.executeQuery(query) } }
上面的代码会查出所有的睡眠数据并按照降序的方式进行排列。然后每一个查询结果都按照:起始时间、结束时间、类型值(例如:在床上还是睡着了)的形式打印出来。我在查询中通过设置limit只取最后的30个样本。你也可以通过predicate方法选择你自定义的起始和结束时间。
App测试
在演示应用中,我使用了NSTimer来纪录点击开始按键后流失的时间。当点击开始和结束按键的时候都会创建一个NSDate对象,并且将经过的时间作为睡眠分析数据进行保存。在点击结束按键的时候可以触发调用saveSleepAnalysis()和retrieveSleepAnalysis()方法取保存和查询睡眠数据。
@IBAction func stop(sender: AnyObject) { endTime = NSDate() saveSleepAnalysis() retrieveSleepAnalysis() timer.invalidate() }
在你自己的app中,你可能会改变NSDate对象并选择与之相关的起始和结束时间来保存在床上和睡觉的值。
如果你做出了修改的话,你可以允许程序并点击开始按键开始计时。让程序运行几分钟然后点击停止按键。然后你可以打开Health应用,你就可以看见睡眠数据了。
对使用HealthKit应用的一些建议
HealthKit是设计用来为app开发人员提供一个更加方便分享和访问用户数据的公共平台,并且避免了任何数据的重复和不一致的可能性。在苹果应用审核指导中详细的表明了:那些使用了HealthKit并且要求获取读写权限的应用如果没有清晰的表明的话那么很有可能会审核不过。
如果应用保存一些假的或者不正确的数据到Health应用中的话也有可能无法审核通过。这意味着,你不能想本文中那样很天真的使用一些算法去计算不同的健康数据。你应该使用内置的传感器去读取和处理那些数据和参数,从而避免计算错误数据。
完整的Xcode工程可以在这里下载得到。