티스토리 뷰
애플 프레임워크에서 제공하는 Healthkit을 사용해 사용자의 수면정보를 가져와보겠습니다.
1. Info.plist에 읽기/쓰기 권한 설정 및 표시 문구 설정
먼저, 정보 접근을 위해 사용자 동의를 얻어야합니다.
Target > Info > Custom iOS Target Properties (or WatchOS Target Properties)
1. + 버튼을 눌러서 Privacy - Health .. 를 적어줍니다.
2. 권한은 Share(읽기권한), Update(쓰기권한) 중 필요한 것을 설정해줍니다.
3. 접근 권한을 허용할 때 뜰 문구를 Value에 써줍니다.
Record 권한은 Healthkit 샘플이 아닌 '의료기록'에 관한 접근 권한입니다. 필요에 따라 설정해주세요.
2. Signing & Capability에 HealthKit 추가
1. + Capability 버튼을 누릅니다.
2. HealthKit을 검색해서 추가해줍니다.
3. 필요에 따라 두 가지 옵션을 선택합니다. 저는 단순 읽기/쓰기 권한만 필요해서 둘 다 설정하지 않았습니다.
3. requestAuthorization 호출로 상세 권한 설정
import HealthKit
class HealthKitService {
let healthStore = HKHealthStore()
// 읽기 및 쓰기 권한 설정
let read = Set([HKCategoryType.categoryType(forIdentifier: .sleepAnalysis)!])
let share = Set([HKCategoryType.categoryType(forIdentifier: .sleepAnalysis)!])
func configure() {
// 해당 장치가 healthkit을 지원하는지 여부
if HKHealthStore.isHealthDataAvailable() {
requestAuthorization()
}
}
// 권한 요청 메소드
private func requestAuthorization() {
self.healthStore.requestAuthorization(toShare: share, read: read) { success, error in
if error != nil {
print(error.debugDescription)
}else{
if success {
print("권한이 허락되었습니다")
}else{
print("권한이 없습니다")
}
}
}
}
}
여러 권한을 설정할 땐 Set안에 나열해주시면 됩니다.
@main
struct MainApp: App {
// Healthkit 인증 코드가 있는 객체를 선언해줍니다.
let service = HealthKitService()
var body: some Scene {
WindowGroup {
ContentView()
}
}
init() {
setup()
}
// 첫 실행 시 Healthkit 권한 설정이 되도록 호출합니다.
func setup() {
service.configure()
}
}
SwiftUI 기준으로 첫 실행시 권한 설정 함수가 호출되도록 @main이 있는 struct에 해당 함수를 호출해줍니다.
실행해보시면 이런 화면이 뜨게 됩니다.
이렇게 한번 허용을 하고 나면 이 화면은 더이상 뜨지 않습니다.
앞으로 개별 항목에 대한 권한 상태를 보고싶다면 다음과 같은 코드를 사용해야합니다.
// 수면 데이터에 대한 권한이 허용되어 있는지 확인
let sleepAnalysisType = HKCategoryType.categoryType(forIdentifier: .sleepAnalysis)!
let authorizationStatus = healthStore.authorizationStatus(for: sleepAnalysisType)
switch authorizationStatus {
case .notDetermined:
// 권한이 아직 요청되지 않음
case .sharingDenied:
// 권한 거부됨
case .sharingAuthorized:
// 권한 부여됨
default:
}
4. 수면 데이터 가져오기
// HealthKitService.swift > class HealthKitService
func getSleepData(){
// 수면 데이터 Type 정의
if let sleepType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {
// 데이터를 필터링할 조건(predicate)를 설정할 수 있음. 여기선 일주일 데이터를 받아오도록 설정
let calendar = Calendar.current
let endDate = Date() // 현재 시간
let startDate = calendar.date(byAdding: .day, value: -7, to: endDate) // 7일 전 시간
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate)
// 최신 데이터를 먼저 가져오도록 sort 기준 정의
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
// 쿼리 수행 완료시 실행할 콜백 정의
let query = HKSampleQuery(sampleType: sleepType, predicate: predicate, limit: 20, sortDescriptors: [sortDescriptor]) { (query, tmpResult, error) -> Void in
if error != nil {
// 에러 처리를 수행합니다.
print(error)
return
}
if let result = tmpResult {
for item in result {
if let sample = item as? HKCategorySample {
// 가져온 데이터 출력
print("Sleep value: \(sample.value)")
print("Start Date: \(sample.startDate)")
print("End Date: \(sample.endDate)")
print("Metadata: \(String(describing: sample.metadata))")
print("UUID: \(sample.uuid)")
print("Source: \(sample.sourceRevision)")
print("Device: \(String(describing: sample.device))")
print("---------------------------------\n")
}
}
}
}
// HealthKit store에서 쿼리를 실행
healthStore.execute(query)
}
}
HealthKit에서 정보를 가져올 때는 데이터베이스에 쿼리를 날려 조회하듯, 쿼리를 작성해야합니다.
어떤 정보를 가져올 것인지 Type을 지정한 후 조건, 정렬, 콜백 등을 작성하여 HealthStore객체의 excute메소드를 이용하면 됩니다.
수면데이터의 경우 시작 시간과 끝 시간을 통해 얼마나 잠을 잤는지 알 수 있습니다.
그리고 value는 수면 형태를 나타내는데요, 램수면, 깊은 수면 등등이 있습니다.
value는 Int 형태고 의미하는 바는 다음과 같습니다.
inBed = 0
asleepUnspecified = 1
awake = 2
asleepCore = 3
asleepDeep = 4
asleepREM = 5
참고로 수면 데이터는 위와 같이 구성되어 있습니다.
import SwiftUI
struct SleepTimeView: View {
let service = HealthKitService()
var body: some View {
VStack{
Button("Get sleep data") {
service.getSleepData()
}
}
}
}
간단히 뷰를 만들어서 실행해보았습니다.
...
Sleep value: 0
Start Date: 2023-03-27 23:01:10 +0000
End Date: 2023-03-27 23:01:15 +0000
Metadata: Optional(["HKTimeZone": Asia/Seoul])
...
디바이스 소스를 제외하면 이런 정보가 출력되네요.
Inbed 시간이 5분정도 찍혔군요
...
Sleep value: 5
Start Date: 2023-03-27 21:33:46 +0000
End Date: 2023-03-27 22:28:46 +0000
Metadata: Optional(["HKTimeZone": Asia/Seoul])
...
이날 애플워치를 차고 자서 램수면 시간을 확인할 수 있었습니다.
UTC 시간과 서울은 9시간 차이이니 3월 28일 06:33 ~ 3월 28일 07:28동안 램수면 상태였네요.
이제 이걸 잘 가공해서 서비스에 적용하면 될 것 같습니다.
읽어주셔서 감사합니다!
Ref.
공식문서
'iOS' 카테고리의 다른 글
- Total
- Today
- Yesterday
- 아키텍쳐 패턴
- Swift Concurrency
- swift
- Flutter
- Flux
- SwiftUI
- healthkit
- 비동기/동기
- 노션
- MVVM
- reactive programming
- combine
- programmers
- TestCode
- MVI
- ios
- 코디네이터 패턴
- DocC
- GetX
- SWM
- design pattern
- MVC
- 리액티브 프로그래밍
- coordinator pattern
- Architecture Pattern
- 프로그래머스
- RX
- notion
- 소프트웨어마에스트로
- Bloking/Non-bloking
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |