【编者按】本文做者为 Matthew Maher,文章手把手地介绍了如何借助 HealthKit 创建简单的健身应用,包含诸多代码实例。本文系国内 ITOM 管理平台 OneAPM 编译呈现。html
根据新闻报导,健康与健美在今时今日的重要程度比已往任什么时候候都高。提及来有点好笑,彷佛就在几天以前,笔者就见到过相似的新闻。或许,这是当人逐渐变老以后挥之不去的感受吧——渴望保持健康以及健美的感受。无论怎么说,健康与健美是一个重要话题。技术的进步,尤为是移动应用与硬件世界的不断提升,正为这个彷佛日益成长的话题带来全新的契机。ios
HealthKit 是苹果公司推出的一款移动应用平台,旨在为重要、可追踪的健康数据与注重健康、热衷锻炼的科技消费者搭起桥梁。这很酷。用户能够轻松地追踪一段时间内可测量的健身与健康数据。除了了解自身的健康数据,看到图表中喜人的增加曲线也的确鼓舞人心。git
正如人们想象的那样,在管理健康信息时安全是很是重要的考虑因素。HealthKit 直截了当地将全部 HealthKit 信息的绝对控制权置于用户的手中。用户能够受权或拒绝任何应用对其健康数据发出的读取请求。github
做为开发者,咱们须要征求许可才能从/向 HealthKit 读取/写入数据。实际上,咱们须要明确地声明打算读取或改变的数据。此外,任何使用 HealthKit 的应用都必须包含隐私政策,这样一来,用户才能对其信息的处理感到更加放心。编程
##关于 OneHourWalker 在本文中,咱们将打造一个有趣的小应用,它会从 HealthKit 读取数据,也会向其写入新数据。来见一见 OneHourWalker 吧。swift
OneHourWalker 是一款追踪使用者在一个小时内行走或跑步之距离的健身应用。用户能够将距离与 HealthKit 分享,以后就能在健康应用中读取之。我知道,一个小时听起来有点过于乐观了(至少笔者本人可能没法坚持下去)。所以,用户也能够提前停止计数,并分享距离。数组
额,到目前为止,彷佛 OneHourWalker 只会向 HealthKit 写入数据。咱们须要读取什么数据呢?安全
好问题!在步行锻炼时,我喜欢选择乡间或林间小路。经常,我会遇到树枝低垂的区域。而我是一条身高 193cm 的汉子,这真的让我很苦恼。解决办法是:从 HealthKit 读取用户的身高数据,将之打印为应用的一个标签。这个标签能够做为对用户的善意提醒,这样,他们就能避免在步行时被树枝打到。性能优化
首先,点此下载 OneHourWalker 的初始项目。先试着跑起来,找找应用运行的感受。计数器与地点追踪功能已经在运行了,因此咱们只需专一于 HealthKit 实现。注意,当到达 60 分钟时间点时,计算器与追踪都会中止。网络
##启用 HealthKit 首先,在咱们的应用中启用 HealthKit。在项目导航中,点击 OneHourWalker,以后点击 Targets 下面的 OneHourWalker,以后选择屏幕顶部的 Capabilities 选项。
查看 Capabilities 列表的底部,启用 HealthKit
。这一简单的操做会将 HealthKit 权限添加到 App ID,将 HealthKit 键添加到 info plist 文件,将 HealthKit 权限添加到受权文件,而且与 HealthKit.framework
相链接。就是这么简单。
##开始编程 接下来,跳转到 TimerViewController.swift
,开始将 HealthKit 引入 OneHourWalker。首先,建立一个 HealthKitManager 实例。
import UIKit import CoreLocation import HealthKit class TimerViewController: UIViewController, CLLocationManagerDelegate { @IBOutlet weak var timerLabel: UILabel! @IBOutlet weak var milesLabel: UILabel! @IBOutlet weak var heightLabel: UILabel! var zeroTime = NSTimeInterval() var timer : NSTimer = NSTimer() let locationManager = CLLocationManager() var startLocation: CLLocation! var lastLocation: CLLocation! var distanceTraveled = 0.0 let healthManager:HealthKitManager = HealthKitManager()
全部 HealthKit 工做都会在 HealthKitManager.swift
中进行。它会包含重要的方法,咱们很快就会谈到。
正如在前文介绍部分所述,咱们须要取得用户的许可,才能读取并修改他们的健康数据。在 viewDidLoad()
中,咱们就得这么作。
override func viewDidLoad() { super.viewDidLoad() locationManager.requestWhenInUseAuthorization() if CLLocationManager.locationServicesEnabled(){ locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest } else { print("Need to Enable Location") } // We cannot access the user's HealthKit data without specific permission. getHealthKitPermission() }
getHealthKitPermission()
方法会调用 manager 的 authorizeHealthKit()
方法。若是一切顺利,咱们便能调用setHeight()
方法。不过,咱们很快会在后文中谈到此方法。
func getHealthKitPermission() { // Seek authorization in HealthKitManager.swift. healthManager.authorizeHealthKit { (authorized, error) -> Void in if authorized { // Get and set the user's height. self.setHeight() } else { if error != nil { print(error) } print("Permission denied.") } } }
在 HealthKitManager.swift 中,咱们会建立 authorizeHealthKit() 方法。然而,除此以外,咱们须要建立 HealthKit 存储,用于链接应用与 HealthKit 的数据。
let healthKitStore: HKHealthStore = HKHealthStore() func authorizeHealthKit(completion: ((success: Bool, error: NSError!) -> Void)!) { // State the health data type(s) we want to read from HealthKit. let healthDataToRead = Set(arrayLiteral: HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)!) // State the health data type(s) we want to write from HealthKit. let healthDataToWrite = Set(arrayLiteral: HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)!) // Just in case OneHourWalker makes its way to an iPad... if !HKHealthStore.isHealthDataAvailable() { print("Can't access HealthKit.") } // Request authorization to read and/or write the specific data. healthKitStore.requestAuthorizationToShareTypes(healthDataToWrite, readTypes: healthDataToRead) { (success, error) -> Void in if( completion != nil ) { completion(success:success, error:error) } } }
在请求获取用户健康数据的受权时,咱们须要明确指定打算读取以及修改的信息。对本例而言,咱们须要读取用户的身高,从而帮助他们躲避有危险的低垂枝丫。咱们但愿 HealthKit 能提供一个能够转化为可理解的身高的 HKObject 量。此外,咱们还要得到修改 HKObject 量的许可,以记录用户的行走及跑步距离。
在处理好 OneHourWalker 与 iPad 通讯的可能性后,咱们作出官方请求。
在 HealthKitManager.swift
中,建立从 HealthKit 读取用户身高数据的 getHeight()
方法。
func getHeight(sampleType: HKSampleType , completion: ((HKSample!, NSError!) -> Void)!) { // Predicate for the height query let distantPastHeight = NSDate.distantPast() as NSDate let currentDate = NSDate() let lastHeightPredicate = HKQuery.predicateForSamplesWithStartDate(distantPastHeight, endDate: currentDate, options: .None) // Get the single most recent height let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false) // Query HealthKit for the last Height entry. let heightQuery = HKSampleQuery(sampleType: sampleType, predicate: lastHeightPredicate, limit: 1, sortDescriptors: [sortDescriptor]) { (sampleQuery, results, error ) -> Void in if let queryError = error { completion(nil, queryError) return } // Set the first HKQuantitySample in results as the most recent height. let lastHeight = results!.first if completion != nil { completion(lastHeight, nil) } } // Time to execute the query. self.healthKitStore.executeQuery(heightQuery) }
查询身高数据的第一步是建立一个断言以定义时间参数。咱们是在请求一段时间内的全部身高数据——与当前日期相距甚远的一个过去的日期。显然,这会返回一个数组。然而,咱们只想要最近期的身高,所以,咱们请求数据时可让最新的数据排在数组的最前头。
在构建这一查询时,咱们会把数组的长度限制为1。在考虑好出现错误的可能性后,咱们会将结果中的首个也即惟一一个数组项目分配给 lastHeight。接下来,完善 getHeight() 方法。最后,针对用户的健康数据执行查询。
回到 TimerViewController.swift
,在 app 真正投入使用以前,假设用户受权了适当的许可,则 setHeight()
方法会被 getHealthKitPermission()
调用。
var height: HKQuantitySample?
首先,咱们须要为 HKQuantitySample 实例声明一个身高变量。
func setHeight() { // Create the HKSample for Height. let heightSample = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight) // Call HealthKitManager's getSample() method to get the user's height. self.healthManager.getHeight(heightSample!, completion: { (userHeight, error) -> Void in if( error != nil ) { print("Error: \(error.localizedDescription)") return } var heightString = "" self.height = userHeight as? HKQuantitySample // The height is formatted to the user's locale. if let meters = self.height?.quantity.doubleValueForUnit(HKUnit.meterUnit()) { let formatHeight = NSLengthFormatter() formatHeight.forPersonHeightUse = true heightString = formatHeight.stringFromMeters(meters) } // Set the label to reflect the user's height. dispatch_async(dispatch_get_main_queue(), { () -> Void in self.heightLabel.text = heightString }) }) }
在 share()
方法之上,咱们会建立 setHeight()
方法。咱们请求的身高数据样本以 HKQuantity
返回,标识符 HKQuantityTypeIdentifierHeight
知道这一对象。
接下来,调用在 manager 中建立的 getHeight()
方法。有了身高样本,咱们还须要将之翻译为恰当的字符串以展现在标签中。与往常同样,考虑全部可能的错误状况是很重要的。
到此,用户就能够打开 app,查看他们的身高(若是他的健康应用中记录着身高数据),开启计时器,追踪他跑步或行走的距离了。接下来,咱们要处理将距离数据写入健康应用的过程,这样,用户才能在同一个应用中保存其全部的健身数据。
在用户结束外出锻炼以后,无论有没有到60分钟,他可能会使用 Share(分享)按钮将其辛苦赚得的运动距离发送到健康应用。因此,在 share() 方法中,咱们须要调用 HealthKitManager.swift
的 saveDistance()
方法来实现这一过程。在这个方法中,咱们会发送运动距离以及取得该距离的日期。这样,用户便能在次日争取更好的成绩。
@IBAction func share(sender: AnyObject) { healthManager.saveDistance(distanceTraveled, date: NSDate()) }
接下来,回到 manager,咱们要在此处建立 saveDistance()
方法。首先,咱们要让 HealthKit 知道咱们打算写入一个表明步行及跑步距离的量。以后,将度量单位设置为英里,并赋值官方的样本量。HealthKit 的 saveObject()
方法会将此数据写入用户的健康数据。
func saveDistance(distanceRecorded: Double, date: NSDate ) { // Set the quantity type to the running/walking distance. let distanceType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning) // Set the unit of measurement to miles. let distanceQuantity = HKQuantity(unit: HKUnit.mileUnit(), doubleValue: distanceRecorded) // Set the official Quantity Sample. let distance = HKQuantitySample(type: distanceType!, quantity: distanceQuantity, startDate: date, endDate: date) // Save the distance quantity sample to the HealthKit Store. healthKitStore.saveObject(distance, withCompletion: { (success, error) -> Void in if( error != nil ) { print(error) } else { print("The distance has been recorded! Better go check!") } }) }
跳转到健康应用,所记录的数据会出如今 Walking + Running Distance(行走+跑步距离)一行(若是已经启用)。此外,依照下面的路径,咱们能够看到详细的样本数据:Health Data tab(健康数据选项卡) > Fitness(健身) > Walking + Running Distance(行走+跑步距离) > Show All Data(显示全部数据)。咱们的数据就在此列表中。轻击一个单元,咱们的图标(目前还未设置)就会与距离一同出现。再次点击此单元,就能看到完整的细节数据。
借助 OneHourWalker,咱们便能为全世界 iOS 用户的身体健康贡献一份力量。然而,这只是一个开始。在使用 HealthKit 读取并修改健康数据的道路上,还有很是多的可能性。
固然,对用户而言,拥有这些可追踪数据的好处不少。人们能够轻松地按照日期、星期进行比较,从而激励本身朝着目标努力。不过,真正的伟大之处在于,开发者能够提供全新的,富有创造力的有趣方法来获取数据。
欢迎你们对 HealthKit 应用进行测试。点击此处查看 OneHourWalker 的最终版本。
本文系 OneAPM 工程师编译整理。OneAPM Mobile Insight 以真实用户体验为度量标准进行 Crash 分析,监控网络请求及网络错误,提高用户留存。访问 OneAPM 官方网站感觉更多应用性能优化体验,想阅读更多技术文章,请访问 OneAPM 官方技术博客。
本文转自 OneAPM 官方博客