Swift iOS HealthKit 使用案例: 獲取體溫列表 HKHealthStore

Swift iOS HealthKit 使用案例: 獲取體溫列表 HKHealthStore

前言

好像國內不多有關於 swift 的教程和文章,基本都是 ObjectC 的,因此發一下。ios

要學 Swift 的能夠去看 斯坦福大學的教程, 點這裏,固然,英文要好,看完就會。我就是看這個教程學會的。
另外,推薦安裝 Dash 這個應用,是個查閱 API 的工具軟件,學 Swift 開發必備

這個教程的開發環境:swift

  • XCode 11.3.1
  • iOS 13+

做一個應用,獲取健康應用中的體溫數據

結果如圖: app

body-temperature-list.JPG

關於 HealthKit 的全部實體類說明

以下圖:
主要有async

  1. 數據存儲對象: HKObject HKSample 這兩個是抽象類,使用的時候要使用其實體類,下圖中說明
  2. 數據查詢對象: HKQuery 用於設置各類各樣的查詢例子,
  3. 數據單位對象: HKUnit 能夠表示全部健康數據的單位,如:英里卡路里攝氏度等等

iOS-HealthKit.png

查詢數據的過程說明

  1. Info.plist 文件中添加兩個值,後面的文字說明會顯示在應用請求受權的窗口中ide

    1. 普通模式下是這樣的名字 man.png
    2. 右擊選擇 Raw Key & Values 是這樣 row.png
  2. 操做健康數據時,先判斷是否支持健康數據 isHealthDataAvailable() -> Bool
  3. app 須要先向健康應用獲取你所要操做的數據類型的受權,用戶贊成以後才能處理健康數據 requestAuthorization(toShare:, read:, completion: (Bool, Error?) -> Void)
  4. 而後須要建立查詢對象,要用 HKQuery 這個抽象類下面的那幾個類,在上圖中有說明,這裏以 HKSampleQuery(樣本查詢) 爲例說明,不一樣查詢類型的對應參數不一樣工具

    1. 建立的時候須要輸入對應的參數
    2. 你要查詢的數據類型、數據標識 sampleType 所要查詢的樣本類型,具體哪一個類型的數據:好比,體溫
    3. 查詢的時間條件 predicate,這個是時間的 predicate,留空時則不篩選時間
    4. 查詢的數量 limit
    5. 查詢結果的排序方式 sortDescriptors
    6. 最後是回調方法 (query, results, error) query 是當前查詢對象, results? 是查詢到的結果, error? 是發生錯誤時的錯誤信息,最主要的操做就在此處

看代碼

TemperatureTableViewController.swiftspa

//
//  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)
        }
    }
    
}
相關文章
相關標籤/搜索