멋있게걷는방법

[Swift] HealthKit 설정과 데이터 요청 (distanceWalkingRunning, activeEnergyBurned, appleExerciseTime) 본문

iOS

[Swift] HealthKit 설정과 데이터 요청 (distanceWalkingRunning, activeEnergyBurned, appleExerciseTime)

도현D 2023. 3. 7. 23:43

프로젝트에서 HealthKit 을 사용했던 경험을 바탕으로 글을 적어보려고 합니다.🙂

HealthKit 이란?

HealthKit 은 사용자의 건강 정보를 받아올 수 있는데요.
아이폰에 건강이라는 앱에 들어가면 자신의 건강 정보를 확인할 수 있는데요. 이 데이터를 사용하는 기술입니다.

애플워치가 꼭 필요한가?

= 애플워치가 없더라도 괜찮습니다!
애플워치가 있다면, 애플워치를 착용했을 때의 이동한 거리나 피트니스 정보가 플러스 된다는 장점이 있습니다.
하지만 애플워치 셀룰러가 아니라면 거의 아이폰도 함께 갖고 다니니까 애플워치가 없더라도 충분합니다.

HKHealthStore

HKHealthStore 의 공식문서를 보면 'HealthKit에서 관리하는 모든 데이터의 액세스 포인트' 라고 합니다.
이 클래스를 이용하여 HealthKit 데이터를 공유하거나 읽을 수 있는 권한을 요청할 수 있습니다.

사용하려면 먼저..

먼저 Info 에서 위 사진처럼 키를 추가하여 문자열을 입력해주세요. ( 권한을 요청할 때 앱 설명에 쓰입니다.)

그리고,

Target -> Signing & Capabilities -> +Capability -> HealthKit 추가

위 과정을 실행해주시면

이렇게 뜰텐데 그럼 준비는 끝났습니다!

(저는 걷기 + 달리기 거리, 운동 시간, 활동 에너지 데이터를 불러오려고 합니다!)

 

 

let healthStore = HKHealthStore()
let read: Set = [HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
                             HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
                             HKSampleType.quantityType(forIdentifier: .appleExerciseTime)!]
let share: Set = [HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
                              HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!]

func requestAuthorization() {
        healthStore.requestAuthorization(toShare: share, read: read) { success, _ in
            if success {
                print("success")
            } else {
                print("faild")
            }
        }
    }

 

 

주의!

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Authorization to share the following types is disallowed: HKQuantityTypeIdentifierAppleExerciseTime'

위 처럼 문제가 발생하는 이유는 저같은 경우 .appleExerciseTime 을 share 에도 추가했기 때문이었습니다.

 

( 앞에 apple 이 붙은 프로퍼티를 사용할 때에는 read 에만 추가해야합니다!! )

위 함수를 성공적으로 실행하면 이래와 같은 화면을 보실 수 있을 겁니다.

이제 사용자가 접근 권한을 허용해주면 바로 데이터를 불러올 수 있습니다.

어떻게 불러오지?

제가 사용했던 코드를 예시로 들면,

func getDistanceWalkingRunning() {
    let stepType = HKQuantityType.quantityType(forIdentifier: .distanceWalkingRunning)!
    let second = TimeZone.autoupdatingCurrent.secondsFromGMT(for: Date())
    let now = Date().addingTimeInterval(TimeInterval(second))
    var dateComponents = Calendar.current.dateComponents([.year, .month, .day], from: Date())
    dateComponents.timeZone = TimeZone(abbreviation: "ko")
    let dateWithTime = Calendar.current.date(from: dateComponents)!
    let startDate = Calendar.current.date(byAdding: .day, value: -6, to: dateWithTime)!
    let daily = DateComponents(day: 1)
    let exactlySevenDaysAgo = Calendar.current.date(byAdding: DateComponents(day: -7), to: dateWithTime)!
    let oneWeekAgo = HKQuery.predicateForSamples(withStart: exactlySevenDaysAgo,
                                                 end: now, options: .strictStartDate)
    let query = HKStatisticsCollectionQuery(quantityType: stepType,
                                            quantitySamplePredicate: oneWeekAgo,
                                            options: .cumulativeSum,
                                            anchorDate: startDate,
                                        intervalComponents: daily)

    query.initialResultsHandler = { _, result, _ in
        if let results = result {
            results.enumerateStatistics(from: startDate, to: now) { [weak self] statistic, _ in
                if let count = statistic.sumQuantity() {
                    let val = count.doubleValue(for: HKUnit.meter())
                    self?.distanceWalkingRunningData.append(round((val / 1000) * 10) / 10)
                } else {
                    self?.distanceWalkingRunningData.append(0)
                }
            }
        }
    }
    healthStore.execute(query)
}

위 코드는 오늘을 기준으로 저번 주 일주일동안 걷기 + 달리기 데이터를 가져오는 코드입니다.

 

이 함수를 권한 요청이 success 일 때 실행시키면 바로 값을 가져오지않고 함수 실행이 끝난 뒤에 동작하기 때문에
viewWillAppear 같은 곳에서 이 데이터를 가지고 UI 에 반영할 일이 있다면 viewWillDisAppear 나 다른 주기를 갖는 함수를 사용해야 하는 것 같더라구요.

시간대 설정에서 어려움이 있었습니다.

저는 데이터를 가져오는 시간대를 설정하는 곳에서 어려움이 있었는데,

처음엔 현재 시간 ~ 내일 현재 시간의 데이터를 가져왔더니 건강 앱과 동일한 데이터도 아닐 뿐더러, 내일 날짜의 현재 시간까지의 데이터를 요청하다보니 nil 로 반환되는 문제가 있었습니다.

이렇게 해봤어요.

그래서, 00시 ~ 내일 00시까지의 데이터를 가져오면 정확한 데이터를 가져올 수 있겠다 생각해

DateComponents 를 이용해 오늘 날짜까지만 가져오도록 함으로써 시간을 00으로 초기화 할 수 있었고, timeZone 을 한국으로 설정했습니다.

결과적으로 건강 앱과 동일한 데이터를 가져올 수 있었습니다.

 

내용에 틀린 부분이 있다면 알려주세요!🙇🏻