첫 번째 헬스 커넥트 통합 앱

1. 소개

e4a4985ad1cdae8b.png

헬스 커넥트란 무엇인가요?

헬스 커넥트는 Android 앱 개발자를 위한 건강 데이터 플랫폼입니다. 사용자의 건강 및 피트니스 데이터에 대한 액세스와 모든 기기에서 일관된 기능 동작을 위한 통합된 단일 인터페이스를 제공합니다. 헬스 커넥트를 사용하면 사용자가 기기 내에 건강 및 피트니스 데이터 저장소를 안전하게 보유하면서 액세스 권한을 완전하고 투명하게 제어할 수 있습니다.

헬스 커넥트는 어떻게 작동하나요?

헬스 커넥트는 활동, 수면, 영양, 신체 측정, 활력 징후(예: 심박수, 혈압) 등 50가지가 넘는 일반적인 건강 및 피트니스 데이터 유형과 카테고리를 지원합니다.

헬스 커넥트 작동 방식

사용자 권한을 통해 개발자는 표준화된 스키마와 API 동작을 사용하여 헬스 커넥트에서 안전하게 읽고 쓸 수 있습니다. 사용자는 개인 정보 보호 설정을 완전히 제어할 수 있으며 세부적인 제어를 통해 데이터 액세스를 요청하는 앱을 언제든지 확인할 수 있습니다. 헬스 커넥트의 데이터는 기기에 저장되고 암호화됩니다. 사용자는 기기에서 원하지 않는 데이터 액세스를 차단하거나 데이터를 삭제할 수 있고 여러 앱을 사용할 때 특정 데이터 소스를 다른 데이터 소스보다 우선할 수 있습니다.

헬스 커넥트 아키텍처

아키텍처

다음은 헬스 커넥트의 주요 특징과 아키텍처 구성요소에 관한 설명입니다.

  • 클라이언트 앱: 헬스 커넥트와 통합하기 위해 클라이언트 앱은 건강 및 피트니스 앱에 SDK를 연결합니다. 이를 통해 Health Connect API와 상호작용하는 API 노출 영역을 제공합니다.
  • 소프트웨어 개발 키트(SDK): SDK를 사용하여 클라이언트 앱이 IPC를 통해 헬스 커넥트 APK와 통신할 수 있습니다.
  • 헬스 커넥트 APK: 헬스 커넥트를 구현하는 APK입니다. 권한 관리 및 데이터 관리 구성요소를 모두 포함합니다. 헬스 커넥트 APK는 사용자 기기에서 직접 사용할 수 있어 헬스 커넥트를 계정 중심이 아닌 기기 중심 환경으로 구성할 수 있습니다.
  • 권한 관리: 헬스 커넥트에는 사용자 인터페이스가 포함되어 있으며 이를 통해 앱은 사용자의 권한을 요청하여 데이터를 표시합니다. 헬스 커넥트는 기존 사용자 권한 목록도 제공합니다. 이를 통해 사용자는 다양한 애플리케이션에 부여하거나 거부한 액세스 권한을 관리할 수 있습니다.
  • 데이터 관리: 헬스 커넥트는 사용자의 걸음 수나 사이클링 속도, 심박수, 기타 지원되는 데이터 유형 등 기록된 데이터에 관한 개요를 사용자 인터페이스에 제공합니다.

빌드할 항목

이 Codelab에서는 헬스 커넥트와 통합된 간단한 건강 및 피트니스 앱을 빌드합니다. 앱에서 다음 작업을 실행합니다.

  • 데이터 액세스를 위한 사용자 권한을 가져오고 확인합니다.
  • 헬스 커넥트에 데이터를 씁니다.
  • 헬스 커넥트에서 집계된 데이터를 읽습니다.

학습할 내용

  • 헬스 커넥트 통합 개발을 지원하도록 환경을 설정하는 방법.
  • 권한을 얻고 권한 확인을 실행하는 방법.
  • 헬스 커넥트 플랫폼에 건강 및 피트니스 데이터를 제공하는 방법.
  • 기기 내 데이터 저장소를 활용하는 방법.
  • Google에서 제공하는 개발자 도구로 앱을 확인하는 방법.

