@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +266 -267
- package/package.json +2 -2
- package/pipeline/scripts/_notices.mjs +1 -1
- package/pipeline/skills/.skill-manifest.json +68 -68
- package/pipeline/skills/shared/README.md +70 -70
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
- package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
- package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
- package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
- package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
- package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
- package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
- package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
- package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
- package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
- package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
- package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
- package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
- package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
- package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
- package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
- package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
- package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
- package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
- package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
- package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
- package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
- package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
- package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
- package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
- package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
- package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
- package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
- package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
- package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
- package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
- package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
- package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
- package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
- package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
- package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
- package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
- package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
- package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
- package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
- package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
- package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
- package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
- package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
- package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
- package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
- package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
- package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
- package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
- package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
- package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
- package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
- package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
- package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
- package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
- package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
|
@@ -1,339 +1,300 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: healthkit
|
|
3
|
-
description: "
|
|
3
|
+
description: "HealthKit on iOS, iPadOS, watchOS and visionOS: HKHealthStore authorization, sample, statistics and chart-ready collection queries, saving HKQuantitySample values, background delivery, live workouts (HKWorkoutSession, HKLiveWorkoutBuilder), HKUnit, HKQuantityTypeIdentifier. Use when reading, writing or querying Health data, integrating with the Health app, displaying health metrics, logging workouts or turning on background delivery."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# HealthKit
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
HealthKit is the store behind the Health app. This skill covers asking for
|
|
11
|
+
access, reading with queries, writing samples, getting woken up for new data,
|
|
12
|
+
and running live workouts. Examples use Swift 6.3 and iOS 26.
|
|
11
13
|
|
|
12
|
-
##
|
|
14
|
+
## Setup and availability
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
- [Authorization](#authorization)
|
|
16
|
-
- [Reading Data: Sample Queries](#reading-data-sample-queries)
|
|
17
|
-
- [Reading Data: Statistics Queries](#reading-data-statistics-queries)
|
|
18
|
-
- [Reading Data: Statistics Collection Queries](#reading-data-statistics-collection-queries)
|
|
19
|
-
- [Writing Data](#writing-data)
|
|
20
|
-
- [Background Delivery](#background-delivery)
|
|
21
|
-
- [Workout Sessions](#workout-sessions)
|
|
22
|
-
- [Common Data Types](#common-data-types)
|
|
23
|
-
- [HKUnit Reference](#hkunit-reference)
|
|
24
|
-
- [Common Mistakes](#common-mistakes)
|
|
25
|
-
- [Review Checklist](#review-checklist)
|
|
26
|
-
- [References](#references)
|
|
16
|
+
### Project configuration
|
|
27
17
|
|
|
28
|
-
|
|
18
|
+
1. In Xcode, add the HealthKit capability to the target. Doing so writes the
|
|
19
|
+
entitlement for you.
|
|
20
|
+
2. Info.plist needs `NSHealthShareUsageDescription` if the app reads and
|
|
21
|
+
`NSHealthUpdateUsageDescription` if it writes.
|
|
22
|
+
3. To be launched for new data, also tick the Background Delivery option under
|
|
23
|
+
the HealthKit capability.
|
|
29
24
|
|
|
30
|
-
###
|
|
31
|
-
|
|
32
|
-
1. Enable the HealthKit capability in Xcode (adds the entitlement)
|
|
33
|
-
2. Add `NSHealthShareUsageDescription` (read) and `NSHealthUpdateUsageDescription` (write) to Info.plist
|
|
34
|
-
3. For background delivery, enable the "Background Delivery" sub-capability
|
|
35
|
-
|
|
36
|
-
### Availability Check
|
|
37
|
-
|
|
38
|
-
Always check availability before calling other HealthKit APIs. Health data is
|
|
39
|
-
available on iOS, watchOS, visionOS, iPadOS 17+, and iOS apps running on
|
|
40
|
-
Vision Pro. It is unavailable on iPadOS 16 or earlier and may be restricted by
|
|
41
|
-
managed device policy.
|
|
25
|
+
### Is health data available?
|
|
42
26
|
|
|
43
27
|
```swift
|
|
44
28
|
import HealthKit
|
|
45
29
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
30
|
+
enum Health {
|
|
31
|
+
static let store = HKHealthStore()
|
|
32
|
+
static var isUsable: Bool { HKHealthStore.isHealthDataAvailable() }
|
|
49
33
|
}
|
|
50
|
-
|
|
51
|
-
let healthStore = HKHealthStore()
|
|
52
34
|
```
|
|
53
35
|
|
|
54
|
-
|
|
55
|
-
is
|
|
56
|
-
|
|
57
|
-
|
|
36
|
+
- Check `HKHealthStore.isHealthDataAvailable()` first; nothing else in HealthKit should run before it.
|
|
37
|
+
- Data is available on iPhone, Apple Watch, Apple Vision Pro (including iPhone
|
|
38
|
+
apps running there) and iPad on iPadOS 17 and later.
|
|
39
|
+
- iPads still on iPadOS 16 or older have no Health store, and device
|
|
40
|
+
management policy can switch it off anywhere.
|
|
41
|
+
- Make one `HKHealthStore` for the whole app and share it; the class is
|
|
42
|
+
thread-safe.
|
|
43
|
+
- Enabling the capability can make Xcode add `healthkit` to
|
|
44
|
+
`UIRequiredDeviceCapabilities`. If HealthKit is an optional feature, check
|
|
45
|
+
that entry so devices without Health are not excluded from installing.
|
|
58
46
|
|
|
59
47
|
## Authorization
|
|
60
48
|
|
|
61
|
-
|
|
49
|
+
Ask only for the types the feature uses. Requesting more than needed is a
|
|
50
|
+
common App Review rejection.
|
|
62
51
|
|
|
63
52
|
```swift
|
|
64
|
-
|
|
65
|
-
let typesToShare: Set<HKSampleType> = [
|
|
66
|
-
HKQuantityType(.stepCount),
|
|
67
|
-
HKQuantityType(.activeEnergyBurned)
|
|
68
|
-
]
|
|
53
|
+
import HealthKit
|
|
69
54
|
|
|
70
|
-
|
|
55
|
+
func requestSleepAppAccess(_ store: HKHealthStore) async throws {
|
|
56
|
+
let writes: Set<HKSampleType> = [HKQuantityType(.activeEnergyBurned)]
|
|
57
|
+
let reads: Set<HKObjectType> = [
|
|
71
58
|
HKQuantityType(.stepCount),
|
|
72
59
|
HKQuantityType(.heartRate),
|
|
73
|
-
HKQuantityType(.activeEnergyBurned),
|
|
74
60
|
HKCharacteristicType(.dateOfBirth)
|
|
75
61
|
]
|
|
76
|
-
|
|
77
|
-
try await healthStore.requestAuthorization(
|
|
78
|
-
toShare: typesToShare,
|
|
79
|
-
read: typesToRead
|
|
80
|
-
)
|
|
62
|
+
try await store.requestAuthorization(toShare: writes, read: reads)
|
|
81
63
|
}
|
|
82
64
|
```
|
|
83
65
|
|
|
84
|
-
###
|
|
66
|
+
### What the status tells you
|
|
85
67
|
|
|
86
|
-
`authorizationStatus(for:)` reports
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
68
|
+
`authorizationStatus(for:)` reports only on sharing (writing). HealthKit never
|
|
69
|
+
reveals whether a read request was allowed, to protect privacy. When reading is
|
|
70
|
+
denied, queries simply return the samples this app saved itself, which looks
|
|
71
|
+
like an empty or incomplete history.
|
|
90
72
|
|
|
91
73
|
```swift
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
case .
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// User granted write access
|
|
102
|
-
break
|
|
103
|
-
case .sharingDenied:
|
|
104
|
-
// User denied write access (read denial is indistinguishable from "no data")
|
|
105
|
-
break
|
|
106
|
-
@unknown default:
|
|
107
|
-
break
|
|
74
|
+
import HealthKit
|
|
75
|
+
|
|
76
|
+
func canSave(_ type: HKObjectType, store: HKHealthStore) -> Bool? {
|
|
77
|
+
switch store.authorizationStatus(for: type) {
|
|
78
|
+
case .notDetermined: return nil
|
|
79
|
+
case .sharingAuthorized: return true
|
|
80
|
+
case .sharingDenied: return false
|
|
81
|
+
@unknown default: return false
|
|
82
|
+
}
|
|
108
83
|
}
|
|
109
84
|
```
|
|
110
85
|
|
|
111
|
-
|
|
86
|
+
`nil` here means the app may still ask.
|
|
112
87
|
|
|
113
|
-
|
|
88
|
+
## Reading samples
|
|
89
|
+
|
|
90
|
+
For one-off reads use `HKSampleQueryDescriptor` with async/await rather than
|
|
91
|
+
the older callback-based `HKSampleQuery`.
|
|
114
92
|
|
|
115
93
|
```swift
|
|
116
|
-
|
|
117
|
-
let heartRateType = HKQuantityType(.heartRate)
|
|
94
|
+
import HealthKit
|
|
118
95
|
|
|
119
|
-
|
|
120
|
-
|
|
96
|
+
func latestPulseReadings(_ store: HKHealthStore) async throws -> [Double] {
|
|
97
|
+
let pulse = HKQuantityType(.heartRate)
|
|
98
|
+
let query = HKSampleQueryDescriptor(
|
|
99
|
+
predicates: [.quantitySample(type: pulse)],
|
|
121
100
|
sortDescriptors: [SortDescriptor(\.endDate, order: .reverse)],
|
|
122
101
|
limit: 20
|
|
123
102
|
)
|
|
124
|
-
|
|
125
|
-
let
|
|
126
|
-
return
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Extracting values from samples:
|
|
130
|
-
for sample in results {
|
|
131
|
-
let bpm = sample.quantity.doubleValue(
|
|
132
|
-
for: HKUnit.count().unitDivided(by: .minute())
|
|
133
|
-
)
|
|
134
|
-
print("\(bpm) bpm at \(sample.endDate)")
|
|
103
|
+
let perMinute = HKUnit.count().unitDivided(by: .minute())
|
|
104
|
+
let samples = try await query.result(for: store)
|
|
105
|
+
return samples.map { $0.quantity.doubleValue(for: perMinute) }
|
|
135
106
|
}
|
|
136
107
|
```
|
|
137
108
|
|
|
138
|
-
##
|
|
109
|
+
## Aggregates: statistics queries
|
|
139
110
|
|
|
140
|
-
|
|
111
|
+
`HKStatisticsQueryDescriptor` returns one aggregated value: a sum, average,
|
|
112
|
+
minimum or maximum.
|
|
141
113
|
|
|
142
114
|
```swift
|
|
143
|
-
|
|
144
|
-
let calendar = Calendar.current
|
|
145
|
-
let startOfDay = calendar.startOfDay(for: Date())
|
|
146
|
-
let endOfDay = calendar.date(byAdding: .day, value: 1, to: startOfDay)!
|
|
147
|
-
|
|
148
|
-
let predicate = HKQuery.predicateForSamples(
|
|
149
|
-
withStart: startOfDay, end: endOfDay
|
|
150
|
-
)
|
|
151
|
-
let stepType = HKQuantityType(.stepCount)
|
|
152
|
-
let samplePredicate = HKSamplePredicate.quantitySample(
|
|
153
|
-
type: stepType, predicate: predicate
|
|
154
|
-
)
|
|
115
|
+
import HealthKit
|
|
155
116
|
|
|
117
|
+
func stepsToday(_ store: HKHealthStore) async throws -> Double {
|
|
118
|
+
let calendar = Calendar.current
|
|
119
|
+
let midnight = calendar.startOfDay(for: .now)
|
|
120
|
+
guard let tomorrow = calendar.date(byAdding: DateComponents(day: 1), to: midnight) else { return 0 }
|
|
121
|
+
let window = HKQuery.predicateForSamples(withStart: midnight, end: tomorrow)
|
|
156
122
|
let query = HKStatisticsQueryDescriptor(
|
|
157
|
-
predicate:
|
|
123
|
+
predicate: .quantitySample(type: HKQuantityType(.stepCount), predicate: window),
|
|
158
124
|
options: .cumulativeSum
|
|
159
125
|
)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return result?.sumQuantity()?.doubleValue(for: .count())
|
|
126
|
+
let total = try await query.result(for: store)
|
|
127
|
+
return total?.sumQuantity()?.doubleValue(for: .count()) ?? 0
|
|
163
128
|
}
|
|
164
129
|
```
|
|
165
130
|
|
|
166
|
-
|
|
167
|
-
- Cumulative types (steps, calories): `.cumulativeSum`
|
|
168
|
-
- Discrete types (heart rate, weight): `.discreteAverage`, `.discreteMin`, `.discreteMax`
|
|
131
|
+
Pick the option from the kind of data:
|
|
169
132
|
|
|
170
|
-
|
|
133
|
+
| Data | Examples | Options |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| cumulative | steps, energy burned | `.cumulativeSum` |
|
|
136
|
+
| discrete | heart rate, body mass | `.discreteAverage`, `.discreteMin`, `.discreteMax` |
|
|
171
137
|
|
|
172
|
-
|
|
138
|
+
## Time series: statistics collection queries
|
|
173
139
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
for: calendar.date(byAdding: .day, value: 1, to: Date())!
|
|
179
|
-
)
|
|
180
|
-
let startDate = calendar.date(byAdding: .day, value: -days, to: endDate)!
|
|
140
|
+
`HKStatisticsCollectionQueryDescriptor` buckets data into equal intervals,
|
|
141
|
+
which is exactly what a chart needs. It takes a `predicate`, `options`, an
|
|
142
|
+
`anchorDate` that aligns the buckets and `intervalComponents` such as
|
|
143
|
+
`DateComponents(day: 1)`.
|
|
181
144
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
)
|
|
185
|
-
let stepType = HKQuantityType(.stepCount)
|
|
186
|
-
let samplePredicate = HKSamplePredicate.quantitySample(
|
|
187
|
-
type: stepType, predicate: predicate
|
|
188
|
-
)
|
|
145
|
+
```swift
|
|
146
|
+
import HealthKit
|
|
189
147
|
|
|
148
|
+
func dailyEnergy(_ store: HKHealthStore, between start: Date, and end: Date) async throws -> [(Date, Double)] {
|
|
190
149
|
let query = HKStatisticsCollectionQueryDescriptor(
|
|
191
|
-
predicate:
|
|
150
|
+
predicate: .quantitySample(type: HKQuantityType(.activeEnergyBurned),
|
|
151
|
+
predicate: HKQuery.predicateForSamples(withStart: start, end: end)),
|
|
192
152
|
options: .cumulativeSum,
|
|
193
|
-
anchorDate:
|
|
153
|
+
anchorDate: start,
|
|
194
154
|
intervalComponents: DateComponents(day: 1)
|
|
195
155
|
)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
collection.statisticsCollection.enumerateStatistics(
|
|
201
|
-
from: startDate, to: endDate
|
|
202
|
-
) { statistics, _ in
|
|
203
|
-
let steps = statistics.sumQuantity()?
|
|
204
|
-
.doubleValue(for: .count()) ?? 0
|
|
205
|
-
dailySteps.append((date: statistics.startDate, steps: steps))
|
|
156
|
+
var days: [(Date, Double)] = []
|
|
157
|
+
try await query.result(for: store).enumerateStatistics(from: start, to: end) { bucket, _ in
|
|
158
|
+
days.append((bucket.startDate, bucket.sumQuantity()?.doubleValue(for: .kilocalorie()) ?? 0))
|
|
206
159
|
}
|
|
207
|
-
|
|
208
|
-
return dailySteps
|
|
160
|
+
return days
|
|
209
161
|
}
|
|
210
162
|
```
|
|
211
163
|
|
|
212
|
-
###
|
|
164
|
+
### Keeping a chart live
|
|
213
165
|
|
|
214
|
-
|
|
166
|
+
`results(for:)`, plural, returns an `AsyncSequence` that yields a fresh
|
|
167
|
+
collection whenever matching data changes. Consume it in a `Task` with
|
|
168
|
+
`for try await`. The descriptor is not `Sendable`, so mark the parameter
|
|
169
|
+
`sending`; the caller hands it over and does not touch it again:
|
|
215
170
|
|
|
216
171
|
```swift
|
|
217
|
-
|
|
172
|
+
import HealthKit
|
|
218
173
|
|
|
219
|
-
Task {
|
|
220
|
-
|
|
221
|
-
|
|
174
|
+
func followEnergy(_ query: sending HKStatisticsCollectionQueryDescriptor, store: HKHealthStore) -> Task<Void, Error> {
|
|
175
|
+
Task {
|
|
176
|
+
for try await update in query.results(for: store) {
|
|
177
|
+
_ = update.statisticsCollection
|
|
178
|
+
}
|
|
222
179
|
}
|
|
223
180
|
}
|
|
224
181
|
```
|
|
225
182
|
|
|
226
|
-
## Writing
|
|
227
|
-
|
|
228
|
-
Create `HKQuantitySample` objects and save them to the store.
|
|
183
|
+
## Writing
|
|
229
184
|
|
|
230
185
|
```swift
|
|
231
|
-
|
|
232
|
-
let stepType = HKQuantityType(.stepCount)
|
|
233
|
-
let quantity = HKQuantity(unit: .count(), doubleValue: count)
|
|
234
|
-
|
|
235
|
-
let sample = HKQuantitySample(
|
|
236
|
-
type: stepType,
|
|
237
|
-
quantity: quantity,
|
|
238
|
-
start: start,
|
|
239
|
-
end: end
|
|
240
|
-
)
|
|
186
|
+
import HealthKit
|
|
241
187
|
|
|
242
|
-
|
|
188
|
+
func logPushUps(_ reps: Double, over span: DateInterval, store: HKHealthStore) async throws {
|
|
189
|
+
let amount = HKQuantity(unit: .count(), doubleValue: reps)
|
|
190
|
+
let entry = HKQuantitySample(type: HKQuantityType(.pushCount), quantity: amount, start: span.start, end: span.end)
|
|
191
|
+
try await store.save(entry)
|
|
243
192
|
}
|
|
244
|
-
|
|
245
193
|
```
|
|
246
194
|
|
|
247
|
-
|
|
195
|
+
An app may delete only the samples it wrote. Data from other apps or from
|
|
196
|
+
Apple Watch is read-only to it.
|
|
248
197
|
|
|
249
|
-
## Background
|
|
198
|
+
## Background delivery
|
|
250
199
|
|
|
251
|
-
|
|
200
|
+
Background delivery launches the app when new samples of a type arrive. It
|
|
201
|
+
needs the background delivery entitlement and always works as a pair: an
|
|
202
|
+
executed `HKObserverQuery` and a call to
|
|
203
|
+
`enableBackgroundDelivery(for:frequency:)`.
|
|
252
204
|
|
|
253
205
|
```swift
|
|
254
|
-
|
|
255
|
-
let stepType = HKQuantityType(.stepCount)
|
|
256
|
-
|
|
257
|
-
try await healthStore.enableBackgroundDelivery(
|
|
258
|
-
for: stepType,
|
|
259
|
-
frequency: .hourly
|
|
260
|
-
)
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
**Pair with an `HKObserverQuery`** to handle notifications. Always call the completion handler:
|
|
206
|
+
import HealthKit
|
|
265
207
|
|
|
266
|
-
|
|
267
|
-
let
|
|
268
|
-
sampleType:
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
208
|
+
func registerWeightUpdates(_ store: HKHealthStore, refresh: @escaping @Sendable () -> Void) async throws {
|
|
209
|
+
let weight = HKQuantityType(.bodyMass)
|
|
210
|
+
let watcher = HKObserverQuery(sampleType: weight, predicate: nil) { _, finished, error in
|
|
211
|
+
defer { finished() }
|
|
212
|
+
guard error == nil else { return }
|
|
213
|
+
refresh()
|
|
214
|
+
}
|
|
215
|
+
store.execute(watcher)
|
|
216
|
+
try await store.enableBackgroundDelivery(for: weight, frequency: .daily)
|
|
274
217
|
}
|
|
275
|
-
healthStore.execute(observerQuery)
|
|
276
218
|
```
|
|
277
219
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
`HKWorkoutSession`
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
220
|
+
- Frequencies: `.immediate`, `.hourly`, `.daily`, `.weekly`.
|
|
221
|
+
- Order matters. Create the observer queries every time the app launches.
|
|
222
|
+
Register the type with `enableBackgroundDelivery` a single time; the system
|
|
223
|
+
keeps that registration across launches.
|
|
224
|
+
- The frequency is a ceiling. The app is woken at most that often, and some
|
|
225
|
+
types are capped lower (step count on iOS is at most hourly).
|
|
226
|
+
- Always call the observer's completion handler, here with `defer`.
|
|
227
|
+
- Simulator does not support background delivery. Use a device.
|
|
228
|
+
|
|
229
|
+
## Workout sessions
|
|
230
|
+
|
|
231
|
+
Live workouts combine `HKWorkoutSession` with `HKLiveWorkoutBuilder`.
|
|
232
|
+
|
|
233
|
+
| API | iOS / iPadOS | visionOS | watchOS |
|
|
234
|
+
|---|---|---|---|
|
|
235
|
+
| `HKWorkoutSession` | 17+ | 1+ | 2+ |
|
|
236
|
+
| `HKLiveWorkoutBuilder` | 26+ | - | 5+ |
|
|
237
|
+
|
|
238
|
+
- Apps that still deploy to iPhone or iPad releases before 26 must wrap the
|
|
239
|
+
live builder in an availability check.
|
|
240
|
+
- iPhone and iPad have no built-in heart rate sensor; live heart rate there
|
|
241
|
+
requires a paired external sensor. Apple Watch sessions record high-frequency
|
|
242
|
+
heart rate on their own.
|
|
243
|
+
- iPhone workouts often run with the phone locked. Before showing health
|
|
244
|
+
metrics on the Lock Screen, plan for the system flow that grants access to
|
|
245
|
+
workout data there.
|
|
297
246
|
|
|
298
247
|
```swift
|
|
299
|
-
|
|
300
|
-
let configuration = HKWorkoutConfiguration()
|
|
301
|
-
configuration.activityType = .running
|
|
302
|
-
configuration.locationType = .outdoor
|
|
303
|
-
|
|
304
|
-
let session = try HKWorkoutSession(
|
|
305
|
-
healthStore: healthStore,
|
|
306
|
-
configuration: configuration
|
|
307
|
-
)
|
|
308
|
-
session.delegate = self
|
|
248
|
+
import HealthKit
|
|
309
249
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
250
|
+
@available(iOS 26.0, *)
|
|
251
|
+
@MainActor
|
|
252
|
+
final class RideRecorder: NSObject, HKWorkoutSessionDelegate {
|
|
253
|
+
private let store: HKHealthStore
|
|
254
|
+
private var session: HKWorkoutSession?
|
|
255
|
+
private var builder: HKLiveWorkoutBuilder?
|
|
256
|
+
|
|
257
|
+
init(store: HKHealthStore) { self.store = store }
|
|
258
|
+
|
|
259
|
+
func begin() async throws {
|
|
260
|
+
let setup = HKWorkoutConfiguration()
|
|
261
|
+
setup.activityType = .cycling
|
|
262
|
+
setup.locationType = .outdoor
|
|
263
|
+
|
|
264
|
+
let session = try HKWorkoutSession(healthStore: store, configuration: setup)
|
|
265
|
+
session.delegate = self
|
|
266
|
+
let builder = session.associatedWorkoutBuilder()
|
|
267
|
+
builder.dataSource = HKLiveWorkoutDataSource(healthStore: store, workoutConfiguration: setup)
|
|
268
|
+
self.session = session
|
|
269
|
+
self.builder = builder
|
|
270
|
+
|
|
271
|
+
let now = Date()
|
|
272
|
+
session.startActivity(with: now)
|
|
273
|
+
try await builder.beginCollection(at: now)
|
|
274
|
+
}
|
|
315
275
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
276
|
+
func finish() async throws {
|
|
277
|
+
guard let activeSession = session, let activeBuilder = builder else { return }
|
|
278
|
+
activeSession.end()
|
|
279
|
+
try await activeBuilder.endCollection(at: .now)
|
|
280
|
+
_ = try await activeBuilder.finishWorkout()
|
|
281
|
+
}
|
|
319
282
|
|
|
320
|
-
func
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
session.end()
|
|
325
|
-
try await builder.endCollection(at: Date())
|
|
326
|
-
try await builder.finishWorkout()
|
|
283
|
+
nonisolated func workoutSession(_ ride: HKWorkoutSession,
|
|
284
|
+
didChangeTo toState: HKWorkoutSessionState,
|
|
285
|
+
from fromState: HKWorkoutSessionState, date: Date) {}
|
|
286
|
+
nonisolated func workoutSession(_ ride: HKWorkoutSession, didFailWithError failure: Error) {}
|
|
327
287
|
}
|
|
328
288
|
```
|
|
329
289
|
|
|
330
|
-
|
|
290
|
+
End in this order: `session.end()`, then `builder.endCollection(at:)`, then
|
|
291
|
+
`builder.finishWorkout()`.
|
|
331
292
|
|
|
332
|
-
## Common
|
|
293
|
+
## Common data types
|
|
333
294
|
|
|
334
295
|
### HKQuantityTypeIdentifier
|
|
335
296
|
|
|
336
|
-
| Identifier |
|
|
297
|
+
| Identifier | Group | Unit |
|
|
337
298
|
|---|---|---|
|
|
338
299
|
| `.stepCount` | Fitness | `.count()` |
|
|
339
300
|
| `.distanceWalkingRunning` | Fitness | `.meter()` |
|
|
@@ -346,88 +307,76 @@ For full workout lifecycle management including pause/resume, delegate handling,
|
|
|
346
307
|
| `.bodyMassIndex` | Body | `.count()` |
|
|
347
308
|
| `.height` | Body | `.meter()` |
|
|
348
309
|
| `.bodyFatPercentage` | Body | `.percent()` |
|
|
349
|
-
| `.bloodGlucose` | Lab |
|
|
310
|
+
| `.bloodGlucose` | Lab | mg/dL: `HKUnit.gramUnit(with: .milli).unitDivided(by: HKUnit.literUnit(with: .deci))` |
|
|
350
311
|
|
|
351
312
|
### HKCategoryTypeIdentifier
|
|
352
313
|
|
|
353
|
-
|
|
314
|
+
Frequently used: `.sleepAnalysis`, `.mindfulSession`, `.appleStandHour`.
|
|
354
315
|
|
|
355
316
|
### HKCharacteristicType
|
|
356
317
|
|
|
357
|
-
Read-only user
|
|
358
|
-
`.bloodType`, `.fitzpatrickSkinType`, `.wheelchairUse`,
|
|
318
|
+
Read-only values the user sets once: `.dateOfBirth`, `.biologicalSex`,
|
|
319
|
+
`.bloodType`, `.fitzpatrickSkinType`, `.wheelchairUse`, `.activityMoveMode`.
|
|
359
320
|
|
|
360
|
-
## HKUnit
|
|
321
|
+
## HKUnit quick reference
|
|
361
322
|
|
|
362
323
|
```swift
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
HKUnit
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
HKUnit.
|
|
370
|
-
HKUnit.
|
|
371
|
-
HKUnit.
|
|
372
|
-
|
|
373
|
-
// Compound units
|
|
374
|
-
HKUnit.count().unitDivided(by: .minute()) // Heart rate (bpm)
|
|
375
|
-
HKUnit.meter().unitDivided(by: .second()) // Speed (m/s)
|
|
376
|
-
|
|
377
|
-
// Prefixed units
|
|
378
|
-
HKUnit.gramUnit(with: .milli) // Milligrams
|
|
379
|
-
HKUnit.literUnit(with: .deci) // Deciliters
|
|
324
|
+
import HealthKit
|
|
325
|
+
|
|
326
|
+
let simple: [HKUnit] = [
|
|
327
|
+
.count(), .meter(), .mile(), .kilocalorie(), .jouleUnit(with: .kilo),
|
|
328
|
+
.gramUnit(with: .kilo), .pound(), .percent()
|
|
329
|
+
]
|
|
330
|
+
let beatsPerMinute = HKUnit.count().unitDivided(by: .minute())
|
|
331
|
+
let metresPerSecond = HKUnit.meter().unitDivided(by: .second())
|
|
332
|
+
let milligrams = HKUnit.gramUnit(with: .milli)
|
|
333
|
+
let decilitres = HKUnit.literUnit(with: .deci)
|
|
380
334
|
```
|
|
381
335
|
|
|
382
|
-
## Common
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
- [ ]
|
|
404
|
-
- [ ]
|
|
405
|
-
- [ ]
|
|
406
|
-
- [ ]
|
|
407
|
-
- [ ]
|
|
408
|
-
|
|
409
|
-
- [ ]
|
|
410
|
-
- [ ]
|
|
411
|
-
- [ ]
|
|
412
|
-
- [ ]
|
|
413
|
-
- [ ]
|
|
414
|
-
|
|
415
|
-
- [ ] Background delivery entitlement enabled if using `enableBackgroundDelivery`
|
|
416
|
-
- [ ] Background delivery tested on device and frequency caps considered
|
|
417
|
-
- [ ] Workout sessions properly ended and builder finalized
|
|
418
|
-
- [ ] Workout API availability and live heart-rate sensor requirements handled
|
|
419
|
-
- [ ] Write operations only for sample types the app created
|
|
336
|
+
## Common mistakes
|
|
337
|
+
|
|
338
|
+
- **Asking for everything.** Extra types are an App Review risk.
|
|
339
|
+
- **Reading the status as if it covered reads.** `.sharingAuthorized` can be
|
|
340
|
+
checked before saving. A read denial is invisible; the app just sees its own
|
|
341
|
+
samples, or empty and partial results.
|
|
342
|
+
- **Skipping `isHealthDataAvailable()`.** Handle an unavailable or restricted
|
|
343
|
+
store gracefully instead of crashing.
|
|
344
|
+
- **Callback queries in new async code.** Prefer the descriptor types and keep
|
|
345
|
+
large queries off the main actor.
|
|
346
|
+
- **Not calling the observer completion handler.** HealthKit delays and
|
|
347
|
+
eventually stops background deliveries.
|
|
348
|
+
- **Expecting `.immediate` to be immediate.** The system caps delivery; test
|
|
349
|
+
on a device.
|
|
350
|
+
- **Summing discrete values.** Match the statistics option to the type.
|
|
351
|
+
|
|
352
|
+
## Review checklist
|
|
353
|
+
|
|
354
|
+
- [ ] `isHealthDataAvailable()` is the first HealthKit call
|
|
355
|
+
- [ ] Only the types the feature needs are requested
|
|
356
|
+
- [ ] Info.plist has `NSHealthShareUsageDescription` and/or `NSHealthUpdateUsageDescription`
|
|
357
|
+
- [ ] The HealthKit capability is on
|
|
358
|
+
- [ ] Write authorization is checked before saving; read denial is handled as empty or partial data
|
|
359
|
+
- [ ] One `HKHealthStore` is shared
|
|
360
|
+
- [ ] Async descriptors are used instead of callback queries
|
|
361
|
+
- [ ] Heavy queries do not run on the main thread
|
|
362
|
+
- [ ] Statistics options match the type (cumulative or discrete)
|
|
363
|
+
- [ ] Background delivery is paired with an `HKObserverQuery` created at launch whose `completionHandler` is always called
|
|
364
|
+
- [ ] The background delivery entitlement is present when `enableBackgroundDelivery` is used
|
|
365
|
+
- [ ] Background delivery was tested on a device with its frequency caps in mind
|
|
366
|
+
- [ ] Workout sessions are ended and their builders finished
|
|
367
|
+
- [ ] Workout API availability and the external heart-rate sensor requirement are handled
|
|
368
|
+
- [ ] Deletes and edits touch only samples the app created
|
|
420
369
|
|
|
421
370
|
## References
|
|
422
371
|
|
|
423
|
-
-
|
|
424
|
-
- [HealthKit
|
|
425
|
-
- [HKHealthStore](https://
|
|
426
|
-
- [HKSampleQueryDescriptor](https://
|
|
427
|
-
- [HKStatisticsQueryDescriptor](https://
|
|
428
|
-
- [HKStatisticsCollectionQueryDescriptor](https://
|
|
429
|
-
- [HKWorkoutSession](https://
|
|
430
|
-
- [HKLiveWorkoutBuilder](https://
|
|
431
|
-
- [Setting up HealthKit](https://
|
|
432
|
-
- [
|
|
433
|
-
- [Configuring HealthKit access](https://
|
|
372
|
+
- [HealthKit patterns](references/healthkit-patterns.md) - full workout manager, watch-to-phone mirroring, platform quirks and permission changes, more on background delivery, anchored queries, predicates, chart data, SwiftUI integration, characteristics
|
|
373
|
+
- [HealthKit](https://developer.apple.com/documentation/healthkit)
|
|
374
|
+
- [HKHealthStore](https://developer.apple.com/documentation/healthkit/hkhealthstore)
|
|
375
|
+
- [HKSampleQueryDescriptor](https://developer.apple.com/documentation/healthkit/hksamplequerydescriptor)
|
|
376
|
+
- [HKStatisticsQueryDescriptor](https://developer.apple.com/documentation/healthkit/hkstatisticsquerydescriptor)
|
|
377
|
+
- [HKStatisticsCollectionQueryDescriptor](https://developer.apple.com/documentation/healthkit/hkstatisticscollectionquerydescriptor)
|
|
378
|
+
- [HKWorkoutSession](https://developer.apple.com/documentation/healthkit/hkworkoutsession)
|
|
379
|
+
- [HKLiveWorkoutBuilder](https://developer.apple.com/documentation/healthkit/hkliveworkoutbuilder)
|
|
380
|
+
- [Setting up HealthKit](https://developer.apple.com/documentation/healthkit/setting-up-healthkit)
|
|
381
|
+
- [Apple guide: authorizing health data access](https://developer.apple.com/documentation/healthkit/authorizing-access-to-health-data)
|
|
382
|
+
- [Configuring HealthKit access](https://developer.apple.com/documentation/xcode/configuring-healthkit-access)
|