认识 HealthKit 药物 API
Meet the HealthKit Medications API
2025年6月9日
一句话判断
HealthKit 终于开放药物数据读取了——HKUserAnnotatedMedication 和 HKMedicationDoseEvent 让你可以构建用药提醒、副作用追踪、用药依从性分析等功能。
这场 Session 讲了什么
Health 应用从 iOS 15 开始支持药物追踪,但第三方 app 一直无法读取这些数据。现在 Medications API 打开了这扇门。
两个核心对象:
HKUserAnnotatedMedication:用户添加到 Health 的药物,包含:
isArchived:是否已归档(不再使用)hasSchedule:是否设置了提醒计划nickname:用户自定义昵称medicationConcept:药物概念,包含唯一标识符、名称、剂型(胶囊/片剂/液体)、相关临床编码(如 RxNorm)
HKMedicationDoseEvent:用药记录,是一种新的 HKSample,包含:
- 用药状态(taken、skipped、snoozed、未交互)
- 剂量数量(scheduled vs actual 的差异)
- 与药物概念的关联(通过 medicationConceptIdentifier)
- 计划时间和实际时间
查询方式:
HKUserAnnotatedMedicationQueryDescriptor查询药物列表,支持isArchived和hasSchedule谓词- 剂量事件是 HKSample,可以用 Sample Query、Anchored Object Query、Observer Query
- 授权机制特殊:用户授权某个药物后,你的 app 自动获得该药物和其所有剂量事件的读取权限
Demo app 展示了完整流程:查询授权药物 -> 显示今日最近一次用药 -> 用 RxNorm 编码关联副作用 -> 用 emoji 表示症状强度 -> 用 Anchored Object Query 做图表实时更新。
值得深挖的点
-
授权是 per-object 的,不是 per-type 的。用户可以在 Health 应用里选择性地授权某些药物给你的 app。新增药物时,Health 应用会在添加界面直接提示用户选择是否分享给你的 app——不需要你的 app 做任何事。
-
RxNorm 编码是连接药物和外部数据的桥梁。
medicationConcept.relatedCodings包含标准化的临床编码,RxNorm 是其中最常用的。Demo 用它做药物-副作用映射,你也可以用来关联教育内容、药物交互信息等。 -
Anchored Object Query 在剂量事件场景需要特殊处理。剂量事件可能补录过去几天的、被删除后重新保存的、或者从未交互的提醒。处理不当会显示不一致的数据。
-
不需要单独请求剂量事件的授权。授权药物 = 授权该药物的剂量事件,一步到位。
代码片段
查询授权药物列表:
func fetchMedications() async throws -> [HKUserAnnotatedMedication] {
let descriptor = HKUserAnnotatedMedicationQueryDescriptor(
predicates: [], // 不需要谓词,获取所有已授权药物
sortDescriptors: [],
limit: HKObjectQueryNoLimit
)
return try await descriptor.results(for: healthStore)
}
查询今日某药物的最近一次用药:
func fetchLatestDose(for medication: HKMedicationConcept) async throws -> HKMedicationDoseEvent? {
let today = Calendar.current.startOfDay(for: Date())
let predicate = HKSamplePredicate.medicationDoseEvent(
.init(
medicationConceptIdentifier: medication.identifier,
logStatus: .taken,
startDate: today
)
)
let descriptor = HKSampleQueryDescriptor(
predicates: predicate,
sortDescriptors: [SortDescriptor(\.startDate, order: .reverse)],
limit: 1
)
return try await descriptor.results(for: healthStore).first
}
用 RxNorm 编码关联副作用:
let rxNormSystem = "http://www.nlm.nih.gov/research/urns/urn:oid:2.16.840.1.113883.6.88"
func sideEffects(for concept: HKMedicationConcept) -> [SymptomType] {
let rxNormCodes = concept.relatedCodings
.filter { $0.system?.absoluteString == rxNormSystem }
.compactMap { $0.code }
return rxNormCodes.flatMap { symptomDatabase[$0] ?? [] }
}
最佳实践
- 用 per-object authorization API 请求药物授权,不要用 sample type 方式。用
HKUserAnnotatedMedicationType作为 object type。 - 锚定 Object Query 做图表数据。剂量事件是流式更新的,用锚定查询能高效获取增量变化,避免重复处理。
- 处理剂量事件的非线性特性。事件可能是补录的、被删除的、snooz 的。用 anchored query 的 deleted objects 清理数据模型。
- 用 RxNorm 做标准化关联。不同设备上药物名称可能不同,但 RxNorm 编码是稳定的跨设备标识符。
- 用户新增药物时,Health 应用会自动处理授权 UI,你的 app 只需要在下次查询时发现新数据就行。
还有什么值得关注
- “Getting started with HealthKit” session 是 HealthKit 基础,如果你之前没用过 HealthKit 建议先看。
- HKMedicationDoseEvent 的 log status 有很多种,理解每种的含义对数据处理很重要。
- 药物概念的
generalForm属性(tablet、capsule、liquid)可以用来定制 UI。 - 这个 API 在 iOS、iPadOS、visionOS 上都可用。