필요한 항목

  • Android 스튜디오의 최신 정식 버전
  • Android SDK 버전 28(Pie) 이상이 적용된 Android 휴대기기

2. 설정

헬스 커넥트 설치

헬스 커넥트 APK(Play 스토어에서 사용 가능). 헬스 커넥트를 휴대기기에 설치하여 Health Connect SDK를 통해 애플리케이션에서 전송한 모든 요청을 처리하세요. QR 코드를 스캔하여 헬스 커넥트를 설치하세요.

633ed0490a74595d.png

샘플 코드 가져오기

git이 설치되어 있으면 아래 명령어를 실행하여 이 저장소의 코드를 클론하면 됩니다. git이 설치되어 있는지 확인하려면 터미널이나 명령줄에 git --version을 입력하여 올바르게 실행되는지 확인합니다.

git clone https://github.com/android/android-health-connect-codelab.git
cd android-health-connect-codelab

git이 없는 경우 다음 버튼을 클릭하여 이 Codelab의 모든 코드를 다운로드할 수 있습니다.

샘플 디렉터리에는 이 Codelab의 startfinished 코드가 포함되어 있습니다. Android 스튜디오의 Project 뷰에 다음 두 개의 모듈이 있습니다.

  • start: 이 프로젝트의 시작 코드로, 이 코드를 변경하여 Codelab을 완료합니다.
  • finished: 이 Codelab의 완료 코드입니다. 작업 확인에 사용됩니다.

'시작' 코드 살펴보기

Codelab 샘플 앱에는 Jetpack Compose를 사용하여 빌드한 기본 UI가 있으며 포함된 화면은 다음과 같습니다.

  • WelcomeScreen: 앱의 방문 페이지이며 헬스 커넥트 사용 가능 여부(설치됨, 설치되지 않음, 지원되지 않음)에 따라 다양한 메시지를 표시합니다.
  • PrivacyPolicyScreen: 앱의 권한 사용에 관해 설명하며 사용자가 헬스 커넥트 권한 대화상자에서 개인정보처리방침 링크를 클릭하면 사용자에게 표시됩니다.
  • InputReadingsScreen: 체중 기록을 간단하게 읽고 쓰는 방법을 보여줍니다.
  • ExerciseSessionScreen: 사용자가 운동 세션을 삽입하고 나열할 수 있는 곳입니다. 기록을 클릭하면 사용자는 세션과 관련된 자세한 데이터가 표시되는 ExerciseSessionDetailScreen으로 이동하게 됩니다.
  • DifferentialChangesScreen: 변경 토큰을 가져오고 헬스 커넥트에서 새 변경사항을 가져오는 방법을 보여줍니다.

HealthConnectManager는 헬스 커넥트와 상호작용하는 모든 기능을 저장합니다. 이 Codelab에서는 필수 기능을 완료하는 방법을 단계별로 안내합니다. start 빌드 내의 <!-- TODO: 문자열에는 이 Codelab에서 상응하는 섹션이 있으며 이 섹션에서 프로젝트에 삽입할 수 있는 샘플 코드가 제공됩니다.

먼저 프로젝트에 헬스 커넥트를 추가해 보겠습니다.

헬스 커넥트 클라이언트 SDK 추가

헬스 커넥트 SDK를 사용하려면 build.gradle 파일에 종속 항목을 추가해야 합니다. 헬스 커넥트의 최신 버전을 찾으려면 Jetpack 라이브러리 출시를 확인하세요.

dependencies {
    // Add a dependency of Health Connect SDK
    implementation "androidx.health.connect:connect-client:1.0.0-alpha11"
}

헬스 커넥트 공개 상태 선언

앱 내에서 헬스 커넥트와 상호작용하려면 AndroidManifest.xml에서 다음과 같이 헬스 커넥트 패키지 이름을 선언합니다.

<!-- TODO: declare Health Connect visibility -->
<queries>
   <package android:name="com.google.android.apps.healthdata" />
</queries>

