Using Sleep Analysis in HealthKit With Swift
使用Swift通过HealthKit框架进行睡眠分析
作者:ANUSHK MITTAL,原文链接,原文日期:2016-06-18
Today, Sleep Revolution is a fad and users are curious than ever to not only know about the the time they’ve been asleep but also to analyze the data gathered over a period to reveal their sleeping trends. Advancements in technology including hardwares, and mobiles in particular have brought this seemingly ever-growing subject into a whole new light.
目前,睡眠革命成为一种狂潮,人们比以往更加关注,不仅要知道他们睡眠的时间,还要分析一段时间内收集的数据以观察睡眠趋势。随着科技特别是硬件和手机的不断发展,人们看到了新的曙光。
Apple provides a cool way to communicate with user’s personal health information in a secure manner and store the information securely through the built-in Health app. Not only can you use HealthKit to build a fitness app
, the framework also allows you access sleep analysis data.
苹果提供了一种很炫酷的方式来让用户个人健康信息在安全的方式下传递,并且通过内置的Health应用安全的存储信息。你不仅可以使用HealthKit创建一个健康应用,也使用框架访问睡眠分析数据。
In this tutorial, I will give you a quick introduction to the HealthKit framework, and demonstrate how you can build a simple app for sleep analysis.
在这篇指南,我会让你对HealthKit框架进行一个快速的入门,并且演示如何创建一个睡眠分析的简单应用。
Introduction
介绍
The HealthKit framework provides a structure to save data in an encrypted database called the HealthKit store. You can access this database using the HKHealthStore
class. Both iPhone and Apple Watch have their own HealthKit store. Health data is synced between Apple Watch and iPhone; however, old data is periodically purged from Apple Watch to save space. HealthKit and the Health app are unavailable on iPad.
HealthKit框架提供了一种结构来存储数据到被称为HealthKit store的加密数据库。你可以使用HKHealthStore
类来访问这个数据库。iPhone和Apple Watch都有他们各自的HealthKit store。健康数据在Apple Watch和iPhone之间进行同步;然而,旧的数据会被定期清理以节省空间。HealthKit和Health应用均不支持iPad。
HealthKit is a powerful tool if you want to create an iOS or watchOS app based on health data. It is designed to manage data from a wide range of sources, automatically merging the data from different sources based on user’s preferences. Apps can also access the raw data for each source, and merge the data themselves. Not only for body measurements, fitness or nutrition, the data can also be used for sleep analysis.
如果你想开发一款基于健康数据的iOS或watchOS应用,那么HealthKit无疑是一个强有力的工具。HealthKit被设计用于管理大范围的数据来源,并根据用户设定自动合并处理。应用也可以访问每一个来源的raw数据,并且自己合并数据。这些数据不仅用于身体测量、健康或营养,还可以被用来做睡眠分析。
For the rest of the article, I will show you how to make use of the HealthKit framework for saving and accessing sleep analysis data on iOS. The same methods are applicable for watchOS applications as well. Please note that the tutorial is written using Swift 2.0 and Xcode 7. So make sure you use Xcode 7 (or up) to follow the tutorial.
文章的剩下部分,我将向你展示如何利用HealthKit框架来保存和访问iOS上的睡眠数据。在watchOS上可以用相同的方法。请注意这篇指南是基于Swift 2.0和Xcode 7写作的。所以请您遵守指南使用Xcode7(或以上)版本。
Before moving on, download the starter project and unzip it. I have already created the user interface with basic functionalities for you. When you run the starter project, you will see a timer UI that shows the time elapsed after you push the start button.
在开始之前,下载上手项目并解压。我已经为你创建了基本功能的用户界面。当你运行上手项目,你按下按钮后将会看到按下按钮之后经过时间的计数器界面。
Working with the HealthKit Framework
使用HealthKit框架
Our aim with the application is to save sleep analysis information and retrieve the data using the Start
& Stop
buttons. To use HealthKit, you must begin by granting the HealthKit capabilities to your app bundle. In your app project, navigate to your current target -> capabilities and turn on HealthKit.
我们应用的目标是使用Start
和Stop
按钮保存睡眠分析信息和获取数据。你必须在应用bundle中打开允许获取HealthKit的权限方可使用HealthKit。在你的应用项目,选择当前的target -> capabilities并且打开HealthKit。
Next, you will need to create an instance of HKHealthStore in the ViewController class using the following code:
接下来,你需要使用下面的代码在ViewController
中创建一个HKHealthStore
实例:
let healthStore = HKHealthStore()
Later we will use the HKHealthStore
instance to access the HealthKit
store.
然后我们使用HKHealthStore
实例访问HealthKit store。
As mentioned, HealthKit grants users control over their health data. So you have to first request users’ permission before you can gain access (write/read) to the Sleep Analysis data of the user. To do so, first import the built-in HealthKit
framework and update the viewDidLoad
method like this:
需要提及一点的是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")
}
}
}
This code will prompt the user to allow or deny the requested permissions. With the completion block, you can handle success or error and get the final result. It is not necessary that the user grants your app all the requested permissions. You must handle the errors gracefully in your app.
这段代码可以提示用户允许或者拒绝权限请求。通过completion block,你可以处理success或者error信息并且得到最后的结果。并不需要用户获得所有的请求权限。你必须在应用优雅的处理错误信息。
But for testing purpose, you must have to select the “Allow” option to grant the app permission to access the health data on your device.
但是对于测试目的,你必须选择“Allow”选项来授权应用获取你设备上健康数据的访问权限。
Writing Sleep Analysis Data
存储睡眠分析数据
First, how can we retrieve the sleep analysis data? According to Apple’s documentation, each sleep analysis sample can have only one value. To represent the user being both in bed and asleep, HealthKit uses two or more samples with overlapping times. By comparing the start and end times of these samples, apps can calculate a number of secondary statistics:
首先,我们如何获取睡眠分析数据?根据苹果的文档,每一个睡眠分析样本只有1个值。为了展示用户躺在床上和睡眠的时间,HealthKit使用2个或更多的重叠时间。通过比较开始和结束的样本,应用可以计算出大量的次级统计数据:
- the amount of time it takes for the user to fall asleep(用户睡着的时间)
- the percentage of time in bed that the user actually sleeps(用户在床上真正睡眠时间所占的比例)
- the number of times the user wakes up while still in bed(用户躺在床上醒来的次数)
- the total amount of time spent both in bed and asleep(躺在床上和睡眠的总时间)
In brief, you follow the below approach to save sleep analysis data to the HealthKit store:
简而言之,你可以遵循下面方式来保存睡眠分析数据到HealthKit sotore
:
- We need to define two
NSDate
objects corresponding to the start time and the end time.(我们需要定义两个跨越开始时间和结束时间的NSDate
对象) - We then create an instance of
HKObjectType
usingHKCategoryTypeIdentifierSleepAnalysis
.(下来我们使用HKCategoryTypeIdentifierSleepAnalysis
来创建HKObjectType
实例) - We need to create a new object of the
HKCategorySample
type. You normally use category samples to record sleep data. Individual samples represent time periods when the user is in bed or asleep. So we will create both an in-bed sample and an asleep sample with overlapping times.( 我们需要创建一个HKCategorySample
类型。你通常需要使用category samples记录睡眠数据。用户可以个性化的展示躺在床上或者睡眠的时间段。所以我们将要创建躺在床上和睡眠的重叠时间。) - Finally, we’ll save the object using
saveObject
ofHKHealthStore
.(最后我们需要使用HKHealthStore
的saveObject
来保存对象)
Editor’s note: For the type of the sample, you can look it up in HealthKit Constants Reference.
编者注: 对于样本的类型, 你可以在HealthKit Constants Reference里面查询.
If you translate the above into Swift, here is the code snippet to save sleep analysis data for both in bed and asleep values. Please insert the method in the ViewController
class:
如果你将上面所述转换为Swift,这段代码可以保存在床上和睡眠的分析数据。请添加该方法到ViewController
类:
func saveSleepAnalysis() {
// alarmTime and endTime are NSDate objects
// alarmTime和endTime是NSDate对象
if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) {
// we create our new object we want to push in Health app
//我们创建新对象push到Health应用
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
}
})
}
}
This function can be called at the time we want to save the Sleep Analysis data to HealthKit.
每当我们想要保存睡眠分析数据到HealthKit的时候都可以调用。
Reading Sleep Analysis Data
读取睡眠分析数据
To read the sleep analysis data, we will need to create a query. You should begin by defining the HKObjectType
category to HKCategoryTypeIdentifierSleepAnalysis
. You may also want to use a predicate to filter the retrieved data using startDate
and endDate
which are NSDate objects corresponding to the time range that you may want to retrieve. You will also need to create a sortDescriptor
for sorting the retrieved queries to select the desired result.
为了获取睡眠分析数据,我们需要创建一个查询(query)。你应该通过定义HKCategoryTypeIdentifierSleepAnalysis
的类目HKObjectType
。你可能也需要使用predicete来过滤获取的数据,使用startDate
和endDate
NSDate对象检索你可能需要的时间范围。你可能也需要创建一个sortDescriptos
来对获取的查询进行排序以得到想要的结果。
Your code for retrieving sleep analysis data should look like this:
你获取睡眠合理数据的代码可能如下:
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
// 首先使用一个sortDescriptos获取最近的数据
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
// we create our query with a block completion to execute
//我们创建一个blcok来查询
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)
}
This code queries the HealthKit to get all Sleep Analysis data and then sorts it down to descending order. Then each query is printed with the startDate and endDate along with the type of value i.e. In Bed or Asleep. I have set the limit to 30 to retrieve the last 30 recorded samples. You can also use the predicate method to choose your custom start and end dates.
这段代码通过HealthKit获得全部睡眠分析数据,然后做降序。接下来对每一个查询按照在床上或者睡眠的开始和结束日期打印值。我设置限制最多30条以获取最近的30条数据。你也可以使用predicate方法来自定义开始和结束日期。
App Testing
App 测试
For the demo application, I have used an NSTimer to show the time elapsed since you push the start button. The NSDate
objects are created on the start and end buttons to save sleep analysis data as the elapsed time. In the stop
action method, you can invoke the saveSleepAnalysis()
and retrieveSleepAnalysis()
methods to save and get the sleep data.
对于Demo应用,我已经用一个NSTimer来展示自从你按下开始按钮所经过的时间。NSDate
对象在按下开始按钮的创建,在按结束按钮的时候保存睡眠分析数据。在stop方法中,你可以调用saveSleepAnalysis()
和retrieveSleepAnalysis()
方法来保存和获取睡眠数据。
@IBAction func stop(sender: AnyObject) {
endTime = NSDate()
saveSleepAnalysis()
retrieveSleepAnalysis()
timer.invalidate()
}
In your apps, you may want to change the NSDate objects to choose relevant start and end times (probably different) for saving the in bed and asleep values.
在你的应用中,你可能想要想要NSDate对象来选择有意义的开始和结束的时间段(可能不同)来存储躺在床上和睡眠的值。
Once you’ve made the changes, you can run the demo app and start the timer. Let it run for a few minutes and then tap the Stop button. After that, open the Health app. You’ll find the sleep data in there.
一旦你做出改变,你可以运行demo应用并开启计时器。让它跑几分钟,然后按下stop按钮。接下来打开Health应用,你将会在里面找到睡眠数据。
Some Advices for HealthKit Apps
对HealthKit 应用的一些建议
HealthKit is designed to provide a common platform for app developers to share and access user’s data easily and avoids any possible duplication or inconsistency in data. Apple review guidelines are very specific for apps using the HealthKit and requesting read/write permissions without a clear demonstration of their use might result in the app being rejected.
HealthKit被设计为公共平台让应用开发者更方便分享和访问避免可能的重复和不一致的数据。苹果审核指南中对于使用HealthKit和请求读写权限,但是没有一个明确的声明可能会被拒绝。
Apps that save fake or incorrect data to the Health App would also be rejected. This means, that you cannot be naïve with your algorithms for calculating different health values like sleep analysis in this tutorial. You should try using the inbuilt sensor data for reading and manipulating any parameters to avoid calculating false data.
应用保存无效或者错误的数据到Health App也可能会被拒绝。这就意味着,你不能像指南中的睡眠数据一样用你的算法计算不同的健康值。你应该尝试去读和操作内置的传感器数据,以避免错误的数据。
For the complete Xcode project, you can get it here.
对于完整的Xcode项目,你可以在这里获取。