Swift iOS HealthKit 使用案例: 获取体温列表 HKHealthStore
前言
好像国内很少有关于 swift
的教程和文章,基本都是 ObjectC
的,所以发一下。
要学Swift
的可以去看 斯坦福大学的教程,点这里,当然,英文要好,看完就会。我就是看这个教程学会的。
另外,推荐安装Dash
这个应用,是个查阅 API 的工具软件,学Swift
开发必备
这个教程的开发环境:
- XCode 11.3.1
- iOS 13+
作一个应用,获取健康应用中的体温数据
结果如图:
关于 HealthKit 的所有实体类说明
如下图:
主要有
- 数据存储对象:
HKObject
HKSample
这两个是抽象类,使用的时候要使用其实体类,下图中说明 - 数据查询对象:
HKQuery
用于设置各种各样的查询例子, - 数据单位对象:
HKUnit
可以表示所有健康数据的单位,如:米
,英里
,卡路里
,摄氏度
等等
查询数据的过程说明
-
在
Info.plist
文件中添加两个值,后面的文字说明会显示在应用请求授权的窗口中- 普通模式下是这样的名字
- 右击选择
Raw Key & Values
是这样
- 操作健康数据时,先判断是否支持健康数据
isHealthDataAvailable() -> Bool
- app 需要先向
健康
应用获取你所要操作的数据类型的授权,用户同意之后才能处理健康数据requestAuthorization(toShare:, read:, completion: (Bool, Error?) -> Void)
-
然后需要创建查询对象,要用
HKQuery
这个抽象类下面的那几个类,在上图中有说明,这里以HKSampleQuery
(样本查询) 为例说明,不同查询类型的对应参数不同- 创建的时候需要输入对应的参数
- 你要查询的数据类型、数据标识
sampleType
所要查询的样本类型,具体哪个类型的数据:比如,体温 - 查询的时间条件
predicate
,这个是时间的 predicate,留空时则不筛选时间 - 查询的数量
limit
- 查询结果的排序方式
sortDescriptors
- 最后是回调方法
(query, results, error)
query
是当前查询对象,results?
是查询到的结果,error?
是发生错误时的错误信息,最主要的操作就在此处
看代码
TemperatureTableViewController.swift
//
// TemperatureTableViewController.swift
// BodyTemparature
//
// Created by Kyle on 2020/2/10.
// Copyright © 2020 Cyan Maple. All rights reserved.
//
import UIKit
import HealthKit
/// 获取 Health 中的体温数据
class TemperatureTableViewController: UITableViewController {
// 存储查询到的数据
private var temperatureSamples: Array<HKSample> = []
private var kit: HKHealthStore! {
return HKHealthStore()
}
private let queryType = HKQuantityType.quantityType(forIdentifier: .bodyTemperature)!
private let querySample = HKSampleType.quantityType(forIdentifier: .bodyTemperature)!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "体温记录 top 10"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add",
style: .plain,
target: self,
action: #selector(buttonPressed))
// 如果 iOS 11+ 显示大标题
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.prefersLargeTitles = true
}
if HKHealthStore.isHealthDataAvailable(){
// Write Authorize
let queryTypeArray: Set<HKSampleType> = [queryType]
// Read Authorize
let querySampleArray: Set<HKObjectType> = [querySample]
kit.requestAuthorization(toShare: queryTypeArray, read: querySampleArray) { (success, error) in
if success{
self.getTemperatureData()
} else {
self.showAlert(title: "Fail", message: "Unable to access to Health App", buttonTitle: "OK")
}
}
} else {
// show alert
showAlert(title: "Fail", message: "设备不支持使用健康", buttonTitle: "退出")
}
}
@objc func buttonPressed() {
print("Button Pressed")
// TODO: Add temperature in modal view
}
func getTemperatureData(){
/*
// 时间查询条件对象
let calendar = Calendar.current
let todayStart = calendar.date(from: calendar.dateComponents([.year,.month,.day], from: Date()))
let dayPredicate = HKQuery.predicateForSamples(withStart: todayStart,
end: Date(timeInterval: 24*60*60,since: todayStart!),
options: HKQueryOptions.strictStartDate) */
// 创建查询对象
let temperatureSampleQuery = HKSampleQuery(sampleType: querySample, // 要获取的类型对象
predicate: nil, // 时间参数,为空时则不限制时间
limit: 10, // 获取数量
sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)]) // 获取到的数据排序方式
{ (query, results, error) in
/// 获取到结果之后 results 是返回的 [HKSample]?
if let samples = results {
// 挨个插入到 tableView 中
for sample in samples {
DispatchQueue.main.async {
self.temperatureSamples.append(sample)
self.tableView.insertRows(at: [IndexPath(row: self.temperatureSamples.firstIndex(of: sample)!, section:0)],
with: .right )
}
}
}
}
// 执行查询操作
kit.execute(temperatureSampleQuery)
}
/// 自定义方法:输入 HKSample 输出 日期和温度
func getTemperatureAndDate(sample: HKSample) -> (Date, Double) {
let quantitySample = sample as! HKQuantitySample
let date = sample.startDate
let temperature = quantitySample.quantity.doubleValue(for: .degreeCelsius())
return (date, temperature)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return temperatureSamples.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TemperatureCell", for: indexPath)
let (date, temperature) = getTemperatureAndDate(sample: temperatureSamples[indexPath.row])
cell.textLabel?.text = String(temperature)
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .short
dateFormatter.locale = Locale(identifier: "zh_CN")
cell.detailTextLabel?.text = dateFormatter.string(from: date)
return cell
}
// MARK: - Tool Methods - Alert
func showAlert(title: String, message: String, buttonTitle: String) {
let alert = UIAlertController(title: title,
message: message,
preferredStyle: .alert)
let okAction = UIAlertAction(title: buttonTitle, style: .default, handler: { (action) in
})
alert.addAction(okAction)
DispatchQueue.main.async {
self.present(alert, animated: true, completion: nil)
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。