프로젝트 실행

설정이 완료되면 start 프로젝트를 실행합니다. 이제 'Health Connect is installed on this device.(헬스 커넥트가 이 기기에 설치되었습니다)'라는 텍스트가 표시된 시작 화면과 메뉴 창이 나타납니다. 이후 섹션에서 헬스 커넥트와 상호작용하는 기능을 추가합니다.

d54773774e4dc9f.png 462cd7b6cf553ad.png

3. 권한 제어

헬스 커넥트에서는 개발자가 권한 요청을 앱에서 사용되는 데이터 유형으로 제한하도록 권장합니다. 포괄적 권한 요청은 앱에 대한 사용자 신뢰도를 떨어뜨리고 사용자 신뢰를 저하시킬 수 있습니다. 권한이 세 번 이상 거부되면 앱이 잠기게 됩니다. 그 결과, 권한 요청이 더 이상 표시되지 않습니다.

이 Codelab에서는 다음 권한만 있으면 됩니다.

  • 운동 세션
  • 심박수
  • 걸음 수
  • 총 칼로리 소모량
  • 체중

권한 선언

AndroidManifest.xml 권한을 사용하여 앱에서 읽거나 쓰는 모든 데이터 유형을 선언해야 합니다. 헬스 커넥트에서는 버전 alpha10부터 표준 Android 권한 선언 형식을 사용합니다.

필요한 데이터 유형의 권한을 선언하려면 <uses-permission> 요소를 사용하여 각 이름에 권한을 할당하세요. 그런 다음 <manifest> 태그 내에 중첩합니다. 권한 및 해당 데이터 유형의 전체 목록은 데이터 유형 목록을 참고하세요.

<!-- TODO: declare Health Connect permissions -->
  <uses-permission android:name="android.permission.health.READ_HEART_RATE"/>
  <uses-permission android:name="android.permission.health.WRITE_HEART_RATE"/>
  <uses-permission android:name="android.permission.health.READ_STEPS"/>
  <uses-permission android:name="android.permission.health.WRITE_STEPS"/>
  <uses-permission android:name="android.permission.health.READ_EXERCISE"/>
  <uses-permission android:name="android.permission.health.WRITE_EXERCISE"/>
  <uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED"/>
  <uses-permission android:name="android.permission.health.WRITE_TOTAL_CALORIES_BURNED"/>
  <uses-permission android:name="android.permission.health.READ_WEIGHT"/>
  <uses-permission android:name="android.permission.health.WRITE_WEIGHT"/>

앱에서의 권한 사용 방법을 설명하는 인텐트를 처리하기 위해 AndroidManifest.xml에서 인텐트 필터를 선언합니다. 앱은 이 인텐트를 처리하고 사용자 데이터의 사용 및 처리 방식을 설명하는 개인정보처리방침을 표시해야 합니다. 이 인텐트는 사용자가 헬스 커넥트 권한 대화상자에서 개인정보처리방침 링크를 클릭하면 앱으로 전송됩니다.

<!-- TODO: Add intent filter to handle permission rationale intent -->
<intent-filter>
    <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
</intent-filter>

이제 앱을 다시 열어 선언된 권한을 확인하세요. 메뉴 창에서 Settings를 클릭하여 헬스 커넥트 설정 화면으로 이동합니다. 그런 다음 App permissions를 클릭하면 목록에 Health Connect Codelab이 표시됩니다. Health Connect Codelab을 클릭하여 해당 앱의 읽기 및 쓰기 액세스 권한에 대한 데이터 유형 목록을 표시합니다.

fbed69d871f92178.png 1b9c7764c1dbdfac.png

권한 요청

권한을 관리하기 위해 사용자를 Health Connect Settings로 직접 안내하는 것 외에도 Health Connect API를 통해 앱에서 권한을 요청할 수도 있습니다. 사용자는 언제든지 권한을 변경할 수 있으므로 앱에서 필수 권한을 사용할 수 있는지 확인해야 합니다. 이 Codelab 프로젝트에서는 데이터를 읽거나 쓰기 전에 확인하고 권한 요청을 보냅니다.

