如何借助 HealthKit 打造一款健身应用?
【编者按】本文作者为 Matthew Maher,文章手把手地介绍了如何借助 HealthKit 建立简单的健身应用,包含诸多代码实例。本文系国内 ITOM 管理平台 OneAPM 编译呈现。
根据新闻报导,健康与健美在今时今日的重要程度比已往任何时候都高。说起来有点可笑,似乎就在几天之前,笔者就见到过类似的新闻。或许,这是当人逐渐变老之后挥之不去的感觉吧——渴望保持健康以及健美的感觉。不管怎么说,健康与健美是一个重要话题。技术的进步,尤其是移动应用与硬件世界的不断提高,正为这个似乎日益成长的话题带来全新的契机。
HealthKit 是苹果公司推出的一款移动应用平台,旨在为重要、可追踪的健康数据与注重健康、热衷锻炼的科技消费者搭起桥梁。这很酷。用户可以轻松地追踪一段时间内可测量的健身与健康数据。除了了解自身的健康数据,看到图表中喜人的增长曲线也的确鼓舞人心。
正如人们想象的那样,在管理健康信息时安全是非常重要的考虑因素。HealthKit 直截了当地将所有 HealthKit 信息的绝对控制权置于用户的手中。用户可以授权或拒绝任何应用对其健康数据发出的读取请求。
作为开发者,我们需要征求许可才能从/向 HealthKit 读取/写入数据。实际上,我们需要明确地声明打算读取或改变的数据。此外,任何使用 HealthKit 的应用都必须包含隐私政策,这样一来,用户才能对其信息的处理感到更加放心。
关于 OneHourWalker
在本文中,我们将打造一个有趣的小应用,它会从 HealthKit 读取数据,也会向其写入新数据。来见一见 OneHourWalker 吧。
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 官方博客
原文地址:http://www.appcoda.com/healthkit-introduction/
如何借助 HealthKit 打造一款健身应用?的更多相关文章
- 【ASP.NET程序员福利】打造一款人见人爱的ORM(一)
“很多人都不太认可以第三方ORM,因为考虑的点不够全面,没有大用户群体的ORM有保证,这点是不可否认确是事实.但是往往用户群体大的ORM又有不足之处,今天我们就来聊聊关于ORM的话题,打造 ...
- 如何打造一款五星级的 APP ?
移动互联网大潮来袭!据统计,2015 年平均每天有 1000 个新的应用上架,而这些应用的现状可以说是鱼龙混杂,同是每个人的眼光.品味.意识和利益都不同,因此每人眼中的应用也是不同的.在巨大的市场竞争 ...
- 【产品案例】我是如何从零搭建起一款健身O2O产品的?
作者: Wander_Yang 我在年初参与到“SHAPE”这款健身产品的研发中,也算是第一次以产品经理的身份,从0开始负责一个产品的建立. 产品是一款O2O的智能健身连锁店,目前产品已经上线8个月, ...
- 【ASP.NET程序员福利】打造一款人见人爱的ORM(二)
上一篇我已经给大家介绍AntORM的框架[ASP.NET程序员福利]打造一款人见人爱的ORM(一),今天就来着重介绍一下如何使用这套框架 1>AntORM 所有成员 如果你只想操作一种数据库,可 ...
- 打造一款属于自己的web服务器——开篇
JVM总结慢慢来吧,先插播一篇水文,来介绍下最近业余一直在写的一个小项目——easy-httpserver(github).适合新手学习,大神们路过即可^_^. 一.这是个什么玩意? easy-htt ...
- jquery+css3打造一款ajax分页插件
原文:[原创]jquery+css3打造一款ajax分页插件 最近公司的项目将好多分页改成了ajax的前台分页以前写的分页插件就不好用了,遂重写一个 支持IE6+,但没有动画效果如果没有硬需求,个人认 ...
- Notepad++给自己打造一款PowerQuery M语言编辑器【转】
Excel 使用Notepad++给自己打造一款PowerQuery M语言编辑器 Excel 使用Notepad++给自己打造一款PowerQuery M语言编辑器-Power BI-ExcelHo ...
- 基于VueJS的render渲染函数结合自定义组件打造一款非常强大的IView 的Table
基于VueJS的render渲染函数结合自定义组件打造一款非常强大的IView 的Table https://segmentfault.com/a/1190000015970367
- 使用Python打造一款间谍程序
知识点 这次我们使用python来打造一款间谍程序 程序中会用到许多知识点,大致分为四块 win32API 此处可以在MSDN上查看 Python基础重点在cpytes库的使用,使用方法请点击此处 ...
随机推荐
- ICANN认证注册商小全 英、德、法
转载 在ICANN认证注册商小全(一)和ICANN认证注册商小全(二)中,QQPCC介绍了美洲的各ICANN认证注册商.今天我们移师欧洲,介绍欧洲的ICANN认证注册商,欧洲的注册商也很多,不可能在一 ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(三):搭建开发环境
生成项目模板 登录Spring Initializr生成Spring Boot项目模板,保存到本地. 地址:https://start.spring.io/ 导入Maven项目 使用IDE导入生成的M ...
- mysql sql语句最大长度设置方法
今天发现了一个错误:Could not execute JDBC batch update 最后发现原因是SQL语句长度大于1M,而我机器上的mysql是默认设置,也就是说mysql通讯的数据包大小设 ...
- 比特币算法——SHA256算法介绍
SHA256是安全散列算法SHA(Secure Hash Algorithm)系列算法之一,其摘要长度为256bits,即32个字节,故称SHA256.SHA系列算法是美国国家安全局 (NSA) 设计 ...
- mysql添加用户、修改权限,修改登录权限ip
1.添加用户 1.1 登录MYSQL: @>mysql -u root -p @>密码 1.2 创建用户: 格式:grant select on 数据库.* to 用户名@登录主机 ide ...
- mysqldump 用法
mysqldump 是文本备份还是二进制备份 它是文本备份,如果你打开备份文件你将看到所有的语句,可以用于重新创建表和对象.它也有 insert 语句来使用数据构成表. mysqldump 的语法是什 ...
- 小程序实例:用js方法splict()、indexOf()、push()、replace()等操作数组Array的增删改查
一.增加数组子级 1.Array.push() 定义和用法 向数组的末尾处添加一个或多个子集,并返回新数组的长度 语法 var array=["好","扎在那个" ...
- tabs自动切换功能的实现
<html><head><!-- Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href= ...
- [转]本地 Windows 计算机密码登录 登录 腾讯云 Linux 实例
本文转自:https://cloud.tencent.com/document/product/213/5436? 登录工具 使用 远程登录软件 ,采用密码登录 Linux 实例(本例中选择使用 Pu ...
- 【题解】LFYZNoip前水题赛 T6
垃圾出题人们在30分钟内完成了讨论,出题,命题,造数据,跑std的所有环节 luv的化学竞赛题 题目背景 luv_letters 在肝化学竞赛题,他的梦想是混个省一,但是遗憾的是他今年的省二莫名消失了 ...