Meet the HealthKit Medications API
App Services 入门 2m

认识 HealthKit 药物 API

Meet the HealthKit Medications API

2025年6月9日

在 Apple 官方观看视频

一句话判断

HealthKit 终于开放药物数据读取了——HKUserAnnotatedMedicationHKMedicationDoseEvent 让你可以构建用药提醒、副作用追踪、用药依从性分析等功能。

这场 Session 讲了什么

Health 应用从 iOS 15 开始支持药物追踪,但第三方 app 一直无法读取这些数据。现在 Medications API 打开了这扇门。

两个核心对象:

HKUserAnnotatedMedication:用户添加到 Health 的药物,包含:

  • isArchived:是否已归档(不再使用)
  • hasSchedule:是否设置了提醒计划
  • nickname:用户自定义昵称
  • medicationConcept:药物概念,包含唯一标识符、名称、剂型(胶囊/片剂/液体)、相关临床编码(如 RxNorm)

HKMedicationDoseEvent:用药记录,是一种新的 HKSample,包含:

  • 用药状态(taken、skipped、snoozed、未交互)
  • 剂量数量(scheduled vs actual 的差异)
  • 与药物概念的关联(通过 medicationConceptIdentifier)
  • 计划时间和实际时间

查询方式:

  • HKUserAnnotatedMedicationQueryDescriptor 查询药物列表,支持 isArchivedhasSchedule 谓词
  • 剂量事件是 HKSample,可以用 Sample Query、Anchored Object Query、Observer Query
  • 授权机制特殊:用户授权某个药物后,你的 app 自动获得该药物和其所有剂量事件的读取权限

Demo app 展示了完整流程:查询授权药物 -> 显示今日最近一次用药 -> 用 RxNorm 编码关联副作用 -> 用 emoji 表示症状强度 -> 用 Anchored Object Query 做图表实时更新。

值得深挖的点

  1. 授权是 per-object 的,不是 per-type 的。用户可以在 Health 应用里选择性地授权某些药物给你的 app。新增药物时,Health 应用会在添加界面直接提示用户选择是否分享给你的 app——不需要你的 app 做任何事。

  2. RxNorm 编码是连接药物和外部数据的桥梁medicationConcept.relatedCodings 包含标准化的临床编码,RxNorm 是其中最常用的。Demo 用它做药物-副作用映射,你也可以用来关联教育内容、药物交互信息等。

  3. Anchored Object Query 在剂量事件场景需要特殊处理。剂量事件可能补录过去几天的、被删除后重新保存的、或者从未交互的提醒。处理不当会显示不一致的数据。

  4. 不需要单独请求剂量事件的授权。授权药物 = 授权该药物的剂量事件,一步到位。

代码片段

查询授权药物列表:

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 上都可用。
应用服务 Health & Fitness