从零开始一步步学习HealthKit:第一部分

说明

本文从http://content.catalyze.io/blog/getting-started-with-apple-healthkit-part-1翻译而来,如有语法,词汇的不足,敬请批评指正,原作者保留转载,修改权力。

也许HealthKit和相关的健康应用是苹果iOS8最令人激动的更新。通过健康类的API,开发者可以将健康相关类型的数据保存在一个集中的地方,也可以访问这些数据。这给人了无限的联想空间:首先,苹果健康类型的大框架下决定了那些应用可以被下载。其次,这些健康类型的app允许用户在HealthKit Store里整体的,直观的查看到他们所拥有的数据。

这就使得用户不用担心该找那些应用去收集那些数据了,也使得开发者不用去考虑与其他应用进行通信的问题,HealthKit把这一切都给封装好了。在接下来了的两个部分中我们将讨论HealthKit的许多功能,以及使用这些功能去创建一个简单的Healthkit Demo。今天的第一部分我们将整体上了解下HealthKit的一些接口,提供一些代码片段等等,在下一节我们讲着重讲解下更多的技术细节问,进而构建出一个完整的App 例子。

关于许可

利用HealthKit,苹果将用户的健康数据保存的非常的精细化。在开发者使用HealthKit之前,你需要获取你能够读写数据类型的权限。例如你只想列出用户的生日和体重信息,想记录用户的体温信息,那么你就得对生日和体重获取只读权限,对温度获取读写权限。

一旦获取读取权限成功,用户手机上将会显示一个允许那些类型的数据被存取的对话框,并且对一些单一的功能提供授权。如果你期望获取写入的权限,那么你将在你的应用里无法获取数据被更改的通知。然后,当你期望获取读取的权限的时候,将不会发送授权的通知,或者用户在弹出Alert通知的时候,选择了取消。

隐藏用户的请求能够有效的保护用户的信息,例如,当你想要记录用户的血糖值并且用户拒绝的时候,你就能假定用户是患有糖尿病的。保护这些信息是苹果HealthKit保护终端用户隐私的一个重要的地方。

在HealthKit中,所有的许可都在HKHealthStore里。在你的应用中,最好只保存一个HKHealthStore的实例,这样就能够只用向用户提出一次的权限访问请求,否则将会不断的向你的应用提出读取权限请求,导致你的应用程序混乱。

同步HealthKit的数据将对你的健康类型的应用的功能进行削弱。因此在不进行任何详细说明的前提下去获取HealthKit 的数据是非常不明智的,这是个非常好的练习的机会,尤其是你在有用户登录的时候,先让用户登录应用,进而去熟悉下你的应用。了解那些类型的数据将被收集。然后可能将在第一时间获取存取权限,一旦你正确的获取了读取权限了之后,你就能够开始收集相关的数据点了。

关于单位

HealthKit中最基本的构造就是测量单位,你能够无限制的向用户收集数字,但是这些数字离开单位的后缀是毫无意义的。HealthKit中与单位相关的类是HKUnit,这个类使用起来非常的直接,并且已经包括很多相关的单位类型,能够快速的帮你创建你想要的单位。如果没有帮助信息找不到你想要的单位,你可以通过以下方式去获取你想要的单位类型:

HKUnit *gram = [HKUnit gramUnit];

HKUnit *mgPerdL = [HKUnit unitFromString:@"mg/dL"];

 

单位的选择应当贴合你的数据类型。例如,你不会选择克作为测量温度的单位,并且也不太可能选择开氏温度单位去度量体温。作为体温比较适合的单位只能是华氏或者摄氏比较好些。这个根据用户的第一选择来去确定,HealthKit不参与。HealthKit中也有一些将公制的单位与其他系统制式的单位进行转换的API,这篇文章中不做讨论。

关于数量

现在我们构建好了单位,也同时收集了一个数字,那么我们现在就得把两者进行关联下。在HealthKit中关联一个值与单位的类就是Quantity。以下是HKQuantity类型的构建:

HKQuantity *quantity = [HKQuantity quantityWithUnit:gram doubleValue:120.0];

 

