의료 데이터 쓰기

이 가이드는 Health Connect 버전 1.1.0-beta02와 호환됩니다.

헬스 커넥트에서 개인 건강 기록 (PHR)을 사용하여 의료 데이터를 쓰려면 다음 단계를 따르세요.

  1. 기능 사용 가능 여부 확인
  2. 쓰기 권한 요청
  3. 데이터 소스 만들기 (MedicalDataSource)
  4. 의료 리소스 작성 (MedicalResource)

기능 사용 가능 여부

사용자의 기기가 헬스 커넥트에서 PHR을 지원하는지 확인하려면 클라이언트에서 FEATURE_PERSONAL_HEALTH_RECORD의 사용 가능 여부를 확인합니다.

if (healthConnectClient
     .features
     .getFeatureStatus(
       HealthConnectFeatures.FEATURE_PERSONAL_HEALTH_RECORD
     ) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {

  // Feature is available
} else {
  // Feature isn't available
}

자세한 내용은 기능 사용 가능 여부 확인하기를 참고하세요.

필수 권한

의료 데이터 쓰기는 다음 권한으로 보호됩니다.

  • android.permission.health.WRITE_MEDICAL_DATA

앱의 Play Console과 앱 매니페스트에서 다음 권한을 선언합니다.

<application>
  <uses-permission
android:name="android.permission.health.WRITE_MEDICAL_DATA" />
</application>

기기와 앱에서 사용할 모든 적절한 권한을 선언해야 할 책임은 개발자에게 있습니다. 또한 사용하기 전에 각 권한이 사용자에 의해 부여되었는지 확인해야 합니다.

사용자에게 권한 요청

클라이언트 인스턴스를 만든 후 앱은 사용자에게 권한을 요청해야 합니다. 사용자는 언제든지 권한을 부여하거나 거부할 수 있어야 합니다.

이렇게 하려면 필요한 데이터 유형의 권한 집합을 만듭니다. 먼저 집합의 권한이 Android 매니페스트에 선언되어 있는지 확인합니다.

// Create a set of permissions for required data types
import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_WRITE_MEDICAL_DATA

val PERMISSIONS =
    setOf(
       PERMISSION_WRITE_MEDICAL_DATA
)

getGrantedPermissions를 사용하여 앱에 필요한 권한이 이미 부여되었는지 확인합니다. 그렇지 않은 경우 createRequestPermissionResultContract를 사용하여 이러한 권한을 요청합니다. 헬스 커넥트 권한 화면이 표시됩니다.

// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()

val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions successfully granted
  } else {
    // Lack of required permissions
  }
}

suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
  val granted = healthConnectClient.permissionController.getGrantedPermissions()
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions already granted; proceed with inserting or reading data
  } else {
    requestPermissions.launch(PERMISSIONS)
  }
}

사용자는 언제든지 권한을 부여하거나 취소할 수 있으므로 앱은 부여된 권한을 주기적으로 확인하고 권한이 상실되는 시나리오를 처리해야 합니다.

데이터 소스

헬스 커넥트의 MedicalDataSource는 의료 기관, 병원, API와 같은 사용자 대상 데이터 소스를 나타냅니다.

헬스 커넥트에 저장된 의료 기록은 MedicalDataSource로 구성됩니다. 이를 통해 API 또는 의료 시스템과 같은 서로 다른 소스에서 가져온 동일한 개인의 의료 기록을 분리할 수 있습니다.

모든 레코드가 동일한 소스에서 비롯되는 경우 쓰기 앱은 MedicalDataSource를 하나만 만들면 됩니다. 레코드가 여러 소스에서 발생하는 경우에도 데이터가 조정되고 모든 레코드에 고유한 FHIR 리소스 유형과 FHIR 리소스 ID 조합이 있는 경우 앱은 단일 MedicalDataSource를 만들 수 있습니다. 그러지 않으면 각 데이터 소스에 대해 MedicalDataSource가 만들어져야 합니다.

모든 의료 기록은 MedicalDataSource와 연결되어야 하므로 리소스를 작성하기 전에 만들어야 합니다.

