如何使用Swift来学习HealthKit中的sleep analysis
如今,有关睡眠的问题变得流行起来,用户不仅对他们什么时候入睡感兴趣,更关心的是一段时间之后,应用根据收集的数据所得出的结果。随着硬件和手机技术的发展,有关科技与睡眠的话题变的极其受关注。
苹果通过内建的Health应用,提供了一种简单酷炫的方式来安全的访问和存储用户的健康信息。你不仅可以用HealthKit来开发一个健康类应用,还可以利用framework来获取有关sleep analysis的数据。
在这个教程里,我将带你快速了解HealthKit的框架,并且演示如何开发一个简单的sleep analysis应用。
简介
HealthKit框架提供了一种结构HealthKit store,利用它你可以把信息存储在一个加密的数据库里。你可以通过HKHealthStore
这个类来访问数据库。iPhone和Apple Watch分别拥有自己的HealthKit store,并且里面的数据在iPhone和Apple Watch之间是同步的。但是有一点需要注意,在Apple Watch中,为了节省空间,旧的数据是会被清除的。而iPad是不支持Health Kit和Health应用的。
你如果想开发一个iOS或者watchOS的应用,那么HealthKit是一个强大的工具。HealthKit就是被设计用来管理来自不同资源的数据,而且可以根据用户的设置来合并这些数据。应用还可以访问原始数据,并且合并他们。身体指标,健康指标以及营养指标,这些数据都可以被用来做sleep analysis。
接下来,你将会了解如何使用HealthKit框架去保存和访问iOS中的sleep analysis数据。以下的内容同样适用于watchOS。这个教程是基于Swift 2.0 和 Xcode 7. 请确保你是用Xcode 7或者以上的版本。
在这之前,下载初始工程文件并且解压缩。我已经为你创建了基本的界面。当你运行这个工程的时候,你会看到一个计时器的界面,点击开始按钮,计时器开始运行。
学习HealthKit框架
这个教程的目标是开发一个简单的应用,可以存储sleep analysis的数据,以及通过开始
& 停止
按钮来获取数据。第一步,你必须获得HealthKit的许可。在你的工程文件中,选择Current Target选项,选择capabilities,并且打开对应的HealthKit。
下一步,你需要在ViewController
中创建一个HKHealthStore
实例,下面是代码:
let healthStore = HKHealthStore()
接着,我们使用创建的HKHealthStore
实例来访问HealthKit store。
就像刚才提到的一样,HealthKit允许用户去选择是否其他程序可以获取他们的健康数据。所以在你访问(读/写)sleep analysis数据之前,你需要获取用户的许可。怎么做呢?第一步,导入内建的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")
}
}
}
以上的代码将会请求获取用户的HealthKit权限,用户可以选择允许或者拒绝。在完成闭包中,你可以做更多的处理,例如获取权限成功怎么办,出现错误应该怎么办。用户有可能拒绝你的访问权限,所以你必须要在完成闭包中小心的处理这些特殊情况。
为了教程的顺利进行,你必须要选择允许选项来使应用获得你手机上的健康数据。
写入sleep analysis数据
首先,我们如何得到sleep analysis的数据呢?根据苹果的官方文档,每一个sleep analysis的样本只包含一个值。这个值表示了用户在床上的时间和睡眠的时间,HealthKit用了二个或者二个以上的样本,每一个样本都包含与其它样本重叠的时间。通过这些样本的开始时间和结束时间,我们能够计算出这样的一些数据:
- 用户入睡用了多长时间
- 用户睡眠时间与用户在床上时间的比例
- 用户醒来后直到下床的时间
- 用户在床上和用户睡眠的总共时间
简单来说,根据以下方法,我们能够把sleep analysis数据存入到HealKit store中。
- 首先根据开始时间和结束时间,定义两个
NSDate
对象 - 利用
HKCategoryTypeIdentifierSleepAnalysis
创建HKObjectType
实例 - 创建一个
HKCategorySample
实例。每一个样本代表了用户在床上或者睡眠的时间长度。所以我们创建一个在床上的样本和睡眠的样本,这两个样本有着冲重叠的时间。
4.最后,我们用HKHealthStore
的saveObject
方法来保存这个对象。
如果把上述的4步转化为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, startDate: self.alarmTime, endDate: self.endTime)
healthStore.saveObject(object2, withCompletion: { (success, error) -> Void in
if error != nil {
// something happened
return
}
if success {
print("My new data (2) was saved in HealthKit")
} else {
// something happened again
}
})
}
}
当想要存储sleep analysis数据到HealthKit的时候,我们可以调用这个方法。
读取sleep analysis数据
为了能够读取sleep analysis的数据,我们需要执行一个查询操作。首先,定义一个HKObjectType
类别,指明类别是HKCategoryTypeIdentifierSleepAnalysis
。接下来可以用predicate去过滤得到的数据,可以根据startDate
和endDate
这两个NSDate类来得到你想要的时间区间。最后还创建一个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)
}
}
这个方法用来查询HealthKit,并且得到所有的sleep analysis数据,并且把这些数据按照降序排序。接下来每一个查询都以startDate和endDate的形式被打印出来。例如In Bed 或者是 Asleep。 在创建query对象时,我在limit参数里传入了30,表示我想得到最后30条记录的样本。当然了,你可以用在predicate参数中,传入你自己定义的predicate对象,这样你就可以自定义startDate和endDate了。
应用测试
在这个Demo应用中,我用了一个NSTimer来模拟真实的时间,当你按下开始按钮后,计时器会运行。两个NSDate
对象在开始和结束按钮被按下时分别被创建,这样我们就可以模拟记录sleep analysis数据了。在stop
方法中,你可以调用saveSleepAnalysis()
和retrieveSleepAnalysis()
方法来存储和读取睡眠数据。
@IBAction func stop(sender: AnyObject) {
endTime = NSDate()
saveSleepAnalysis()
retrieveSleepAnalysis()
timer.invalidate()
}
在你的工程文件中,你不用完全遵循我的代码,你也可以自由的改变startDate和endDate这两个NSDate对象去存储用户在床上的时间和睡眠时间。
好了,现在你可以运行你的程序,开始计时。让我们等上几分钟,然后点击停止按钮。之后,我们可以打开自带的Health应用。你会发现睡眠数据已经出现在界面中了。
小贴士时间
HealthKit是为开发者用来提供一个通用的平台,通过这个平台,我们可以轻松的共享,获取用户数据,同时并且避免了重复或者前后矛盾的数据。在Apple审核应用规则中明确规定了,必须要清楚明确的请求获取用户的Health权限,如果不这么做,很可能你的应用会被拒绝上架。
如果一个应用试图在Health应用中存入虚假的或者不正确的数据,同样会被拒绝上架。这意味着,像本教程中使用非常简单的算法去计算不同的健康数据,这样也是不行的。你应该利用内建的传感器去获取数据,计算数据,这样,你获得的数据会更加真实有效。
如果你想获得完全的Xcode工程,你可以从这里获取。