虽然简单,但是quantity是非常强大的,而且也是单位换算的基础。

单位换算

单位换算中两个直接关联的类是HKQuantity和HKUnit。当然你不能够把任意类型的单位转移到另外的任意类型上,那样子的话会被系统抛出一个异常。你可以选择询问HealthKit是否允许转换,然后在去进行转换的工作:

[quantity isCompatibleWithUnit:[HKUnit unitFromString:@"kg"]]; //this one returns YES

double kg = [gram doubleValueForUnit:[HKUnit unitFromString:@"kg"]];

 

例程

我们从用户那里获取了数据,单位,以及数量,那么我们现在就要创建一个保存在HealthKit数据上的对象。在HealthKit中,只有通过例程去存储相应的HealthKit对象。有两种主要的类型:HKQuantitySample和HKCategorySample,两种都是HKSample的子类。需要注意的是HKSample就想其他的HealthKit类型一样是HealthKit的子类,但是本文例子中没有对这个类的相关的介绍。以下是4中类型的类型关系图:

HKObjectHierarchy@2x

数量例程是对于数据的一个度量以及数量的一个度量。这包括血糖的指标,体重,心率,体温等等。分类例程是指一些能够放进类型里的一些度量。现如今只有一种类型的分类例程,那就是睡眠质量。你能够自行分配一个例程例如熟睡时间在床上,或者用户睡眠状态。由于数量例程被使用的更多,我们详细看下如何创建HKQuantitySample:

HKQuantitySample *mySample = [HKQuantitySample quantitySampleWithType:bloodGlucoseType quantity:quantity startDate:now endDate:now metadata:nil];

这段代码告诉了我们数量例程的样子(分类例程也是如此),它由一个类型,一些数量(或者一些指标对于分类信息而言),一个开始的时间,一个结束的时间,当然还有一些元数据。开始/结束时间标注了那些数据应该被收集。对于一些即时获取的数据例如血糖的值,开始时间和结束时间是相同的。它们都是和采集时间相同的。另一个比较简单的概念是元数据,这里包含了任何你想要保存的关于这个例程的信息。这里的值是一个dictionary,但是只能够保存key,string,number这些数据。

元数据和一些催化模型的额外数据很像,但是在例程中最有趣的组件是类型和数量。

类型

类型可以说是例程中最为重要的组件。离开例程你所有的全部仅仅只是一些数量以及一些日期。因此,也许你知道你的例程是:120mg/dL,记录日期09/09/2014。对于你我来说这些就是针对于血糖信息的。但是对于电脑来说,它仅仅只是一个简单的数字,一个单位,以及一个日期。类型可以告诉HealthKit正在测量的数据类型。它给予了健康数据正确的内容和意义,它是 120mg/dL的血糖值,或者它是98.6˚F体温值。再搭配单位的属性,你的数据将会更加的有意义。正如不同的例程一样,类型的种类也可以是不同的。HKQuantityType和HKCategoryType都是HKSampleType的子类。与之相同的还有HKCharacteristicType。HKCharacteristicType和HKSampleType都是HKObjectType的子类,以下是类型关系图:

HKObjectTypeHierarchy@2x

数量和类别在Sample同一个分支下。如果你有个血糖的例程(是HKQuantitySample类型的),你可能需要一个HKQuantityType的类。数量类型已经被标示符初始化,是最好的例子。如果你的例程是一个血糖的例程,当然是一个HKQuantitySample的例程,你的类型应该是HKQuantityType类型,然后你的标示符应以HKQuantityTypeprefix。完整的标示符是HKQuatityTypeIdentifierBloodGlucose

HKQuantityType *bloodGlucoseType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodGlucose];

Similarly for category types

HKCategoryType *sleepAnalysisType = [HKCategoryType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis];

特性例程是一种新的例程类型。这种类型包括了同房、生日、血型等信息。这些数据不被经常性的改变。HealthKit针对这些数据与其他的数据不同,是不存在多重拷贝的。而且,对于用户来说,可能仅仅只是想恢复最新时间的信息。对于这些,HealthKit提供了分开的方式处理保存和取回数据。这些将在第二个部分详细讲到。