HealthConnectClient는 Health Connect API의 진입점입니다. HealthConnectManager.kt에서 HealthConnectClient 인스턴스를 가져옵니다.

private val healthConnectClient by lazy { HealthConnectClient.getOrCreate(context) }

애플리케이션 내에서 권한 요청 대화상자를 시작하려면 필요한 데이터 유형의 권한 집합을 먼저 빌드합니다. 사용하는 데이터 유형에 관한 권한을 요청해야 합니다.

예를 들어 Record weight 화면에서는 Weight에 관한 읽기 및 쓰기 권한만 부여해야 합니다. 다음 코드에서와 같이 InputReadingsViewModel.kt에 권한 세트를 만들었습니다.

  val permissions = setOf(
    HealthPermission.getReadPermission(WeightRecord::class),
    HealthPermission.getWritePermission(WeightRecord::class),
  )

그런 다음 권한 요청을 실행하기 전에 이미 권한이 부여되었는지 확인합니다. HealthConnectManager.kt에서 getGrantedPermissions를 사용하여 필요한 데이터 유형의 권한이 부여되었는지 확인합니다. 권한 요청을 실행하려면 PermissionController.createRequestPermissionResultContract()를 사용하여 ActivityResultContract를 만듭니다. 필요한 권한이 부여되지 않으면 이를 실행해야 합니다.

  suspend fun hasAllPermissions(permissions: Set<String>): Boolean {
    return healthConnectClient.permissionController.getGrantedPermissions().containsAll(permissions)
  }

  fun requestPermissionsActivityContract(): ActivityResultContract<Set<String>, Set<String>> {
    return PermissionController.createRequestPermissionResultContract()
  }

이 Codelab 샘플 앱에서는 필요한 데이터 유형에 관한 권한을 부여하지 않은 경우 화면에 Request permissions 버튼이 표시될 수 있습니다. Request permissions를 클릭하면 헬스 커넥트 권한 대화상자가 열립니다. 필요한 권한을 허용하고 Codelab 앱으로 돌아옵니다.

626eedcec23659ce.png 6df6cf0e5c4a1a9e.png

4. 데이터 쓰기

이제 헬스 커넥트에 기록을 작성해 보겠습니다. Weight 기록을 작성하려면 체중 입력 값으로 WeightRecord 객체를 만듭니다. Health Connect SDK는 다양한 단위 클래스를 지원합니다. Mass.kilograms(weightInput)을 사용하여 사용자 체중을 킬로그램으로 설정하는 것을 예로 들 수 있습니다.

헬스 커넥트에 기록되는 모든 데이터는 시간대 오프셋 정보를 지정해야 합니다. 데이터를 쓰는 동안 시간대 오프셋 정보를 지정하면 헬스 커넥트에서 데이터를 읽을 때 시간대 정보가 제공됩니다.

체중 기록을 만든 후 healthConnectClient.insertRecords를 사용하여 헬스 커넥트에 데이터를 씁니다.

/**
* TODO: Writes [WeightRecord] to Health Connect.
*/
suspend fun writeWeightInput(weightInput: Double) {
   val time = ZonedDateTime.now().withNano(0)
   val weightRecord = WeightRecord(
       weight = Mass.kilograms(weightInput),
       time = time.toInstant(),
       zoneOffset = time.offset
   )
   val records = listOf(weightRecord)
   try {
      healthConnectClient.insertRecords(records)
      Toast.makeText(context, "Successfully insert records", Toast.LENGTH_SHORT).show()
   } catch (e: Exception) {
      Toast.makeText(context, e.message.toString(), Toast.LENGTH_SHORT).show()
   }
}

이제 앱을 실행해 보겠습니다. Record weight를 클릭하고 새 체중 기록을 킬로그램으로 입력합니다. 체중 기록이 헬스 커넥트에 기록되었는지 확인하려면 Settings에서 헬스 커넥트 앱을 열고 Data and access > Body measurements > Weight > See all entries로 이동합니다. 헬스 커넥트 Codelab에서 작성한 새로운 체중 기록이 표시됩니다.

