WWDC2020 : Getting started with HealthKit
WWDC2020 : Synchronize health data with HealthKit
2020 : Beyond counting steps
HealthKit Officail Document
HealthKit Article : Setting Up HealthKit
override func viewDidLoad() {
super.viewDidLoad()
if HKHealthStore.isHealthDataAvailable() {
}
}
override func viewDidLoad() {
super.viewDidLoad()
if HKHealthStore.isHealthDataAvailable() {
let healthStore = HKHealthStore()
let readDataTypes : Set = [HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)!,
HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.distanceWalkingRunning)!
]
healthStore.requestAuthorization(toShare: nil, read: readDataTypes) { (success, error) in
if !success {
// Handle the error here.
} else {
// Enter your logic here.
}
}
}
let sampleType = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)
let today = Date()
let startDate = Calendar.current.date(byAdding: .day, value: -7, to: today)
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: today, options: HKQueryOptions.strictEndDate)
let query = HKSampleQuery.init(sampleType: sampleType!,
predicate: predicate,
limit: HKObjectQueryNoLimit,
sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)])
/// Mark: - 한달의 걸음 수와 걸은 시간을 날짜별로 가져오는 함수
func getOneMonthStepCountAndWalkingTimePerDay() {
var realmWalking : [Walking] = []
let sampleType = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)
let today = Date()
let startDate = Calendar.current.date(byAdding: .day, value: -7, to: today)
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: today, options: HKQueryOptions.strictEndDate)
let query = HKSampleQuery.init(sampleType: sampleType!,
predicate: predicate,
limit: HKObjectQueryNoLimit,
sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)]) { (query, results, error) in
var dateOneIndexBeforeBuffer : Date? = nil
var walkingDataBuffer : Walking = Walking()
var stepCountBuffer : Int = 0
var walkingSecondBuffer : Double = 0.0
print("------------------------------------------------------------------------------------")
results?.compactMap{
$0
}.forEach{ stepCountInfo in
// Apple Watch와 중복 계산을 막아준다.
if !stepCountInfo.description.contains("Watch"){
// Day 구분을 위해 StartDate에서 시간을 지워준다.
let startDate = convertStringToDate(dateString: (convertDateToString(date: stepCountInfo.startDate, format: "yyMMdd")), format: "yyMMdd")
// 하나 전 인덱스와 비교해준다.
if dateOneIndexBeforeBuffer != nil {
// 시작일이 전 인덱스의 시작일과 다르다면 날짜가 바뀐 것.
print("RESULT :: \(stepCountInfo.description)")
if startDate < dateOneIndexBeforeBuffer! {
// 날짜가 바뀌면 해당 날짜와, 해당 일의 걸음 수 걸음 시간 각각의 총 합을 객체에 넣어준다.
// 인덱스 (인덱스는 날짜로 선언한다 가변적인 데이터에 대응하기 위해 같은 날짜의 데이터는 Realm에서 Update & Insert를 진행한다.
walkingDataBuffer.id = dateOneIndexBeforeBuffer!.millisecondsSince1970
print("*** WALKING DATE PER CELL :: \(walkingDataBuffer.id)")
// 걸음 수
walkingDataBuffer.walkingCount = stepCountBuffer
print("*** TOTAL WALKING COUNT PER CELL :: \(walkingDataBuffer.walkingCount)")
// 운동 시간
walkingDataBuffer.walkingSecond = Int(round(walkingSecondBuffer))
print("*** TOTAL WALKING TIME PER CELL :: \(walkingDataBuffer.walkingSecond)")
print("------------------------------------------------------------------------------------")
// 리셋 버퍼 벨류
walkingSecondBuffer = 0.0
stepCountBuffer = 0
// DB에 들어갈 객체에 넣어준다.
realmWalking.append(walkingDataBuffer)
}
}
// 걸은 시간
// 운동을 마친 시간과 시작 시간의 timeIntervalSinceReferenceDate 값을 빼주면 운동을 한 시간이 계산된다.
let walkingSecond = stepCountInfo.endDate.timeIntervalSince1970 - stepCountInfo.startDate.timeIntervalSince1970
// 걸은 시간을 더해준다.
walkingSecondBuffer += walkingSecond
// 걸음 수
let stepCount = Int(stepCountInfo.description.components(separatedBy: " count")[0])
// 걸음 수를 더해준다.
stepCountBuffer += stepCount ?? 0
// 다음 인덱스에서 확인할 수 있게 Date를 dateOneIndexBeforeBuffer 에 저장해준다.
dateOneIndexBeforeBuffer = startDate
}
}
}
healthStore.execute(query)
}
if !stepCountInfo.description.contains("Watch")
/// 설정한 기간동안의 걸음 수를 조회할 수 있는 쿼리.
/// - Parameter completion: cumulative parameter sum
func getTodaysSteps(completion: @escaping (Double) -> Void) {
let stepsQuantityType = HKQuantityType.quantityType(forIdentifier: .stepCount)!
let now = Date()
let startDate = Calendar.current.date(byAdding: .day, value: -6, to: Date())!
let predicate = HKQuery.predicateForSamples(
withStart: startDate,
end: now,
options: .strictStartDate
)
let query = HKStatisticsQuery(
quantityType: stepsQuantityType,
quantitySamplePredicate: predicate,
options: .separateBySource
) { _, result, _ in
guard let result = result, let sum = result.sumQuantity() else {
print("Step Zero")
completion(0.0)
return
}
print("result check \(result)")
completion(sum.doubleValue(for: HKUnit.count()))
}
healthStore.execute(query)
}
// 날짜별 스탭카운트 얻기
func getStepCountPerDay(finishCompletion: @escaping () -> Void){
guard let sampleType = HKObjectType.quantityType(forIdentifier: .stepCount)
else {
return
}
let calendar = Calendar.current
var dateComponents = DateComponents()
dateComponents.day = 1
var anchorComponents = calendar.dateComponents([.day, .month, .year], from: Date())
anchorComponents.hour = 0
let anchorDate = calendar.date(from: anchorComponents)
let stepsCumulativeQuery = HKStatisticsCollectionQuery(quantityType: sampleType, quantitySamplePredicate: nil, options: .cumulativeSum, anchorDate: anchorDate!, intervalComponents: dateComponents
)
// Set the results handler
stepsCumulativeQuery.initialResultsHandler = {query, results, error in
let endDate = Date()
let startDate = calendar.date(byAdding: .day, value: -30, to: endDate, wrappingComponents: false)
if let myResults = results{
myResults.enumerateStatistics(from: startDate!, to: endDate as Date) { [self] statistics, stop in
if let quantity = statistics.sumQuantity(){
let date = statistics.startDate
let steps = quantity.doubleValue(for: HKUnit.count())
print("START DATE :: \(statistics.startDate)")
print("STEP COUNT :: \(steps)")
print("-------------------------------------------------------------")
}
}
} else {
print("STEP COUNT DATA NIL")
}
}
HKHealthStore().execute(stepsCumulativeQuery)
finishCompletion()
}
if let quantity = statistics.sumQuantity()