不同于特性例程数据,所有健康类数据必须结构化保存数据,单位和类型信息也应该被保存下来。

储藏数据

我们将我们所有要保存的保存在健康数据库中。调用saveObject:withCompletion:在HKHealthKitStore对象里就ok。很简单,你仅仅需要的就是一个例程。下面是图例关于这些关系的说明,这个可以以血糖值作为参考,当然,这个是HKQuantitySample类型的。

HealthKitSampleComposition

完成block

通过完成Block方法,HealthKit通常会有一个异步执行的进程来告诉你什么时候保存完成了。几乎所有的Block运行都是在后台进程执行的。因此,当你在完成Block里执行UIKit相关操作的时候,你需要跳转到主线程里去执行。教程第二部分将会对此进行详尽的解释,UIKit相关的执行必须放在主线程里是iOS系统的一个重要规定。

疑问

ok,我们现在保存了一些数据,也许你保存了许多。现在的问题是我们需要拿回这些数据。考虑下这种情况,病人通过几个月的血糖app获取到了一些数据,根据这些数据去看医生,有可能被问到,你什么时候的血糖值是超过140mg/dL?或者是你能够给我看下最后一次的病例吗?我们的病人通常都是会容易忽略这些,并且不容易回想起最后一次的病例。但是用户使用的血糖app就能够有效的做到这一点。

非特性数据

非特性数据是查询中最基本的一个类型,他的结果就是根据既定的参数返回所有的结果。所有的queries继承自HKQuerywhich并且具有两种属性:sampleType和predicate。same type是正在查询的数据类型。这是HKQuantityType(或者HKCategoreType等等)的一个实例。predicate是确定要返回那些值所提供的一些参数。predicate有些许不同的定义方式,我们将会在第二节着重讲到。通过上面的例子,我们就能够筛选出所需要的一些血糖数据。

查询Queries方法是能够有限制数量和排序功能的。限制数量同MySQL中的LIMIT或者其他的数据库中一样,给返回来的数据提供数量的限制,不做数量限制的话可以使用HKObjectQueryNoLimit这个关键字。

排序功能有些麻烦,他是NSSortDescriptors中的一个数组,如果你重来都没有用过NSSortDescriptors你不必过虑,因为他们比较难弄清楚,需要时间。下面是NSSortDescriptors的一个使用例子:

[NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO];

这个例子是说明数据根据时间降序排列。你也可以使用HKSampleSort去看下结果是怎样。

特性数据

特性数据有几个方法将在第二部分中讲到。

观察者Queries方法

对于Query查询的比较行之有效的一个方法是观察者模式。如果你想要查询HealthKit中的某个数据你可以通过轮寻最新的数据这中方式去查找,但是这种方式比较耗费资源,并且不够优雅。因此可以使用HKObserverQuery方法。观察者模式是一个长久执行的Query并且不会被随意停止。和完成block一样,observer queries能够通过一个句柄去不断检测数据的变化。

这种方式的处理能够有效的处理软件与硬件之间的配合。如果用户正在使用一个穿戴式的设备检测心率,那么你就能够在应用中实时的展现这些数据。这是一种非常好用的工具。

拓展—Catalyze

通过Catalyze,我们能够很好的帮助你学习HealthKit。我们已经开发了一套utility能够帮助你顺利的实时的保存数据到HealthKit和我们的HIPAA APIs中。那样子的话,无论用户数据中发生了什么样子的数据保存,他们的数据将会同步到外部一个固定的地方,并且对应的是能够让用户进行读取的。另外,如果用户吊销了与HealthKit之间的存取权限,你将无法恢复数据,并且应用也不能够写入数据。这样你就丢失了所有的历史数据。我们的这种不会受到影响。通过这个工具,你能恢复和存取任何数据,完全尊重用户的隐私。

通过第二部分的讲解,你就能够开始通过HealthKit进行开发了。我们非常期待你的交流,如果你有任何反馈和疑问,请通过邮件同我们交流。

发表评论

电子邮件地址不会被公开。 必填项已用*标注