운동 세션 쓰기

세션은 사용자가 활동을 실행하는 시간 간격입니다. 헬스 커넥트의 운동 세션에는 달리기부터 배드민턴까지 무엇이든 포함될 수 있습니다. 세션을 통해 사용자는 시간 기반 실적을 측정할 수 있습니다. 이 데이터는 일정 기간 동안 측정된 즉각적인 샘플 배열(예: 활동 중 연속 심박수 또는 위치 샘플)을 기록합니다.

다음 예는 운동 세션을 작성하는 방법을 보여줍니다. healthConnectClient.insertRecords를 사용하여 세션과 연결된 여러 데이터 기록을 삽입합니다. 이 예의 삽입 요청에는 ExerciseType이 있는 ExerciseSessionRecord와 걸음 수가 있는 StepsRecord, Energy가 있는 TotalCaloriesBurnedRecord 그리고 일련의 HeartRateRecord 샘플이 포함되어 있습니다.

  /**
   * TODO: Writes an [ExerciseSessionRecord] to Health Connect.
   */
  suspend fun writeExerciseSession(start: ZonedDateTime, end: ZonedDateTime) {
    healthConnectClient.insertRecords(
      listOf(
        ExerciseSessionRecord(
          startTime = start.toInstant(),
          startZoneOffset = start.offset,
          endTime = end.toInstant(),
          endZoneOffset = end.offset,
          exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_RUNNING,
          title = "My Run #${Random.nextInt(0, 60)}"
        ),
        StepsRecord(
          startTime = start.toInstant(),
          startZoneOffset = start.offset,
          endTime = end.toInstant(),
          endZoneOffset = end.offset,
          count = (1000 + 1000 * Random.nextInt(3)).toLong()
        ),
        TotalCaloriesBurnedRecord(
          startTime = start.toInstant(),
          startZoneOffset = start.offset,
          endTime = end.toInstant(),
          endZoneOffset = end.offset,
          energy = Energy.calories((140 + Random.nextInt(20)) * 0.01)
        )
      ) + buildHeartRateSeries(start, end)
    )
  }

  /**
   * TODO: Build [HeartRateRecord].
   */
  private fun buildHeartRateSeries(
    sessionStartTime: ZonedDateTime,
    sessionEndTime: ZonedDateTime,
  ): HeartRateRecord {
    val samples = mutableListOf<HeartRateRecord.Sample>()
    var time = sessionStartTime
    while (time.isBefore(sessionEndTime)) {
      samples.add(
        HeartRateRecord.Sample(
          time = time.toInstant(),
          beatsPerMinute = (80 + Random.nextInt(80)).toLong()
        )
      )
      time = time.plusSeconds(30)
    }
    return HeartRateRecord(
      startTime = sessionStartTime.toInstant(),
      startZoneOffset = sessionStartTime.offset,
      endTime = sessionEndTime.toInstant(),
      endZoneOffset = sessionEndTime.offset,
      samples = samples
    )
  }

5. 헬스 커넥트 도구 상자

헬스 커넥트 도구 상자 소개

헬스 커넥트 도구 상자는 앱과 헬스 커넥트의 통합을 테스트할 수 있는 호환 개발자 도구입니다. 헬스 커넥트 도구 상자에서는 데이터를 읽고 헬스 커넥트에 직접 쓸 수 있으므로 앱의 CRUD 작업을 테스트할 수 있습니다.

이 Codelab에서는 헬스 커넥트 도구 상자를 사용하여 방금 구현한 읽기 및 쓰기 기능을 테스트합니다.

헬스 커넥트 도구 상자 설정

ZIP 폴더를 추출하여 APK 파일을 가져옵니다. 그런 다음 연결된 기기에 도구 상자 APK를 설치하려면 adb를 사용합니다. APK가 있는 폴더로 이동하고 다음 명령어를 실행합니다.

$ adb install HealthConnectToolbox-{Version Number}.apk

