안녕하세요!! 윤기사입니다!
이번 포스팅은 헬스킷 운동 데이터에 관한 포스팅인데요!!
바로 사용자의 운동 데이터를 가져오는 겁니다!
"운동 데이터가 뭐야?"라고 생각하실 수도 있어서 바로 시작해 볼게요!
HKWorkout | Apple Developer Documentation
A workout sample that stores information about a single physical activity.
developer.apple.com
- A workout sample that stores information about a single physical activity.
- 단일 신체 활동에 대한 정보를 저장하는 운동 샘플입니다.
단일 신체 활동에 대한 정보...? 이게 무슨 말인가 싶죠...?
요새 운동에 푹 빠져서 헬스장을 다니고 있는데, 항상 애플워치를 차고 얼마나 운동을 하는지 기록을 해요!
그래서 애플워치로 "Traditional Strength Training" 운동 종목을 선택해서 진행을 한답니다! 이게 단일 신체 활동이에요!
기록을 하고 나서 보면 위와 다양한 정보를 저장을 하고 있어요!
저희는 HKWorkout을 이용해서 맨 오른쪽 Details에 접근할 수 있답니다!
그럼, 운동 종목과 운동 시간 등을 가져와보도록 할게요!
1. 헬스킷에서 운동 데이터를 조회하기 위해 로직을 구성해 줍니다.
- Escaping Closure로 [HKWorkout] 배열을 리턴해 줄 겁니다!
- HKSampleQuery를 통해 query를 생성하고 healthStore.execute(:_)를 통해 query를 실행해 줍니다.
/// -------------------------------------------------
/// 헬스킷 운동 데이터 조회
public func getWorkoutValues(startDate: Date, endDate: Date, completion: @escaping([HKWorkout])->()) {
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
let compound = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate])
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: true)
let query = HKSampleQuery(sampleType: HKSampleType.workoutType(), predicate: compound, limit: HKObjectQueryNoLimit, sortDescriptors: [sortDescriptor]) { [weak self] (query, result, error) -> Void in
if error != nil { return }
var workoutList: [HKWorkout] = []
for (_, workoutSamples) in (result ?? []).enumerated() {
guard let data: HKWorkout = workoutSamples as? HKWorkout else { return }
workoutList.append(data)
}
completion(workoutList)
}
healthStore.execute(query)
}
- HKWorkout은 아래와 같은 데이터를 가지고 있어요!!
duration : 운동 진행시간 (단위: 초)
workoutActivities : 운동 종류 = HKWorkoutActivityTypeTraditionalStrengthTraining
workoutActivityType : 운동 타입 = HKWorkoutActivityType(rawValue: 50)
workoutEvents : 운동 중 발생한 이벤트 = ex. 운동 시작 및 중지 시간 기록
startDate : 데이터 시작 시간
endDate : 데이터 종료 시간
uuid : 데이터 uuid
metadata : 메타데이터
HKWeatherHumidity: 7900 %,
HKAverageMETs: 8.95306 kcal/hr·kg,
HKWeatherTemperature: 32.918 degF,
HKTimeZone: Asia/Seoul,
HKIndoorWorkout: 0
device : 운동 데이터를 발생시킨 디바이스 정보
name:Apple Watch,
manufacturer:Apple Inc.,
model:Watch,
hardware:Watch5,10,
software:10.2
sourceRevision : 디바이스와 앱 정보
name:YEOJIN의 Apple Watch,
bundle:com.apple.health.C955A94E-8969-4A01-B9C6-50F43DF3145F,
version:10.2,
productType:Watch5,10,
operatingSystemVersion:10.2
2. 운동 데이터를 담을 모델을 만듭니다!
- 저는 운동 측정일자와 운동 종목, 운동 진행 시간, 운동 시간, 운동 데이터의 Uuid 등을 담아주겠습니다!
struct WorkoutModel {
// list
var recordDate: Date = Date() // 측정일자
var execTypeCode: String = "" // 운동 종목 코드
var execStartTime: Date = Date() // 운동 시작 시간
var execEndTime: Date = Date() // 운동 종료 시간
var execRunTime: TimeInterval = TimeInterval() // 운동 시간 (단위: 초)
var deviceTypeCode: DeviceTypeCode = .WATCH // 디바이스 모델 타입 코드
var recoreUuid: String = "" // 레코드 식별 UUID
func toDictionary() -> [String: Any] {
var dic = [
"recordDate" : recordDate.yyyyMMdd,
"execTypeCode" : execTypeCode,
"execStartTime": execStartTime.yyyyMMddHHmmss,
"execEndTime": execEndTime.yyyyMMddHHmmss,
"execRuntime": Int(execRunTime).toString(),
"deviceTypeCode": DeviceTypeCode.WATCH.rawValue,
"recordUuid": recoreUuid,
] as [String: Any]
return dic
}
}
3. 1에서 completion으로 전달받은 [HKWorkout] 배열을 for문을 통해 Model에 담아줍니다.
/** 헬스킷 운동 데이터 조회 */
public func getWorkoutData(_ startDate: Date? = nil) {
HealthKitManager.shared().getWorkoutValues(startDate: startDate, endDate: Date()) { [weak self] list in
guard let self else { return }
var dicList = [[String: Any]]()
for data in list {
var workoutData = WorkoutModel()
workoutData.recordDate = data.endDate
workoutData.recordCode = "1234"
workoutData.execTypeCode = workoutData.convertHKWorkoutActivityTypeToServer(data.workoutActivityType)
workoutData.execStartTime = data.startDate
workoutData.execEndTime = data.endDate
workoutData.execRunTime = data.duration
workoutData.recoreUuid = data.uuid.uuidString
let workoutModel = workoutData.toDictionary()
dicList.append(workoutModel)
}
self.completionHandler(.workout, dicList)
}
}
4. HKWorkoutActivityType의 rawValue(Int) 값을 String 타입으로 바꿔줍니다.
- (참고) HKWorkoutActivityType의 Traditional Strength Training은 rawValue 값이 "50"입니다.
HKWorkoutActivityType | Apple Developer Documentation
The type of activity performed during a
developer.apple.com
/** 운동 종목 */
enum ExerciseType: String {
case walkingSlow = "SERVER01"/** 천천히 걷기 */
case running = "SERVER02"/** 달리기 */
case outdoorCyclingSlow = "SERVER03"/** 야외 자전거타기 */
case hiking = "SERVER04"/** 등산하기 */
case swimming = "SERVER05"/** 수영 */
case gymnastics = "SERVER06"/** 맨손 체조 */
...
case volleyball = "SERVER30"/** 배구 */
case etc = "SERVER999"
}
func convertHKWorkoutActivityTypeToServer(_ type: HKWorkoutActivityType) -> String {
switch type {
case .walking:
return ExerciseType.walkingSlow.rawValue /** 걷기 */
case .running:
return ExerciseType.running.rawValue /** 달리기 */
case .cycling:
return ExerciseType.outdoorCyclingSlow.rawValue /** 자전거 타기 */
case .hiking:
return ExerciseType.hiking.rawValue /** 등산 */
case .swimming:
return ExerciseType.swimming.rawValue /** 수영 */
case .gymnastics:
return ExerciseType.gymnastics.rawValue /** 맨손 체조 */
...
case .volleyball:
return ExerciseType.volleyball.rawValue /** 배구 */
default:
return ExerciseType.etc.rawValue /** 기타 */
}
}
iOS 헬스킷에서 운동 데이터를 꺼내와서 저희가 원하는 데이터 형식으로 만들어봤는데요,
생각보다 어렵진 않죠?!
이상 iOS 헬스킷 - 운동 데이터에 대한 포스팅을 마치겠습니다 ^_^
'iOS_Swift 앱개발👍' 카테고리의 다른 글
[iOS_Swift] UIImagePickerController 촬영 후 이미지 하나로 만들기_ 46 (3) | 2024.05.02 |
---|---|
[iOS_Swift] VIPER 디자인 패턴 _ 44 (2) | 2023.12.27 |
[iOS_Swift] Fastlane + Jenkins을 이용해 CI/CD를 구축해보자 - 2_43 (0) | 2023.12.20 |
[iOS_Swift] Fastlane을 이용해 CI/CD를 구축해보자 - 1_42 (2) | 2023.11.22 |
[iOS_Swift] HealthKit - 헬스킷 : 수면 데이터 마스터 (With HKCategoryType)_ 41 (1) | 2023.11.13 |