# HealthKit

### 教學連結

* [**How to Import and Export Health App Data using Swift**](https://www.youtube.com/watch?v=y1aWWC0MpNs\&t=174s)
* [**HealthKit Tutorial With Swift: Getting Started**](https://www.raywenderlich.com/159019/healthkit-tutorial-swift-getting-started)

### Memo

* 三大重點：取得資料授權、讀、寫
  * How to request permission and access HealthKit data
  * How to read HealthKit data
  * How to write data to HealthKit’s central repository   &#x20;
* 授權

```swift
//3. Prepare a list of types you want HealthKit to read and write
let healthKitTypesToWrite: Set<HKSampleType> = [bodyMassIndex,
                                                activeEnergy,
                                                HKObjectType.workoutType()]

let healthKitTypesToRead: Set<HKObjectType> = [dateOfBirth,
                                               bloodType,
                                               biologicalSex,
                                               bodyMassIndex,
                                               height,
                                               bodyMass,
                                               HKObjectType.workoutType()]
//4. Request Authorization
HKHealthStore().requestAuthorization(toShare: healthKitTypesToWrite,
                                     read: healthKitTypesToRead) { (success, error) in
  completion(success, error)
}
```

* 讀

```swift
class func getMostRecentSample(for sampleType: HKSampleType,
                               completion: @escaping (HKQuantitySample?, Error?) -> Swift.Void) {

//1. Use HKQuery to load the most recent samples.  
let mostRecentPredicate = HKQuery.predicateForSamples(withStart: Date.distantPast,
                                                      end: Date(),
                                                      options: .strictEndDate)

let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate,
                                      ascending: false)

let limit = 1

let sampleQuery = HKSampleQuery(sampleType: sampleType,
                                predicate: mostRecentPredicate,
                                limit: limit,
                                sortDescriptors: [sortDescriptor]) { (query, samples, error) in

    //2. Always dispatch to the main thread when complete.
    DispatchQueue.main.async {

      guard let samples = samples,
            let mostRecentSample = samples.first as? HKQuantitySample else {

            completion(nil, error)
            return
      }

      completion(mostRecentSample, nil)
    }
  }

HKHealthStore().execute(sampleQuery)
}
```

* 寫

```swift
class func saveBodyMassIndexSample(bodyMassIndex: Double, date: Date) {

  //1.  Make sure the body mass type exists  
  guard let bodyMassIndexType = HKQuantityType.quantityType(forIdentifier: .bodyMassIndex) else {
    fatalError("Body Mass Index Type is no longer available in HealthKit")
  }

  //2.  Use the Count HKUnit to create a body mass quantity
  let bodyMassQuantity = HKQuantity(unit: HKUnit.count(),
                                    doubleValue: bodyMassIndex)

  let bodyMassIndexSample = HKQuantitySample(type: bodyMassIndexType,
                                             quantity: bodyMassQuantity,
                                             start: date,
                                             end: date)

  //3.  Save the same to HealthKit
  HKHealthStore().save(bodyMassIndexSample) { (success, error) in

    if let error = error {
      print("Error Saving BMI Sample: \(error.localizedDescription)")
    } else {
      print("Successfully saved BMI Sample")
    }
  }
}
```

## Tell if data was user entered manually

### 教學連結

* [**Ignore manual entries from Apple Health app as Data Source**](https://stackoverflow.com/questions/31184628/ignore-manual-entries-from-apple-health-app-as-data-source/31254817#31254817)

  ```objectivec
  [NSPredicate predicateWithFormat:@"metadata.%K != YES", HKMetadataKeyWasUserEntered];
  ```
* [**Detect if HealthKit activity has been entered manually**](https://stackoverflow.com/questions/32147812/detect-if-healthkit-activity-has-been-entered-manually)
  * The bundle identifier of the entry if made manually will be **com.apple.Health**, which is the bundle identifier of the Health app. Notice the capital H. When you pull your data just ignore the data which has a bundle identifier of com.apple.Health.

    That way you will be only considering activities which are not manual
* [**Using predicates to filter out sources when doing a query**](https://stackoverflow.com/questions/29311891/using-predicates-to-filter-out-sources-when-doing-a-query)

### Memo

* 非手動輸入

```
(lldb) po samples[1].source.bundleIdentifier
"com.apple.health.6AE18D38-5413-4679-BDBA-7FBD1DA9A45C"

(lldb) po samples[1].source.name
"電商科的iPhoneX"

(lldb) po samples[1].metadata
nil
```

* 手動輸入

```
(lldb) po samples[2].source.bundleIdentifier
"com.apple.Health"

(lldb) po samples[2].source.name
"健康"

(lldb) po samples[2].metadata
▿ Optional<Dictionary<String, Any>>
  ▿ some : 1 element
    ▿ 0 : 2 elements
      - key : "HKWasUserEntered"
      - value : 1
```

## Create Multiple predicate

### 教學連結

* [**HealthKit: create a predicate for specific sources and date range**](https://stackoverflow.com/questions/34400682/healthkit-create-a-predicate-for-specific-sources-and-date-range)
  * Use NSCompoundPredicate
* [**NSCompoundPredicate**](https://developer.apple.com/documentation/foundation/nscompoundpredicate)
* [ **程式範例**](https://blog.csdn.net/kmyhy/article/details/78356497)

  ```objectivec
  //1. Get all workouts with the "Other" activity type.
  let workoutPredicate = HKQuery.predicateForWorkouts(with: .other)

  //2. Get all workouts that only came from this app.
  let sourcePredicate = HKQuery.predicateForObjects(from: HKSource.default())

  //3. Combine the predicates into a single predicate.
  let compound = NSCompoundPredicate(andPredicateWithSubpredicates: [workoutPredicate,
                                                                     sourcePredicate])
  ```

## 獲取統計數據

### 教學連結

* [**HKStatisticsCollectionQuery**](https://developer.apple.com/documentation/healthkit/hkstatisticscollectionquer)
* [**Get total step count for every date in HealthKit**](https://stackoverflow.com/questions/29582462/get-total-step-count-for-every-date-in-healthkit)

### Memo

* 心率單位

  ```swift
  HKUnit(from: "count/min")
  or
  HKUnit.count().unitDivided(by: HKUnit.minute())
  ```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jacky-chen.gitbook.io/jackychen/foundation/healthkit.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
