스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
HealthKit의 웰빙 API 살펴보기
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입니다 오늘은 정신적 웰빙을 소개하고 정신 건강을 지원하기 위해 HealthKit에 추가한 새로운 API를 보여 드리려고 합니다 마찬가지로 건강 앱 소프트웨어 엔지니어인 Matt입니다 팀원들과 함께 만든 앱에서 이러한 새로운 기능을 통합할 수 있도록 도와 드리겠습니다 정신 건강은 이제 우리 사회에서 그 어느 때보다 중요해졌습니다 Apple은 정신 건강 관리 면에서 작은 조치로 큰 효과를 얻을 수 있다고 생각합니다 작년에 Apple은 정신적 웰빙에 중점을 둔 기능 모음을 발표하여 사람들이 자신의 모든 기기에서 의미 있는 실행 방식에 쉽게 접근할 수 있도록 했습니다 건강 앱에서 사람들은 자신의 느낌을 돌아보고 마음 상태를 기록하여 정신적 웰빙을 추적할 수 있습니다
Apple Watch에서 마음 상태를 기록하여 하루 중 언제든지 쉽게 확인할 수도 있습니다 또한 정신적 웰빙을 더 자세히 살펴보기 위해 사람들은 건강 앱에서 불안과 우울에 대한 표준화된 설문지에 답할 수 있습니다 이러한 기능으로 이미 사용자들이 정신적 웰빙에 투자할 수 있게 되었다는 것을 기쁘게 생각하며 더 많은 사람들이 이러한 도구로 이점을 얻게 되기를 바랍니다 이제 이런 경험을 구현하는 데이터 유형을 API로 사용할 수 있습니다 이 세션에서는 정신적 웰빙의 이면에 숨겨진 감성 과학에 대해 자세히 알아보고 이러한 샘플을 읽고 HealthKit에 쓰는 방법을 살펴보겠습니다
먼저, 몇 가지 용어로 시작하겠습니다 GAD-7과 PHQ-9은 표준화된 설문지로 Pfizer에서 제공합니다 전 세계 의사와 임상 의학자가 정신 건강 선별을 위해 사용합니다 GAD-7은 불안 위험을 평가하기 위한 7개 질문으로 구성되고 PHQ-9은 우울 위험을 평가하기 위한 9개 질문으로 구성됩니다 올해에는 GAD-7 불안 설문지와 PHQ-9 우울 설문지의 결과를 읽고 쓸 수 있습니다 이러한 새로운 데이터 유형으로 치료의 효능을 확인하거나 담당 의사의 진료실에서 결과를 받아 저장할 수 있습니다 Pfizer의 표준에 따라 이러한 평가를 수행하는 것이 중요하므로 개발자 문서를 확인하여 자세히 알아보세요 이 세션의 나머지 부분에서는 세 번째 데이터 유형인 마음 상태를 더 자세히 살펴보겠습니다 마음 상태는 기분과 감정을 나타내는 방식으로 개인의 적극적인 성찰을 필요로 합니다 기분과 감정의 차이점은 느낌에 영향을 미치는 기간입니다 감정은 짧게 지속되는 느낌으로 몇 초에서 몇 분 동안 지속되고 기분은 더 장기적인 느낌으로 몇 시간, 며칠까지도 지속됩니다 시간을 내어 잠시 멈추고 되새겨 보면서 현재의 감정 상태를 파악하면 많은 이점을 얻게 됩니다 불쾌한 느낌을 경험하고 있다면 성찰을 통해 좋지 않게 느끼는 시간을 줄일 수 있습니다 유쾌한 느낌을 경험하고 있다면 그 느낌을 음미하면서 더 오랫동안 즐길 수 있습니다 다양한 느낌을 경험하는 것은 정상적이고 건강한 상태입니다 유쾌한 것이든, 불쾌한 것이든 중립적인 것이든 상관없습니다 이렇게 자신의 느낌에 이름을 붙이는 연습을 통해 장기적인 정서 인식과 회복탄력성이 개발됩니다 자신의 느낌을 더 구체적으로 설명할수록 더 큰 임상적 이점을 얻을 수 있습니다 Apple은 이러한 원칙을 고려해 State of Mind API를 디자인했으며 이를 위해 감성 과학 전문가들과 긴밀하게 협력했습니다 어떻게 작동하는지 보여 드리겠습니다 State of Mind에는 4개의 매개변수가 있습니다 첫 번째는 느낌의 종류로 일상적인 기분이나 순간적인 감정으로 구성될 수 있습니다 앱에서 어떤 것을 사용할지 결정할 때에는 해당 느낌의 맥락과 해당 순간에 느끼는 것인지 아니면 더 긴 시간 동안 느끼는 것인지를 고려합니다 다음은 감정가로, 얼마나 좋거나 나쁘게 느끼는지 스스로 보고한감정가 측정치이며, -1부터 +1까지 연속적인 척도로 측정됩니다 매우 좋지 않게 느낀다면 -1에 가까운 값을 선택합니다 매우 좋게 느낀다면 +1에 가까운 값일수록 더 적절할 것입니다 0에 가까운 보다 중립적인 값도 다양한 느낌에 적절합니다 레이블은 어떻게 느끼는지를 열정적임, 심한 압박감을 느낌 안도감 같은 보기를 선택해 설명합니다 모든 보기가 포함된 목록이 있으며 원하는 수만큼 지정하여 누군가의 마음 상태를 완전히 나타낼 수 있습니다
마지막으로, 상관 관계는 느낌의 원인을 설명하며 이때 가족, 정체성, 업무 등의 보기를 사용합니다 레이블과 마찬가지로 다양한 보기 중에서 선택하고 원하는 수만큼 지정할 수 있습니다 State of Mind는 임상적 이점을 제공하기 위해 사람의 감정 상태를 되돌아보기 위한 방법론으로 만들어졌습니다 하지만 사용 사례는 정신적 웰빙에 엄격히 초점을 맞춘 앱에 국한되지 않으며 그래서도 안 됩니다 State of Mind는 다양한 애플리케이션과 잠시 멈추고 되돌아보는 데 적절할 수 있는 모든 곳에서 사용할 수 있습니다 작고 간단한 상호작용을 통해 성찰과 마음 챙기기는 모든 경험에 통합될 수 있습니다 Matt, 이 API를 우리 팀의 앱에 어떻게 사용하게 될까요? State of Mind에 대해 자세히 알아보니, 새로운 API를 사용해 캘린더 이벤트에 대해 어떻게 느끼는지와 연관시킬 수 있겠네요 시간을 어떻게 보내는지를 시각화하는 앱을 개발 중인데요 제가 작업해 온 내용을 보여 드리겠습니다 앱에 Office, Social, Workout 캘린더에 대한 저의 모든 이벤트가 표시되어 있습니다 시간을 어떻게 보내는지에 대한 시각화와 인사이트를 제공하며 새로운 State of Mind API에 대해 한층 더 자세히 알아보고 싶습니다 구체적으로, 누군가가 마음 상태를 추가해 이벤트에 대해 어떻게 느끼는지 나타낼 수 있기를 바랍니다 괜찮으시다면 빌드해 보겠습니다 먼저, State of Mind 샘플을 읽고 쓰는 접근 권한을 요청합니다 표준 HealthKit 승인 흐름을 사용합니다 모든 건강 데이터는 개인정보가 보호되고 안전하며, 승인을 통해 사람들이 제어력을 유지하고 공유할 데이터를 지정할 수 있죠 승인에 대한 자세한 내용은 WWDC20의 ’HealthKit 시작하기’를 참고하세요 이제, 앱 경험을 살펴보겠습니다 수많은 다양한 방법으로 기분과 감정을 보여 줄 수 있습니다 개인적으로 이모티콘은 누군가가 어떻게 느끼는지를 나타내는 재미있고 가벼운 방법이라고 생각합니다 HealthKit에 저장할 수 있는 State of Mind 샘플에 매핑되는 이모티콘 세트를 사용해 보겠습니다 먼저, 이 이모티콘 5개를 선택합니다 여기서 각각은 하나의 State of Mind 레이블과 연결됩니다 다음으로, State of Mind 샘플에서 각각을 어떻게 반영할지 생각해 보려고 합니다
EmojiType이라는 새로운 열거형을 만들어 보겠습니다 여기에는 샘플을 만드는 데 사용할 각 아이콘이 포함됩니다 그런 다음 캘린더 이벤트와 EmojiType에 대해 State of Mind 샘플을 생성하는 함수를 만들겠습니다 최근 이벤트에 대한 샘플을 생성하고 있으므로 느낌의 종류로 momentaryEmotion을 사용합니다 다음으로, 감정가 값이 필요합니다 해당 느낌이 얼마나 유쾌한지 또는 불쾌한지를 나타냅니다 기존 emojiType 열거형을 수정하여 새로운 감정가 속성을 사용합니다 이 속성은 각 이모티콘을 Double로 표현되는 감정가에 매핑합니다
Leah가 설명한 State of Mind 레이블을 살펴본 후 emojiType에서 label이라는 또 다른 속성을 생성하여 각 이모티콘에 대해 선택한 State of Mind 레이블을 정의합니다 이벤트 캘린더를 기반으로 이벤트에서 어떤 상관 관계를 사용할지 추론할 수도 있습니다 예를 들어, Office 캘린더는 Work 상관 관계에 매핑됩니다 HKStateOfMind 이니셜라이저를 사용해 샘플을 만드는 데 필요한 모든 것이 갖춰졌습니다 샘플을 저장하려면 healthStore의 기존 save 메서드를 사용하기만 하면 됩니다
다 됐네요! 팀 스탠드업 이벤트를 위해 적절한 시점입니다 제 State of Mind가 상당히 기뻐하는군요 해당 느낌을 앱에 저장해 보겠습니다 캘린더 이벤트를 탭하면 새로운 이모티콘 선택기가 표시되어 이모티콘을 선택한 다음 샘플을 HealthKit에 저장할 수 있습니다 바로 이렇게요 앱에서 각 이벤트 후 어떻게 느끼는지 확인하도록 합니다 이는 정서 인식과 회복탄력성을 높이는 데 도움이 됩니다 자신의 정신적 웰빙을 추적하고 임상적 이점을 얻도록 독려하는 간단하고 쉬운 방법입니다 - Leah, 또 무엇을 할 수 있나요? - 제가 보여 드리죠!
마음 상태 기록의 이점은 초기 성찰 시점에 국한되지 않습니다 과거에 어떻게 느꼈는지 살펴보면 유용한 정보를 얻을 수 있습니다 추세를 파악할 수도 있습니다 예를 들면, 수면을 충분히 취하지 않으면 느낌이 좋지 않다거나 운동을 우선시하면 기분을 개선할 수 있다는 것입니다 건강 앱에서 시간 경과에 따른 느낌의 범위를 확인하고 삶의 다양한 영역을 비교하는 데 초점을 맞출 수 있습니다 친구, 건강, 취미 등이죠 다른 데이터 유형과 비교한 내용을 확인할 수도 있습니다 예를 들면 운동하기 시간, 마음 챙기기 시간, 수면 등입니다 누군가의 느낌에 대해 더 폭넓게 파악하면 그 사람의 생활 방식을 크게 향상할 수 있으며 건강을 더 잘 관리하도록 영감을 주게 됩니다 정신적으로 그리고 신체적으로요 State of Mind를 사용하면 어떻게 느끼는지에 따라 삶의 순간들을 맥락화하고 맞춤형 인사이트를 제공할 수 있습니다 4개의 새로운 HealthKit 술어를 도입합니다 종류를 기준으로 쿼리하여 감정과 기분을 구분하고 순간 또는 일 단위로 변경 사항을 강조할 수 있습니다 감정가 술어로 얼마나 유쾌한지에 따라 샘플을 가져올 수 있습니다 특정 레이블로 State of Mind 샘플을 검색하고, 차분함 또는 스트레스 같은 특정 느낌을 유발하는 순간을 강조할 수 있죠 또한 상관 관계 술어를 사용하면 연애, 취미 같은 특정 삶의 영역을 기준으로 느낌을 쿼리할 수 있죠 이러한 술어를 사용하면 빠르게 필요한 정보를 얻고 설득력 있는 인사이트 제공에 초점을 맞출 수 있습니다 사람들이 가장 좋게 느끼는 순간을 강조하는 경우든 어려운 순간에 지원용 리소스를 제공하는 경우든 상관없습니다 Matt, 이 내용으로 무엇을 할 수 있을까요? 질문이나 쿼리는 하지 않으실 거라고 생각했는데요 이 앱은 시간을 어떻게 보내는지에 대한 인사이트를 이미 제공합니다 특정 State of Mind 샘플을 쿼리하여 더 설명적인 인사이트를 제공하는 방법을 살펴보겠습니다 Insights 탭에는 해당 주의 Work-Life Balance 점수와 Most Meaningful Event 하이라이트가 표시됩니다 Work-Life Balance는 해당 날짜에 예약된 이벤트와 여가 시간의 비율을 측정하여 계산합니다 캘린더의 대부분이 예약된 모임으로 채워지면 Work-Life Balance가 나빠지죠 Work-Life Balance 지표는 유용할 수 있지만 더 폭넓은 이야기의 한 관점에 불과합니다 예를 들어, 어떤 사람들은 바쁜 하루로 성취감을 느낄 수 있고 제 캘린더의 일부 이벤트는 재미있는 활동일 수 있습니다 이 지표를 향상할 수 있는 한 가지 방법은 하루 동안 내가 어떻게 느끼는지를 고려하는 것입니다 저는 이를 측정하기 위해 각 날짜별로 상관 관계가 지정된 State of Mind 샘플을 쿼리합니다 먼저, 앱의 캘린더 이벤트와 관련된 상관 관계가 있는 특정 날짜 범위의 모든 샘플을 가져오는 쿼리 술어를 생성합니다 이를 새로운 stateOfMindPredicate 메서드에 전달하여 해당 술어와 일치하는 샘플을 찾습니다 그런 다음 HealthKit 쿼리를 구성하고 결과를 가져옵니다 이 결과를 사용해 해당 샘플의 모든 감정가 속성을 변형하고 결합하여 평균 감정가를 백분율로 확인하고 누군가가 어떻게 느끼고 있는지에 대한 지표를 나타냅니다 Calendar Quality라는 이 새로운 지표를 Insights 탭에 추가해 해당 일주일 동안 그 사람의 느낌을 강조합니다 다른 내용이 더 있습니다! 앱에 해당 일주일 동안 가장 의미 있는 이벤트를 나타내는 또 다른 인사이트가 있습니다 지금, 이 지표를 계산하고 있는데요 그 주의 가장 긴 캘린더 이벤트를 쿼리하는 방법을 사용합니다 하지만 다시 생각해 보니 이벤트의 실행 시간으로 이벤트가 얼마나 의미있는지 알 순 없겠네요 죄송합니다, Mrs. B 이 문제를 해결해 보죠 그 대신에 HealthKit에서 이모티콘 선택기의 레이블 중 하나에 대해 쿼리해 보겠습니다 예를 들면 ’행복함’ 등입니다 여기서는 상관 관계와 레이블 술어를 모두 사용하여 찾으려는 샘플 유형을 정확히 찾습니다 그러면 감정가가 가장 높은 샘플을 파악하고 해당 시간 무렵에 가장 가까운 캘린더 이벤트를 찾을 수 있죠
이게 더 낫네요! 행복함 레이블 외에도 다양한 State of Mind 레이블에 대해 이 작업을 수행하여 누군가의 일주일에 대해 다양한 인사이트를 제공할 수 있습니다 이 방법을 사용하니 확실히 제가 더 행복해지는군요 State of Mind 데이터를 사용해 앱을 향상하고 어떻게 느끼는지를 토대로 새로운 인사이트를 제공하여 진정한 맞춤형 경험을 선사할 수 있습니다 그리고 이제 시작에 불과합니다 ’visionOS에서 HealthKit 시작하기’를 확인해 보세요 저희 팀 동료인 Zach와 Sirinda가 이 앱을 Vision Pro로 가져갑니다 HealthKit으로 구동되어 visionOS의 공간 캔버스를 활용하는 경험을 빌드하고 Vision Pro용으로 앱의 동작을 조정하는 방법을 보여 줍니다 여기에는 방문 사용자 처리에 대한 지원이 포함됩니다 하지만 현재로서는 우리 앱이 훨씬 더 상태가 좋은 것 같네요 - 어떻게 생각하세요, Leah? - 훌륭하네요! 단지 내가 시간을 어떻게 보내는지 대신에, 일주일 동안을 되돌아보며 어떻게 느끼는지를 통합한다는 아이디어가 마음에 들어요 다양한 기기 전반에서 정신적 웰빙을 지원하기 위해 훨씬 더 많은 발전이 이루어지고 있습니다 ’일기 쓰기 앱의 향상된 제안 콘텐츠’를 확인해 보세요 저희 동료 Rene가 일기 쓰기를 위한 맞춤형 State of Mind 제안 콘텐츠를 활성화하는 방법을 보여 드립니다 오늘 Matt와 제가 많은 내용을 소개했습니다 State of Mind는 감성 과학의 원칙에 기반하여 임상적 이점을 제공합니다 샘플의 각 속성은 누군가가 어떻게 느끼는지를 나타내는 중요한 렌즈를 제공합니다 이러한 새로운 API로 사려 깊은 경험을 쉽게 생성할 수 있습니다 State of Mind는 명상, 일기 쓰기 기타 마음 챙김 실행 방식 등 정신적 웰빙 애플리케이션의 중요한 도구가 될 수 있습니다 사람들은 삶의 모든 영역에서 느낌을 경험하기 때문에 어떤 경험에든 마음 챙김을 접목하도록 앱을 향상할 수 있죠 State of Mind를 앱에 통합하는 것은 사람들에게 설득력 있는 인사이트를 제공하는 사려 깊은 방법입니다 예를 들면 누군가가 정서적 회복탄력성을 키우도록 돕기 긍정적인 순간 축하하기, 삶에서 중요한 패턴 인지하기 등입니다 마치기 전에, 기억해야 할 사항이 몇 가지 있습니다 정신적 웰빙은 삶의 모든 영역에서 중요하다는 사실을 기억하세요 앱에서 이러한 새 API를 사용할 방법을 찾아보세요 그리고 피드백 지원을 사용해 여러분의 의견을 알려 주세요 저희가 말씀드린 세션을 확인하여 건강 및 정신적 웰빙에 대해 자세히 알아보실 수도 있습니다 State of Mind를 여러분의 기존 앱에 통합하든 새로운 앱을 만드시든 상관없습니다 여러분이 만드신 콘텐츠를 어서 보고 싶네요
-
-
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)
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.