大多数浏览器和
Developer App 均支持流媒体播放。
-
探索 HealthKit 中的身心健康 API
了解如何使用 HealthKit 将身心健康功能整合到你的 App 中。HealthKit 中提供了适用于“心理状态”、“抑郁风险”和“焦虑风险”的新 API。我们将深入探索情绪科学的原理,以介绍感受回顾有哪些好处,以及如何使用“心理状态”来表示不同类型的心情和情绪。
章节
- 0:00 - Introduction
- 1:28 - Mental wellbeing APIs
- 2:13 - State of Mind API
- 8:54 - State of Mind predicates
资源
相关视频
WWDC24
WWDC20
-
下载
嗨!我叫 Leah 是 Health 部门的一名软件工程师 今天 我将介绍 “心理健康” 以及我们在 HealthKit 中 为心理健康提供支持的新增 API 我叫 Matt 也是 Health 部门的一名软件工程师 我会协助将这些新功能 整合到我和团队 正在努力研发的一款 App 中 心理健康比以往任何时候都更为重要 并且与我们的社会息息相关 在 Apple 我们相信 对于照护个人心理健康 一点一滴的积累最终会产生巨大影响 去年 我们发布了一套专注于 心理健康的功能 让用户能够轻松 使用不同的设备参与到 有意义的实践中 在“健康”App 中 用户可以 反思自己的感受并记录心理状态 从而追踪自己的心理健康状况
他们还可通过 Apple Watch 记录心理状态 以便在一天中 随时轻松查看 如果要深入了解 自身心理健康状况 用户可在“健康”App 中 参与针对焦虑症和抑郁症的 标准化问卷调查 我们很高兴看到 这些功能已让用户 能够注重自身心理健康 同时我们还希望更多人 能从这些工具中受益 现在 可为这些体验提供支持的 数据类型均会以 API 的形式提供 在本次讲座中 我们将深入探究“心理健康” 背后的情绪科学 并介绍如何从 HealthKit 中读取 以及如何向其中写入这些样本
首先 我们来了解一些术语 GAD-7 和 PHQ-9 是辉瑞公司提供的两项 标准化问卷调查 世界各地的医生 和临床医师都将它们用于 心理健康筛查 GAD-7 由 7 个问题组成 用于评估某人罹患焦虑症的风险 PHQ-9 则由 9 个问题组成 用于评估罹患抑郁症的风险 今年 你将能读取和写入 GAD-7 焦虑症与 PHQ-9 抑郁症 调查问卷的相关结果 利用这些新的数据类型 用户可判断治疗效果 或保存医生诊疗的 相关结果 依据辉瑞公司的标准 来开展这些评估十分重要 因此 请查看我们的 开发者文档 了解更多信息 在接下来的内容中 我们将进一步深入了解 第三种数据类型 即心理状态 心理状态是人的 心情和情绪的一种表现方式 它要求个人 主动进行反思 心情和情绪的区别在于 激发某种感受的 时间长度 情绪是一种短暂的感受 仅持续几秒钟到几分钟 而心情则是一种较为长期的感受 可持续数小时甚至数天 花点时间停下来 进行反思 并确定当前情绪状态 可带来很多好处 如果你正在经历 不悦的感受 反思可以缩短 你感觉低落的时长 如果你正在经历愉悦的感受 则可细细品味它 并较为长久地享受这种感受 经历各种各样的感受 是正常的 也是健康的 无论感受是愉悦的、不悦的 还是不悲不喜的 通过这种方式来为自己的感受命名 有助于培养长期的 情绪意识和情绪复原能力 一个人在描述个人感受时 越是具体 可获得的临床益处就越多 我们在设计心理状态 API 时 秉持了这些原则 同时还与 情绪科学专家开展密切合作 现在 我来展示一下它的工作原理 心理状态共有 4 个参数 首先是感受种类 (Kind) 它可由每日心情 或瞬时情绪组成 决定要在 App 中使用哪个种类时 请考虑产生相应感受的情境 以及它能否表示 用户在当下 或更长时段内的感受 下一个参数则是效价(Valence) 它是用户自我感觉 好坏程度的一种自我报告度量方法 其度量结果是介于负 1 到正 1 之间的连续值 如果我感觉很差 就会选择一个接近负 1 的值 如果我感觉很好 则选择接近正 1 的值会更合适 接近 0 的更多中间值 也适合于各种感受 标签 (Label) 可描述用户的感受 选项包括“热忱” “不堪重负”和“如释重负”等 这里显示了一个详尽的选项列表 你可指定任意数量的选项 来充分表示 用户的心理状态
最后 关联 (Association) 可描述 某种感受的成因 选项包括 “家人”、“身份”和“工作”等 与标签一样 有很多选项可供选择 你可指定任意数量的关联 “心理状态”的创立初衷是提供 一种方法 用于反思用户的情绪状态 从而为人们提供 切实有效的临床益处 但是 相关用例并不是 也不应局限于 高度关注 心理健康的 App “心理状态”可用于 各种情况下的各种应用 只要适合让人停下来 进行反思的就可以 通过小规模的简单互动 反思和正念便可 融入各种体验中 Matt 在我们团队的 App 中 你会怎么使用这个 API? 深入了解“心理状态”后 我觉得 我可以使用新的 API 来关联 用户对日历事件的感受 说到情境 我正在研发一个 App 可以直观呈现用户的时间安排 我来向你展示一下 我一直在做的工作 现在 我的 App 显示了 “办公”、“社交” 和“体能训练”日历的所有事件 这个 App 可提供关于用户如何安排 个人时间的可视化效果和洞察信息 我很高兴能通过新的心理状态 API 来进一步完善这个 App 具体来说 我想让用户 添加自己的“心理状态” 来表明自己对某一事件的感受 如果你不介意 现在我们就来构建一下 首先 我将请求“心理状态”样本 的读写权限 这个操作可通过标准 HealthKit 授权流程完成 所有健康数据均可确保私密、安全 而授权机制可让用户掌握控制权 并指明他们想分享什么数据 关于授权的更多信息 请观看 WWDC20 的讲座 “HealthKit 入门” 现在 我们来看看 App 体验 我们表达心情和情绪 的方式多种多样 就我个人而言 表情符号 是一种既有趣又简便的 个人感受表示方法 所以 我会使用一组表情符号 它们会映射到我们可在 HealthKit 中 保存的一份“心理状态”样本 首先 我会选择这 5 个表情符号 其中每个表情符号都与一个 “心理状态”标签匹配 接下来 我需要思考 如何在“心理状态”样本中 体现每一个表情符号
为此 我们创建一个名为 EmojiType 的新枚举 其中包含我们将用于 创建样本的每个表情符号 然后 我会创建一个函数 它可为日历事件和 EmojiType 创建一个“心理状态”样本 因为是在为近期发生的事件 创建样本 所以我会将 momentaryEmotion 用作感受种类 接下来 我们需要一个效价值 来表示这个感受的 愉悦或不悦程度 我需要修改现有 emojiType 枚举 以生成一个新的效价属性 这个属性可将每个表情符号 映射到 Double 形式的效价值
查看 Leah 展示的 “心理状态”标签后 我会再创建一个名为 label 的 emojiType 属性 以便定义为每个表情符号选择的 “心理状态”标签 另外 我还可根据事件日历 从相应事件中推断出 该用哪个关联 例如 我的“办公”日历 会映射到“工作”关联 现在 使用 HKStateOfMind 构造器 来创建样本所需的一切 已经准备就绪 要保存这个样本 我只需使用 healthStore 现有的 save 方法即可
这样就可以了!而我也正好赶上 团队站会活动 此时我的“心理状态”非常愉悦 让我们试着把这种感受 保存在 App 中 当我轻点日历事件时 我会看到新的表情符号选择器 通过它 我可以选择一个表情符号 然后将样本保存到 HealthKit 就是这样 这个 App 鼓励我在每次事件之后 花点时间来了解自己的感受 从而帮助我培养 情绪意识和情绪复原能力 这种简便的方法可以鼓励 任何人追踪自己的心理健康状况 收获实实在在的临床益处 - Leah 我们还能做些什么? - 我来给你展示一下
“心理状态”记录的优点 并不仅限于 最初的反思 回顾自己过往的感受 可以提供非常有用的信息 你或许还能发现趋势 比如你睡眠不足时 会感觉低落 或是将锻炼列为优先事项 可改善你的情绪 在“健康”App 中 你可以查看 一段时间内自己的各种感受 并专注于比较 不同的生活领域 比如“朋友”、“健康”或“爱好” 此外 你还可查看 与其他数据类型的对比 例如“锻炼分钟数”、 “正念分钟数”或“睡眠” 通过扩大了解 用户的各种感受 可为他们的生活品质 带来巨大飞跃 从而鼓励用户 更好地关注个人健康 无论是在心理还是生理层面 借助“心理状态” 可根据用户的感受为其生活中的 不同时刻设定情境 并提供个性化的洞察信息 我们即将推出 4 个 新的 HealthKit 谓词 你可按种类 (Kind) 进行查询 来区分情绪和心情 从而凸显不同时刻或日子 之间的变化 借助效价 (Valence) 谓词 你可按 样本的愉悦程度来获取样本 可以搜索附带特定标签 (Label) 的 “心理状态”样本 从而凸显可唤起“平静”或 “有压力”等特定感受的时刻 而借助关联 (Associations) 谓词 则可按照特定生活领域来 查询感受 比如“约会”或“爱好” 利用这些谓词 可以 快速获取所需信息 并专注于提供 令人信服的洞察信息 无论是凸显那些 能让人感觉最佳的时刻 还是提供资源以便 在困难时刻提供支持 Matt 你能用这些谓词做些什么? 我本以为你不会问这个问题 实际上我使用它们进行查询 到目前为止 这个 App 已提供关于用户 如何安排个人时间的部分洞察信息 下面 我们来看看如何查询 特定的“心理状态”样本 从而提供描述性更强的洞察信息 在 Insights 标签页中 我们可看到 当周的“Work-Life Balance”分数 以及“Most Meaningful Event” 亮点 “Work-Life Balance”是通过 测量一天中已安排事件与 空闲时间之比来计算的 因此 如果日历上的大部分日期 都安排有会议 我的“Work-Life Balance” 分数就会很低 虽然“Work-Life Balance” 指标很有帮助 但它只是更宏观层面的 评判视角之一 例如 忙碌的一天可能 会让某些人感到充实 或者日历中的某些事件 可能是很有趣的活动 一种可用于改进这个指标的方法是 考虑我在一天中 有哪些具体感受 此外 我可通过查询每天对应的 相关“心理状态”样本 来对这个指标进行测量 首先 我会创建一个查询谓词来 获取特定日期范围内的所有样本 这些样本与 App 中的 任一日历事件均有关联 接着 我会将这个谓词传递到新的 stateOfMindPredicate 方法中 来查找与这个谓词匹配的样本 然后 我会构建 HealthKit 查询并获取结果 根据这些结果 我会对这些样本的所有 效价属性进行转换和合并 从而得出百分比形式的 平均效价 并用它来表示关于 用户感受的指标 现在 我们可将名为“Calendar Quality”的新指标 添加到“Insights”标签页中 在这里可凸显用户 整周的感受 不过 还有更棒的 这个 App 还会提供另一项洞察信息 来表示当周 最有意义的事件 现在 我通过查询当周 最长的日历事件 来计算这个指标 但我仔细一想 事件的持续时间并不能 完全反映它有多大意义 抱歉 B 女士 现在我们来解决这个问题 我们改为查询 HealthKit 中的 表情符号选择器是否存在 某个标签 比如“Happy” 在此 我会同时使用 关联谓词和标签谓词 来精确查找 所需类型的样本 接着 我便可识别具有 最高效价的样本 并找到这个时间前后 最邻近的日历事件
这样就更棒了 除了“Happy”标签 我们还可为多个不同 “心理状态”标签执行这一操作 从而提供针对用户一周生活的 多条洞察信息 好吧 这当然会让我更开心 借助“心理状态”数据 你可以提升你的 App 并根据用户的感受 提供新的洞察信息 从而打造真正个性化的体验 而这还只是刚刚开始 请观看“开始在 visionOS 中使用 HealthKit” 在这个讲座中 我们的团队成员 Zach 和 Sirinda 会将我们的 App 移植到 Vision Pro 他们将向你展示如何打造 由 HealthKit 提供支持的体验 而这些体验将利用 visionOS 的空间画布 并调整这个 App 在 Vision Pro 中的行为 其中包括对 处理客人用户的支持 但就眼下而言 我们的 App 已有大幅改善 - Leah 你有什么感受? - 我觉得它太棒了! 将我的个人感受整合为一周反思 而不仅仅只显示我如何安排个人时间 这个点子真是太棒了 眼下 我们还在研发更多 新功能 以通过不同的设备 为心理健康提供支持 请观看视频“让日记 App 提供更出色的建议” 我们的朋友 Rene 会在讲座中展示 如何为手记启用个性化的 “心理状态”建议 今天 Matt 和我介绍了很多内容 “心理状态”以 情绪科学的各项原理为基础 从而为人们提供切实有效的临床益处 每个样本属性均可提供 一个重要视角 来表示用户的感受 借助这些新的 API 你可以轻松打造贴心的体验 “心理状态”可作为心理健康 应用领域中一个很有价值的工具 例如冥想、手记 以及其他正念练习 而由于人们会在生活各方面产生各种感受 因此你可提升 App 将正念融入各种体验中 通过将“心理状态”整合到 App 中 你可以通过一种周到的方式 向用户提供令人信服的洞察信息 例如 帮助用户培养情绪复原能力、 庆祝积极时刻以及 认识到个人生活 中的重要模式 在结束本次讲座之前 请大家注意以下几点 请记住 心理健康在我们生活的 各个方面都十分重要 请想办法在你的 App 中 使用这些新的 API 并通过反馈助理 告知我们你的想法 此外 你也可观看 我们提到的某些讲座 详细了解 身体健康和心理健康方面的内容 无论你是将 “心理状态”整合到现有 App 还是受到启发而制作一款新 App 我们都非常期待见证你的成果
-
-
5:37 - Request authorization to read and write State of Mind HealthKit samples
// Request authorization to read and write State of Mind HealthKit samples import HealthKitUI func healthDataAccessRequest( store: HKHealthStore, shareTypes: Set<HKSampleType>, readTypes: Set<HKObjectType>? = nil, trigger: some Equatable, completion: @escaping (Result<Bool, any Error>) -> Void ) -> some View
-
6:26 - EmojiType
// EmojiType enum EmojiType: CaseIterable { case angry case sad case indifferent case satisfied case happy var emoji: String { switch self { case .angry: return "😡" case .sad: return "😢" case .indifferent: return "😐" case .satisfied: return "😌" case .happy: return "😊" } } }
-
6:32 - Create State of Mind sample for an event and emoji selection
/// Create State of Mind sample for an event and emoji selection func createSample(for event: EventModel, emojiType: EmojiType) -> HKStateOfMind { let kind: HKStateOfMind.Kind = .momentaryEmotion let valence: Double = emojiType.valence let label = emojiType.label let association = event.association return HKStateOfMind(date: event.endDate, kind: kind, valence: valence, labels: [label], associations: [association]) }
-
7:21 - Save State of Mind sample from emoji choice
// Save State of Mind sample from emoji choice func save(sample: HKSample, healthStore: HKHealthStore) async { do { try await healthStore.save(sample) } catch { // Handle error here. } }
-
10:34 - Query State of Mind samples
// Query State of Mind samples let datePredicate: NSPredicate = { ... } let associationsPredicate = NSCompoundPredicate ( orPredicateWithSubpredicates: associations.map { HKQuery.predicateForStatesOfMind(with: $0) } ) let compoundPredicate = NSCompoundPredicate( andPredicateWithSubpredicates: [datePredicate, associationsPredicate] ) let state0fMindPredicate = HKSamplePredicate.stateOfMind(compoundPredicate)
-
10:49 - Query State of Mind samples
// Query State of Mind samples let datePredicate: NSPredicate = { ... } let associationsPredicate = NSCompoundPredicate ( orPredicateWithSubpredicates: associations.map { HKQuery.predicateForStatesOfMind(with: $0) } ) let compoundPredicate = NSCompoundPredicate( andPredicateWithSubpredicates: [datePredicate, associationsPredicate] ) let stateOfMindPredicate = HKSamplePredicate.stateOfMind(compoundPredicate) let descriptor = HKSampleQueryDescriptor(predicates: [stateOfMindPredicate], sortDescriptors: []) var results: [HKStateOfMind] = [] do { // Launch the query and wait for the results. results = try await descriptor.result(for: healthStore) } catch { // Handle error here. }
-
10:54 - Query State of Mind samples (continued)
// Adjust each valence value to be from a range of 0.0 to 2.0. let adjustedValenceResults = results.map { $0.valence + 1.0 } // Calculate average valence. let totalAdjustedValence = adjustedValenceResults.reduce (0.0, +) let averageAdjustedValence = totalAdjustedValence / Double(results.count) // Convert valence to percentage. let adjustedValenceAsPercent = Int(100.0 * (averageAdjustedValence / 2.0))
-
11:33 - Query for relevant State of Mind samples with a specific label
// Query for relevant State of Mind samples with a specific label let label: HKStateOfMind.Label = .happy // Configure the query let datePredicate = HKQuery.predicateForSamples(withStart: dateInterval.start, end: dateInterval.end) let associationPredicate = HKQuery.predicateForStatesOfMind(with: association) let labelPredicate = HKQuery.predicateForStates0fMind(with: label) let compoundPredicate = NSCompoundPredicate( andPredicateWithSubpredicates: [datePredicate, associationPredicate, labelPredicate] ) let stateOfMindPredicate = HKSamplePredicate.stateOfMind(compoundPredicate) let descriptor = HKAnchoredObjectQueryDescriptor(predicates: [state0fMindPredicate], anchor: nil) // Fetch the results let results = descriptor.results(for: healthStore) let samples: [HKStateOfMind] = try await results.reduce([]) { $1.addedSamples }
-
11:45 - Process State of Mind sample data
// Process State of Mind sample data let happiestSample = samples.max { $0.valence < $1. valence } let happiestEvent: EventModel? = findClosestEvent(startDate: happiestSample?.startDate, endDate: happiestSample?.endDate)
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。