Health Connect Toolbox 앱을 처음 열면 Apps > Special app access > Display over other apps 아래의 권한 설정으로 이동하게 됩니다. 이 권한을 사용하면 헬스 커넥트 도구 상자에서 다른 앱 위에 오버레이를 표시할 수 있으므로 개발하고 있는 앱을 종료하지 않고도 데이터 읽기 및 쓰기를 테스트할 수 있습니다.

테스트하기 위한 읽기 및 쓰기 권한을 관리하려면 Toolbox 앱의 기본 화면에서 헬스 커넥트 앱을 열거나 권한 흐름으로 바로 이동하면 됩니다.

c3e6fd40b03b408a.png

건강 기록 읽기 및 쓰기

헬스 커넥트 도구 상자는 모든 헬스 커넥트 데이터 유형 읽기 및 쓰기를 지원합니다. Codelab의 이전 세션에서는 헬스 커넥트에 체중과 운동 세션 기록을 작성했습니다. 헬스 커넥트 도구 상자에서 이 데이터를 읽을 수 있는지 확인해 보겠습니다.

헬스 커넥트에서 읽고 쓰기 전에 사용자로부터 권한을 받아야 합니다. 헬스 커넥트 도구 상자도 마찬가지입니다. 먼저 헬스 커넥트 도구 상자의 권한 요청을 수락합니다. 그런 다음 오버레이 메뉴에서 검색 아이콘 1f407c55884bb8c3.png을 클릭하여 대화상자를 열고 데이터 유형(예: 체중)을 선택한 다음 READ HEALTH RECORD를 클릭합니다. 방금 헬스 커넥트에 작성한 Codelab 샘플 앱의 기록이 표시됩니다.

헬스 커넥트에 기록을 삽입하려면 오버레이 메뉴에서 수정 아이콘 10c524823c596aea.png을 클릭하여 대화상자를 엽니다. 그런 다음 데이터 유형을 선택합니다. 도구 상자에서 체중 기록을 삽입해 보겠습니다. 다음 세션에서는 Health Connect API를 통해 기록을 읽고 앱에 데이터를 표시하는 방법을 보여줍니다.

cac9d4c249a1d107.png

6. 데이터 읽기

지금까지 Codelab 샘플 앱과 Toolbox 앱을 모두 사용하여 체중과 운동 세션 기록을 작성했습니다. 이제 Health Connect API를 사용하여 이러한 기록을 읽어 보겠습니다. 먼저 ReadRecordsRequest를 만들고 기록 유형과 읽을 기간을 지정합니다. ReadRecordsRequestdataOriginFilter를 설정하여 읽으려는 기록의 소스 앱을 지정할 수도 있습니다.

    /**
     * TODO: Reads in existing [WeightRecord]s.
     */
    suspend fun readWeightInputs(start: Instant, end: Instant): List<WeightRecord> {
        val request = ReadRecordsRequest(
            recordType = WeightRecord::class,
            timeRangeFilter = TimeRangeFilter.between(start, end)
        )
        val response = healthConnectClient.readRecords(request)
        return response.records
    }
  /**
   * TODO: Obtains a list of [ExerciseSessionRecord]s in a specified time frame.
   */
  suspend fun readExerciseSessions(start: Instant, end: Instant): List<ExerciseSessionRecord> {
    val request = ReadRecordsRequest(
      recordType = ExerciseSessionRecord::class,
      timeRangeFilter = TimeRangeFilter.between(start, end)
    )
    val response = healthConnectClient.readRecords(request)
    return response.records
  }

이제 앱을 실행하여 체중 기록 및 운동 세션 목록이 표시되는지 확인해 보겠습니다.

a08af54eef6bc832.png 3b0781389f1094a1.png

7. 차등 데이터 읽기

Health Connect Differential Changes API는 데이터 유형 세트에 관한 특정 시점의 변경사항을 추적하는 데 도움이 됩니다. 적절하게 데이터베이스를 업데이트할 수 있도록 사용자가 앱 외부의 기존 기록을 업데이트했는지 또는 삭제했는지를 확인하려는 경우를 예로 들 수 있습니다.