MedicalDataSource의 속성:

  • 표시 이름 (필수) - 데이터 소스의 사용자 대상 표시 이름으로, 작성 앱별로 고유하게 식별됩니다.
  • FHIR 기본 URI (필수) - FHIR 서버에서 가져온 데이터의 경우 FHIR 기본 URL이어야 합니다 (예: https://example.com/fhir/). 여러 데이터 소스를 동일한 FHIR 기본 URL과 연결할 수 있습니다.

    데이터가 FHIR URL이 없는 앱에서 생성된 경우 데이터 소스를 가리키는 앱에서 정의한 고유하고 이해하기 쉬운 URI(예: myapp://..)여야 합니다.

    예를 들어 클라이언트 앱이 딥 링크를 지원하는 경우 이 딥 링크를 FHIR Base URI로 사용할 수 있습니다. URI의 최대 길이는 2,000자(영문)입니다.

  • 패키지 이름 (자동으로 채워짐) - 데이터를 쓰는 앱입니다.

  • FHIR 버전 (필수) - FHIR 버전입니다. 지원되는 버전이어야 합니다.

MedicalDataSource 레코드 만들기

앱이 연결된 각 의료 기관 또는 법인의 레코드를 만듭니다.

// Create a `MedicalDataSource`
// Note that `displayName` must be unique across `MedicalDataSource`s
// Each `MedicalDataSource` is assigned an `id` by the system on creation
val medicalDataSource: MedicalDataSource =
    healthConnectClient.createMedicalDataSource(
        CreateMedicalDataSourceRequest(
            fhirBaseUri = Uri.parse("https://fhir.com/oauth/api/FHIR/R4/"),
            displayName = "Test Data Source",
            fhirVersion = FhirVersion(4, 0, 1)
        )
    )

MedicalDataSource 레코드 삭제

이전 예에서는 생성 시 시스템에 의해 id를 반환합니다. MedicalDataSource 레코드를 삭제해야 하는 경우 동일한 id를 참조합니다.

// Delete the `MedicalDataSource` that has the specified `id`
healthConnectClient.deleteMedicalDataSourceWithData(medicalDataSource.id)

의료 리소스

헬스 커넥트의 MedicalResource는 메타데이터와 함께 의료 기록이 포함된 FHIR 리소스를 나타냅니다.

MedicalResource의 속성:

  • DataSourceId (필수): MedicalDataSource에 설명된 데이터 소스입니다.
  • FHIR 버전 (필수) - FHIR 버전입니다. 지원되는 버전이어야 합니다.
  • FHIR 리소스 (필수) JSON으로 인코딩된 FHIR 리소스 인스턴스입니다.
  • 의료 리소스 유형 (자동으로 채워짐) - 사용자 대상 권한에 매핑되는 리소스의 사용자 대상 카테고리입니다.

JSON으로 FHIR 리소스 준비

헬스 커넥트에 의료 리소스를 쓰기 전에 JSON으로 FHIR 리소스 레코드를 준비합니다. 각 JSON을 의료 리소스로 삽입하기 위해 자체 변수에 저장합니다.

FHIR JSON 형식과 관련하여 도움이 필요한 경우 HL7 조직에서 제공한 예시 데이터를 참고하세요.

MedicalResource 레코드 삽입 또는 업데이트

UpsertMedicalResourceRequest를 사용하여 MedicalDataSource의 새 MedicalResource 레코드를 삽입하거나 기존 MedicalResource 레코드를 업데이트합니다.

// Insert `MedicalResource`s into the `MedicalDataSource`
val medicalResources: List<MedicalResource> =
    healthConnectClient.upsertMedicalResources(
        listOf(
            UpsertMedicalResourceRequest(
                medicalDataSource.id,
                medicalDataSource.fhirVersion,
                medicationJsonToInsert // a valid FHIR json string
            )
        )
    )

// Update `MedicalResource`s in the `MedicalDataSource`
val updatedMedicalResources: List<MedicalResource> =
    healthConnectClient.upsertMedicalResources(
        listOf(
            UpsertMedicalResourceRequest(
                medicalDataSource.id,
                medicalDataSource.fhirVersion,
                // a valid FHIR json string
                // if this resource has the same type and ID as in `medicationJsonToInsert`,
                // this `upsertMedicalResources()` call will update the previously inserted
                // `MedicalResource`
                updatedMedicationJsonToInsert
            )
        )
    )

FHIR 리소스 예시

이전 예에서 medicationJsonToInsert 변수는 유효한 FHIR JSON 문자열을 나타냈습니다.

다음은 AllergyIntolerance를 FHIR 리소스 유형으로 사용하여 PHR의 FHIR_RESOURCE_TYPE_ALLERGY_INTOLERANCE 의학 리소스 유형에 매핑되는 JSON의 예입니다.

{
  "resourceType": "AllergyIntolerance",
  "id": "allergyintolerance-1",
  "criticality": "high",
  "code": {
    "coding": [
      {
        "system": "http://snomed.info/sct",
        "code": "91936005",
        "display": "Penicillin allergy"
      }
    ],
    "text": "Penicillin allergy"
  },
  "recordedDate": "2020-10-09T14:58:00+00:00",
   "asserter": {
    "reference": "Patient/patient-1"
  },
  "lastOccurrence": "2020-10-09",
  "patient": {
    "reference": "Patient/patient-1",
    "display": "B., Alex"
  }
  ...
}

MedicalResource 레코드 삭제

MedicalResource 레코드가 ID별로 삭제될 수 있습니다.

// Delete `MedicalResource`s matching the specified `dataSourceId`, `type` and `fhirResourceId`
healthConnectClient.deleteMedicalResources(
    medicalResources.map { medicalResource: MedicalResource ->
        MedicalResourceId(
            dataSourceId = medicalDataSource.id,
            fhirResourceType = medicalResource.id.fhirResourceType,
            fhirResourceId = medicalResource.id.fhirResourceId
        )
    }
)

또는 medicalResourceType를 사용하여 삭제할 수 있습니다.

// Delete all `MedicalResource`s that are in any pair of provided `dataSourceIds` and
// `medicalResourceTypes`
healthConnectClient.deleteMedicalResources(
    DeleteMedicalResourcesRequest(
        dataSourceIds = setOf(medicalDataSource.id),
        medicalResourceTypes = setOf(MEDICAL_RESOURCE_TYPE_MEDICATIONS)
    )
)