์๋ ํ์ธ์ Foma ๐ ์ ๋๋ค!
์ค๋์ ๋ด ์์ดํฐ์ ์๋ ๋์ ๊ฑด๊ฐ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์๋ณด๊ณ ๋ ๊ธฐ๋กํด๋ณด๋ ๊ฒ์ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํฉ๋๋ค!
๋ฐ๋ก ์์ํ ๊ฒ์~
Info.plist
์๋์ ๊ฐ์ด ๋ ์์ฒญ์ ๋ฃ์ด์ค๋๋ค.
NSHealthShareUsageDescription ๋ ์๋ก์ด ๊ฑด๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ ๋
NSHealthUpdateUsageDescription ๋ ๊ธฐ์กด์ ๊ฑด๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ฌ ๋ ํ์ํด์.
<key>NSHealthShareUsageDescription</key>
<string>๊ฑด๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ธ๋ ํ์ํด์.</string>
<key>NSHealthUpdateUsageDescription</key>
<string>๊ฑด๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋๋ฐ ํ์ํด์.</string>
Signing & Capability
์ฑ์ Targets์ Signing & Capbility์์ ์๋์ ๊ฐ์ด HealthKit์ ์ถ๊ฐํด์ฃผ์ธ์!
๋ฐ์ดํฐ ์ธํ
HealthKit์ import ํด์ฃผ์ธ์!
import HealthKit
๊ฐ์ฅ ๋จผ์ HKHealthStore ์ธ์คํด์ค๋ฅผ ์์ฑํด์ค๋๋ค.
let healthStore = HKHealthStore()
HKHealthStore๋ ํฌ์คํท์ ๋ชจ๋ ๋ฐ์ดํฐ์ ํ์ฉ์ ๊ด๋ฆฌํ๋ ํด๋์ค์ ๋๋ค.
์๋์ ๊ฐ์ด ํฌ์ค์คํ ์ด์ ๊ถํ์ ์์ฒญํฉ๋๋ค.
๊ทผ๋ฐ ๊ถํ์ ์์ฒญํ๊ธฐ ์ํด์ ๋๊ฐ์ง ํ๋ผ๋ฏธํฐ๊ฐ ํ์ํ๋ฐ์.
toShare๋ ๋ฐ์ดํฐ๋ฅผ ์ฐ๊ธฐ ์ํ ์์ฒญ, read๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ ์ํ ์์ฒญ์ ๋๋ค.
์ ๋ ๋ค์๊ณผ ๊ฐ์ด ์๋ฉด ์ ๋ณด์ ๋ํ ์ฐ๊ธฐ์ ์ฝ๊ธฐ ํ์ ์ ์์ฑํด์ค๋๋ค.
let typeToShare:HKCategoryType? = HKObjectType.categoryType(forIdentifier: .sleepAnalysis)
let typeToRead:HKSampleType? = HKObjectType.categoryType(forIdentifier: .sleepAnalysis)
์ฉ๋์ ๋ฐ๋ผ์ ๋ค์ํ๊ฒ ํ์ ์ ์ค์ ํ ์ ์์ต๋๋ค.
์๋ฉด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ฐฐ์ด์ ๋ง๋ค์ด ์ค๋๋ค.
var sleepData:[HKCategorySample] = []
๋ฐ์ดํฐ ์์ฒญ
func configure() {
if !HKHealthStore.isHealthDataAvailable() {
requestAuthorization()
}else {
retrieveSleepData()
}
}
func requestAuthorization() {
self.healthStore.requestAuthorization(toShare: Set([typeToShare!]), read: Set([typeToRead!])) { success, error in
if error != nil {
print(error.debugDescription)
}else{
if success {
print("๊ถํ์ด ํ๋ฝ๋์์ต๋๋ค.")
}else{
print("๊ถํ์ด ์์ง ์์ด์.")
}
}
}
}
์ด๋ ๊ฒ ํ๋ฉด ์๋์ ๊ฐ์ด ์์ฒญ ํ๋ฉด์ด ๋์ฌ๊ฑฐ์์.
๋ฐ์ดํฐ ๋ฐ์์ค๊ธฐ
predicate๋ก ๋ฐ์์ฌ ๋ฐ์ดํฐ์ ๋ ์ง ๋ฒ์๋ฅผ ์ค์ ํด์ค๋๋ค.
sortDescriptor๋ก ๋ด๋ฆผ์ฐจ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ต๋๋ค.
query์ ์ ๋ ์ค์ ์ ๋ฃ๊ณ limit์ ์ํ๋ ๋ฐ์ดํฐ๋งํผ ์ค์ ํด์ค๋๋ค.
๋ง์ง๋ง์ผ๋ก ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ sleepData์ ๋ฃ์ด์ค๋๋ค. (ํ ์ด๋ธ๋ทฐ์ ๋ฐ์ดํฐ๋ฅผ ๋์ธ๊ฑฐ๋ผ ์๋์ ๊ฐ์ด reload๋ฅผ ํด์ค๋๋ค.)
func retrieveSleepData() {
let start = makeStringToDate(str: "2021-05-01")
let end = Date()
let predicate = HKQuery.predicateForSamples(withStart:start, end: end, options: .strictStartDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
let query = HKSampleQuery(sampleType: typeToRead!, predicate: nil, limit: 30, sortDescriptors: [sortDescriptor]) { [weak self] (query, sleepResult, error) -> Void in
if error != nil {
return
}
if let result = sleepResult {
DispatchQueue.main.async {
self?.sleepData = result as? [HKCategorySample] ?? []
self?.table.reloadData()
}
}
}
healthStore.execute(query)
}
๋ฐ์ดํฐ ํ์ธํ๊ธฐ
์๋์ ๊ฐ์ด ๋ฐ์ดํธ๋ฅผ ๋ฌธ์์ด๋ก ๋ฐ๊ฟ์ฃผ๋ ํจ์์ ๋ฌธ์์ด์ ๋ฐ์ดํธ๋ก ๋ฐ๊ฟ์ฃผ๋ ํจ์๋ฅผ ์ธํ ํด์ค๋๋ค.
func makeStringToDate(str:String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.locale = Locale(identifier: "ko_KR")
dateFormatter.timeZone = TimeZone(abbreviation: "KST")
return dateFormatter.date(from: str)!
}
func makeStringToDateWithTime(str:String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd-HH:mm"
dateFormatter.locale = Locale(identifier: "ko_KR")
dateFormatter.timeZone = TimeZone(abbreviation: "KST")
return dateFormatter.date(from: str)!
}
func dateToString(date:Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
return dateFormatter.string(from: date)
}
func dateToStringOnlyTime(date:Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm"
return dateFormatter.string(from: date)
}
๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํด์ ํ ์ด๋ธ๋ทฐ ๋ฐ์ดํฐ์์ค์ ์ธ์ ๋ถํฐ ์ธ์ ๊น์ง ์ค๋์ง ํ์ธํด์ค๋๋ค.
extension ViewController:UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sleepData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let sleep = sleepData[indexPath.row]
let cell = table.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let date = dateToString(date: sleep.startDate)
let start = dateToStringOnlyTime(date: sleep.startDate)
let end = dateToStringOnlyTime(date: sleep.endDate)
cell.textLabel?.text = "\(date): \(start)๋ถํฐ ~ \(end)๊น์ง ์ค๋ค์."
return cell
}
}
์๋์ ๊ฐ์ด 5์ 1์ผ๋ถํฐ ํ์ฌ๊น์ง ์ ๊ฐ ๋ช์๋ถํฐ ๋ช์๊น์ง ์ค๋์ง ๋ฐ์ดํฐ๊ฐ ์ ๋์ค๊ฒ ๋ฉ๋๋ค!
๋ฐ์ดํฐ ์ ์ฅํ๊ธฐ
์์๋ณด๊ธฐ ์ฝ๊ฒ 6์ 8์ผ 10์๋ถํฐ 7์ 1์ผ 11์๊น์ง ์๋ฉดํ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด๋ณด๊ฒ ์ต๋๋ค.
func saveSleepData() {
let start = makeStringToDateWithTime(str: "2021-07-10 10:00")
let end = makeStringToDateWithTime(str: "2021-07-10 11:00")
let object = HKCategorySample(type: typeToShare!, value: HKCategoryValueSleepAnalysis.inBed.rawValue, start: start,end: end)
healthStore.save(object, withCompletion: { (success, error) -> Void in
if error != nil {
return
}
if success {
print("์๋ฉด ๋ฐ์ดํฐ ์ ์ฅ ์๋ฃ!")
self.retrieveSleepData()
} else {
print("์๋ฉด ๋ฐ์ดํฐ ์ ์ฅ ์คํจ...")
}
})
}
์ด์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ๊ธฐ ์ํด retrieveSleepData์์ predicate๋ฅผ nil๋ก ์ค์ ํด์ค ๋ค ์คํ์ํต๋๋ค. (๋ฒ์๋ฅผ ์ ํด์ฃผ์ง ์๋ ๊ฒ์ ๋๋ค,)
HKSampleQuery(sampleType: typeToRead!, predicate: nil, limit: 30,...)
์ด๋ ๊ฒ ํ๋ฉด ๊ฐ์ฅ ์ต๊ทผ์ ์ถ๊ฐํ 7์์ ์๋ฉดํ ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค!
์ค๋์ ์ด๋ ๊ฒ ๊ฑด๊ฐ ๋ฐ์ดํฐ ์ค ์๋ฉด ์ ๋ณด๋ฅผ ๋ฐ์์ค๊ณ ๋ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋๋ฐ์.
์๋ฉด๋ฟ๋ง ์๋๋ผ ์ฒด์จ,๊ฑธ์,์ฌ์ฅ๋ฐ๋์ ๋ฑ ์ง์ง ์์ฒญ ๋ง์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํน์๋ผ๋ ๊ถ๊ธํ ์ ์ด ์๊ฑฐ๋ ํ๋ฆฐ ์ ์ด ์๋ค๋ฉด ๋๊ธ๋ก ์๋ ค์ฃผ์ธ์!
Source Code
Reference
๋๊ธ