헬스 커넥트를 통한 데이터 읽기는 포그라운드에서 실행되는 애플리케이션으로 제한됩니다. 이 제한사항은 사용자 개인 정보 보호를 더욱 강화하기 위해 마련되었습니다. 이를 통해 헬스 커넥트는 사용자 데이터에 대한 백그라운드 읽기 액세스 권한이 없고 포그라운드에서만 데이터를 읽고 액세스할 수 있음을 사용자에게 알리고 보장합니다. 앱이 포그라운드에 있을 때 Differential Changes API를 사용하면 개발자가 변경 토큰을 배포하여 헬스 커넥트 변경사항을 가져올 수 있습니다.

HealthConnectManager.kt에는 두 가지 함수 getChangesToken()getChanges()가 있으며 이러한 함수에 Differential Changes API를 추가하여 데이터 변경사항을 가져옵니다.

초기 변경 토큰 설정

데이터 변경사항은 앱에서 변경 토큰을 사용하여 요청하는 경우에만 헬스 커넥트에서 가져옵니다. 변경 토큰은 차등 데이터를 가져올 커밋 기록의 지점을 나타냅니다.

변경 토큰을 가져오려면 데이터 변경사항을 추적하려는 데이터 유형 세트와 함께 ChangesTokenRequest를 전송합니다. 토큰을 유지하고 헬스 커넥트에서 업데이트를 가져오려고 할 때 이 토큰을 사용하세요.

  /**
   * TODO: Obtains a Changes token for the specified record types.
   */
  suspend fun getChangesToken(): String {
    return healthConnectClient.getChangesToken(
      ChangesTokenRequest(
        setOf(
          ExerciseSessionRecord::class,
          StepsRecord::class,
          TotalCaloriesBurnedRecord::class,
          HeartRateRecord::class,
          WeightRecord::class
        )
      )
    )
  }

변경 토큰으로 데이터 업데이트

앱이 마지막으로 헬스 커넥트와 동기화된 시점부터 변경사항을 가져오려면 이전에 가져온 변경 토큰을 사용하고 이 토큰과 함께 getChanges 호출을 전송합니다. ChangesResponse는 헬스 커넥트에서 관찰된 변경사항(예: UpsertionChangeDeletionChange) 목록을 반환합니다.

  /**
   * TODO: Retrieve changes from a Changes token.
   */
  suspend fun getChanges(token: String): Flow<ChangesMessage> = flow {
    var nextChangesToken = token
    do {
      val response = healthConnectClient.getChanges(nextChangesToken)
      if (response.changesTokenExpired) {
        throw IOException("Changes token has expired")
      }
      emit(ChangesMessage.ChangeList(response.changes))
      nextChangesToken = response.nextChangesToken
    } while (response.hasMore)
    emit(ChangesMessage.NoMoreChanges(nextChangesToken))
  }

이제 앱을 실행하여 Changes 화면으로 이동합니다. 먼저 Track changes를 사용 설정하여 변경 토큰을 가져옵니다. 그런 다음 Toolbox 또는 Codelab 앱에서 체중 또는 운동 세션을 삽입합니다. Changes 화면으로 다시 돌아가 Get new changes를 선택합니다. 이제 업데이트 변경사항이 표시됩니다.

f3aded8ae5487e9c.png 437d69e3e000ce81.png

8. 데이터 합산

헬스 커넥트는 집계 API를 통해 집계된 데이터도 제공합니다. 다음 예는 헬스 커넥트에서 누적 및 통계 데이터를 가져오는 방법을 보여줍니다.

healthConnectClient.aggregate를 사용하여 AggregateRequest를 전송합니다. 집계 요청에서 집계 측정항목 세트와 가져올 기간을 지정합니다. 예를 들어 ExerciseSessionRecord.EXERCISE_DURATION_TOTALStepsRecord.COUNT_TOTAL은 누적 데이터를 제공하는 반면 WeightRecord.WEIGHT_AVG, HeartRateRecord.BPM_MAX, HeartRateRecord.BPM_MIN은 통계 데이터를 제공합니다.

    /**
     * TODO: Returns the weekly average of [WeightRecord]s.
     */
    suspend fun computeWeeklyAverage(start: Instant, end: Instant): Mass? {
        val request = AggregateRequest(
            metrics = setOf(WeightRecord.WEIGHT_AVG),
            timeRangeFilter = TimeRangeFilter.between(start, end)
        )
        val response = healthConnectClient.aggregate(request)
        return response[WeightRecord.WEIGHT_AVG]
    }

