译文:使用Swift通过HealthKit框架进行睡眠分析

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.

我们应用的目标是使用StartStop按钮保存睡眠分析信息和获取数据。你必须在应用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

  1. We need to define two NSDate objects corresponding to the start time and the end time.(我们需要定义两个跨越开始时间和结束时间的NSDate对象)
  2. We then create an instance of HKObjectType using HKCategoryTypeIdentifierSleepAnalysis.(下来我们使用HKCategoryTypeIdentifierSleepAnalysis来创建HKObjectType实例)
  3. 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记录睡眠数据。用户可以个性化的展示躺在床上或者睡眠的时间段。所以我们将要创建躺在床上和睡眠的重叠时间。)
  4. Finally, we’ll save the object using saveObject of HKHealthStore.(最后我们需要使用HKHealthStoresaveObject来保存对象)

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来过滤获取的数据,使用startDateendDateNSDate对象检索你可能需要的时间范围。你可能也需要创建一个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项目,你可以在这里获取。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容

  • PLEASE READ THE FOLLOWING APPLE DEVELOPER PROGRAM LICENSE...
    念念不忘的阅读 13,446评论 5 6
  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,437评论 0 23
  • 在一座深山的南坡顶上,有一块大石头。 石头左边的枯草堆里住着一窝刺猬——刺猬爸爸,刺猬妈妈,还有一只刺猬宝宝。 石...
    茧破阅读 475评论 0 3
  • 十点左右,做几组深刻的瑜伽,清晨,走出大门外,心儿欢呼雀跃,身体轻快得想要飞飘起来,肆意抬起双臂,飞啊,飞啊,绕到...
    冬天的雪娃娃快乐阅读 211评论 0 0
  • 首先祝贺你经历了高考顺利进入大学,算是对你前阶段努力的回报,相信你也一定对大学充满着无限憧憬,大学是一个可以自由发...
    Hades_阅读 181评论 0 0