728x90
반응형
HealthKit API
1. 권한 요청
// info.plist 추가
/*
NSHealthShareUsageDescription = Privacy - Health Share Usage Description
NSHealthUpdateUsageDescription = Privacy - Health Update Usage Description
string
AntiSleep wants to access your health data in order to analyze your health and best advice
*/
// 오류
/*
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'The string "" is an invalid value for NSHealthUpdateUsageDescription'
terminating with uncaught exception of type NSException
-> info.plist 각각 정보의 String 뒤에 설명 추가
참고: https://roadtosuccess.tistory.com/2
*/
import HealthKit
2. 심박수
1) HeartRate 가져오기
// ios
import UIKit
import HealthKit
class ViewController: UIViewController {
@IBOutlet weak var heartRateLabel: UILabel!
@IBOutlet weak var driveBtn: UIButton!
// 심박수, 수면시간 권한 요청
let healthStore = HKHealthStore()
var heartRateBPM = String()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
authorizeHealthKit()
setLabel()
}
func setLabel() {
self.heartRateLabel.text = "HeartRate : \(self.heartRateBPM) BPM"
}
// healthKit 권한 요청
func authorizeHealthKit() {
// 심박수, 수면시간 권한 요청
let typeToRead = Set([HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.categoryType(forIdentifier: .sleepAnalysis)!])
let typeToShare = Set([HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.categoryType(forIdentifier: .sleepAnalysis)!])
healthStore.requestAuthorization(toShare: typeToShare, read: typeToRead) { (success, error) in
if error != nil {
print(error.debugDescription)
} else {
if success {
print("권한이 허락되었습니다.")
self.getHeartRateData()
} else {
print("권한이 아직 없습니다.")
}
}
}
}
// 심장 박동수 가져오기
// https://ios-dev-tech.tistory.com/12
// https://www.youtube.com/watch?v=uzJXV_9IBoc
func getHeartRateData() {
// HKObjectType: HealthKitStore 대한 특정 유형의 데이터 식별 클래스
// HKObjectType.quantityType: identifier에 대한 수량 유형 반환
guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
return
}
// startDate: 1시간 전 ~ 현재 날짜 시간 정보
let startDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())
// HKQuery: HealthKit 안 모든 query class 위한 추상 클래스
// HKQuery.predicateForSamples: 특정 시간 동안의 특정 데이터 반환
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictEndDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [sortDescriptor]) {
(sample, result, error) in
guard error == nil else {
return
}
let data = result![0] as! HKQuantitySample
let unit = HKUnit(from: "count/min")
let latesHr = data.quantity.doubleValue(for: unit)
self.heartRateBPM = String(format: "%.2f", latesHr)
print("HeartRate : \(self.heartRateBPM) BPM")
let dateFormator = DateFormatter()
dateFormator.dateFormat = "dd/MM/yyyy hh:mm s"
let StartDate = dateFormator.string(from: data.startDate)
let EndDate = dateFormator.string(from: data.endDate)
print("StartDate : \(StartDate) - EndDate : \(EndDate)")
}
healthStore.execute(query)
}
}
2) HeartRate 데이터 저장, 불러오기
let healthStore = HKHealthStore()
var startedHeartRate : Bool = false
// var heartRateBPM : String!
var heartRateBPM : Double = 0.0
var calc : Double = 0.0
var bpm : Double = 0.0
// 타이머 변수
var startedTimer : Bool = false
func heartRateManager() {
if !startedHeartRate { // true
heartRateCountLabel.setText("HeartRate : \(heartRateBPM) BPM")
print("bpm")
if bpm != heartRateBPM {
bpm = heartRateBPM
heartRateCalc()
}
getHeartRateData()
} else {
print("error")
}
}
func heartRateCalc() {
calc = bpm - heartRateBPM
if (calc >= 20) {
self.alarmLabel.setText("Drowsy Driving")
}
}
// 심장 박동수 가져오기
// https://ios-dev-tech.tistory.com/12
// // https://www.youtube.com/watch?v=uzJXV_9IBoc
func getHeartRateData() {
// HKObjectType: HealthKitStore 대한 특정 유형의 데이터 식별 클래스
// HKObjectType.quantityType: identifier에 대한 수량 유형 반환
guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
return
}
// startDate: 1시간 전 ~ 현재 날짜 시간 정보
let startDate = Calendar.current.date(byAdding: .hour, value: -1, to: Date())
// HKQuery: HealthKit 안 모든 query class 위한 추상 클래스
// HKQuery.predicateForSamples: 특정 시간 동안의 특정 데이터 반환
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: Date(), options: .strictEndDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [sortDescriptor]) {
(sample, result, error) in
guard error == nil else {
return
}
let data = result![0] as! HKQuantitySample
let unit = HKUnit(from: "count/min")
let latesHr = data.quantity.doubleValue(for: unit)
self.heartRateBPM = round(latesHr*100)/100
print("HeartRate : \(self.heartRateBPM) BPM")
// self.heartRateBPM = String(format: "%.2f", latesHr)
// print("HeartRate : \(String(describing: self.heartRateBPM)) BPM")
self.startedHeartRate = !self.startedHeartRate
self.heartRateManager()
let dateFormator = DateFormatter()
dateFormator.dateFormat = "dd/MM/yyyy hh:mm s"
let StartDate = dateFormator.string(from: data.startDate)
let EndDate = dateFormator.string(from: data.endDate)
print("StartDate \(StartDate) : EndDate \(EndDate)")
}
healthStore.execute(query)
}
3. 수면시간
import HealthKit
let healthStore = HKHealthStore()
var startedSleepData : Bool = true
var sleepTime = String()
var calc : Double = 0.0
class InterfaceController: WKInterfaceController {
func authorizeHealthKit() {
// 수면시간 권한 요청
let typeToRead = Set([HKObjectType.categoryType(forIdentifier: .sleepAnalysis)!])
let typeToShare = Set([HKObjectType.categoryType(forIdentifier: .sleepAnalysis)!])
healthStore.requestAuthorization(toShare: typeToShare, read: typeToRead) { (success, error) in
if error != nil {
print(error.debugDescription)
} else {
if success {
print("권한이 허락되었습니다.")
self.getSleepData()
} else {
print("권한이 아직 없습니다.")
}
}
}
}
@IBAction func sBtnTapped() {
print("sleepDataManager")
totalSleepLabel.setText("\(sleepTime)")
sleepDataCalc()
}
func sleepDataManager() {
if !startedSleepData { // false
print("sleepDataManager error")
} else {
print("sleepDataManager success")
totalSleepLabel.setText("\(sleepTime)")
sleepDataCalc()
}
}
func sleepDataCalc() {
print("sleepDataCalc : \(sleepTime)")
if calc <= 18000 { // 5시간
self.sleepDataLabel.setText("졸음 운전 주의하세요.")
} else {
self.sleepDataLabel.setText("안전 운전하세요.")
}
}
// 수면 데이터 가져오기
// https://eysermans.com/post/creating-an-ios-14-widget-showing-health-data
func getSleepData() {
guard let sleepType = HKObjectType.categoryType(forIdentifier: .sleepAnalysis) else {
return
}
let startDate = Calendar.current.date(byAdding: .day, value: -1, to: Date())
let endDate = Date()
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictEndDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
let query = HKSampleQuery(sampleType: sleepType, predicate: predicate, limit: 30, sortDescriptors: [sortDescriptor]) {
(query, result, error) in
guard error == nil else {
print("Something went wrong getting sleep analysis")
self.startedSleepData = !self.startedSleepData
return
}
print("success")
var totalSeconds : Double = 0.0
if let result = result {
for item in result {
if let sample = item as? HKCategorySample {
let timeInterval = sample.endDate.timeIntervalSince(sample.startDate)
totalSeconds = totalSeconds + timeInterval
print("SleepData StartDate \(sample.startDate) : SleepData EndDate: \(sample.endDate)")
}
}
}
let result =
String(Int(totalSeconds / 3600)) + "h " +
String(Int(totalSeconds.truncatingRemainder(dividingBy: 3600) / 60)) + "m " +
String(Int(totalSeconds.truncatingRemainder(dividingBy: 3600).truncatingRemainder(dividingBy: 60))) + "s"
print("totalSleepTime : \(result)")
self.sleepTime = result
self.calc = totalSeconds
self.sleepDataManager()
}
healthStore.execute(query)
}
참고
728x90
반응형
'🎸 기타' 카테고리의 다른 글
[AWS] AWS로 Spring Boot 배포 1/ EC2 인스턴스 생성/ Ubuntu/ 서버 배포/ 탄력적 IP 주소 (0) | 2024.03.20 |
---|---|
[Mac] MacOS에서 Anaconda 설치/ M1칩/ MacPro/ MacAir/ brew로 conda 설치 (0) | 2023.03.22 |
[Cotato] 캐치카페 신촌점 후기/ 코테이토/ IT 동아리 (0) | 2023.02.06 |
[Mac] MacOS에서 jupyter 설치/ M1칩/ MacPro/ MacAir (0) | 2022.12.19 |
[Mac] MacOS에서 Homebrew 설치/ M1칩/ MacPro/ MacAir (0) | 2022.12.19 |