다음 예는 특정 운동 세션의 관련 집계 데이터를 가져오는 방법을 보여줍니다. 먼저 uid와 함께 healthConnectClient.readRecord를 사용하여 기록을 읽습니다. 그런 다음 운동 세션의 startTimeendTime을 기간으로 사용하고 dataOrigin을 필터로 사용하여 관련 집계를 읽습니다.

  /**
   * TODO: Reads aggregated data and raw data for selected data types, for a given [ExerciseSessionRecord].
   */
  suspend fun readAssociatedSessionData(
      uid: String,
  ): ExerciseSessionData {
    val exerciseSession = healthConnectClient.readRecord(ExerciseSessionRecord::class, uid)
    // Use the start time and end time from the session, for reading raw and aggregate data.
    val timeRangeFilter = TimeRangeFilter.between(
      startTime = exerciseSession.record.startTime,
      endTime = exerciseSession.record.endTime
    )
    val aggregateDataTypes = setOf(
      ExerciseSessionRecord.EXERCISE_DURATION_TOTAL,
      StepsRecord.COUNT_TOTAL,
      TotalCaloriesBurnedRecord.ENERGY_TOTAL,
      HeartRateRecord.BPM_AVG,
      HeartRateRecord.BPM_MAX,
      HeartRateRecord.BPM_MIN,
    )
    // Limit the data read to just the application that wrote the session. This may or may not
    // be desirable depending on the use case: In some cases, it may be useful to combine with
    // data written by other apps.
    val dataOriginFilter = setOf(exerciseSession.record.metadata.dataOrigin)
    val aggregateRequest = AggregateRequest(
      metrics = aggregateDataTypes,
      timeRangeFilter = timeRangeFilter,
      dataOriginFilter = dataOriginFilter
    )
    val aggregateData = healthConnectClient.aggregate(aggregateRequest)
    val heartRateData = readData<HeartRateRecord>(timeRangeFilter, dataOriginFilter)

    return ExerciseSessionData(
      uid = uid,
      totalActiveTime = aggregateData[ExerciseSessionRecord.EXERCISE_DURATION_TOTAL],
      totalSteps = aggregateData[StepsRecord.COUNT_TOTAL],
      totalEnergyBurned = aggregateData[TotalCaloriesBurnedRecord.ENERGY_TOTAL],
      minHeartRate = aggregateData[HeartRateRecord.BPM_MIN],
      maxHeartRate = aggregateData[HeartRateRecord.BPM_MAX],
      avgHeartRate = aggregateData[HeartRateRecord.BPM_AVG],
      heartRateSeries = heartRateData,
    )
  }

이제 앱을 실행하여 Record weight 화면에 평균 체중이 표시되는지 확인해 보세요. Exercise sessions 화면을 열고 운동 세션 기록 중 하나를 선택하여 운동 세션의 세부 데이터를 확인할 수도 있습니다.

af1fe646159d6a60.png

9. 축하합니다

축하합니다. 첫 번째 헬스 커넥트 통합 건강 및 피트니스 앱을 빌드했습니다.

앱은 권한을 선언하고 앱에 사용되는 데이터 유형에 관한 사용자 권한을 요청할 수 있습니다. 또한 헬스 커넥트 데이터 저장소에서 데이터를 읽고 쓸 수 있습니다. 헬스 커넥트 데이터 저장소에 모의 데이터를 만들어 앱 개발을 지원하기 위해 헬스 커넥트 도구 상자를 사용하는 방법도 배웠습니다.

지금까지 건강 및 피트니스 앱을 헬스 커넥트 생태계의 일부로 만드는 데 필요한 주요 단계를 알아봤습니다.

추가 자료