헬스 커넥트는 StepsRecord를 사용하여 걸음 수를 기록하는 걸음 수 데이터 유형을 제공합니다. 걸음 수는 건강 및 피트니스 추적의 기본 측정 단위입니다.
모바일 걸음 수 읽기
Android 14 (API 수준 34) 및 SDK 확장 프로그램 버전 20 이상에서 헬스 커넥트는 온디바이스 걸음 수 계산을 제공합니다. 앱에 READ_STEPS 권한이 부여되면 헬스 커넥트에서 Android 기반 기기의 걸음 수를 캡처하기 시작하고 사용자에게 헬스 커넥트 걸음 수 항목에 걸음 수 데이터가 자동으로 추가되어 표시됩니다.
온디바이스 걸음 수 측정을 사용할 수 있는지 확인하려면 기기가 Android 14 (API 수준 34)를 실행하고 SDK 확장 프로그램 버전이 20 이상인지 확인하세요.
val isStepTrackingAvailable =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 20
앱이 aggregate를 사용하여 집계된 걸음 수를 읽고 DataOrigin로 필터링하지 않으면 온디바이스 걸음 수가 합계에 자동으로 포함되며 2026년 6월 업데이트를 위해 변경할 필요가 없습니다.
온디바이스 단계의 기여 분석 변경
2026년 6월 업데이트부터 Health Connect에서 기본적으로 추적하는 걸음 수는 com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e와 같은 합성 패키지 이름 (SPN)에 기여한 것으로 표시됩니다.
이전에는 내장 단계가 패키지 이름 android에 기여한 것으로 표시되었습니다.
2026년 6월 이전에 기록된 이전 단계 데이터는 android 패키지 이름을 유지합니다.
SPN은 기기별이며 사용자 개인 정보를 보호하기 위해 애플리케이션별로 범위가 지정됩니다.
- 안정: 현재 기기의 SPN이 애플리케이션에 안정적입니다.
- 애플리케이션 범위: 동일한 기기의 서로 다른 애플리케이션은 기기 내 걸음 수 데이터에 대해 서로 다른 SPN을 확인합니다.
온디바이스 단계 쿼리
SPN은 범위가 지정되고 기기별이므로 SPN 값을 하드코딩하면 안 됩니다. 대신 getCurrentDeviceDataSource API를 사용하여 현재 기기의 SPN을 가져옵니다.
온디바이스 걸음 수 측정에는 SDK 확장 프로그램 버전 20 이상이 필요하지만 getCurrentDeviceDataSource() API는 SDK 확장 프로그램 버전 22 이상이 적용된 Android 14 (API 수준 34)에서 사용할 수 있습니다. 이 API를 사용하려면 모듈 수준 build.gradle.kts 또는 build.gradle 파일에서 compileSdkExtension을 22 이상으로 설정하세요.
Kotlin
android { compileSdk = 35 compileSdkExtension = 22 }
Groovy
android { compileSdk 35 compileSdkExtension 22 }
getCurrentDeviceDataSource() API는 아직 헬스 커넥트 Jetpack 라이브러리에서 사용할 수 없습니다. 다음 예에서는 Executor 및 OutcomeReceiver 콜백이 필요한 Android 프레임워크 API를 사용합니다.
import android.content.Context
import android.health.connect.DeviceDataSource
import android.health.connect.HealthConnectException
import android.health.connect.HealthConnectManager
import android.os.OutcomeReceiver
val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)
healthConnectManager?.getCurrentDeviceDataSource(
context.mainExecutor,
object : OutcomeReceiver<DeviceDataSource, HealthConnectException> {
override fun onResult(result: DeviceDataSource) {
val currentDeviceSpn = result.deviceDataOrigin.packageName
}
override fun onError(error: HealthConnectException) {
// Handle error
}
}
)
앱에서 온디바이스 걸음 수를 읽어야 하거나 소스 애플리케이션 또는 기기별로 분류된 걸음 수 데이터를 표시하는 경우 DataOrigin이 android이거나 기기의 SPN과 일치하는 레코드를 쿼리해야 합니다. 앱에서 걸음 수 데이터의 기여 분석을 표시하는 경우 metadata.device를 사용하여 개별 레코드의 소스 기기를 식별합니다. 집계된 데이터에서 SPN으로 식별되는 온디바이스 단계의 경우 DeviceDataSource의 model 또는 manufacturer와 같은 기기 메타데이터를 기여 분석에 사용하거나 온디바이스 단계에 '휴대전화'와 같은 일반 라벨을 사용할 수 있습니다.
다음 예는 android와 현재 기기 SPN을 모두 필터링하여 집계된 온디바이스 걸음 수 데이터를 읽는 방법을 보여줍니다.
import android.content.Context
import android.health.connect.DeviceDataSource
import android.health.connect.HealthConnectException
import android.health.connect.HealthConnectManager
import android.os.Build
import android.os.OutcomeReceiver
import android.os.ext.SdkExtensions
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.records.metadata.DataOrigin
import androidx.health.connect.client.request.AggregateRequest
import androidx.health.connect.client.time.TimeRangeFilter
import java.time.Instant
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlinx.coroutines.suspendCancellableCoroutine
suspend fun readDeviceStepsByTimeRange(
healthConnectClient: HealthConnectClient,
context: Context,
startTime: Instant,
endTime: Instant
) {
// 1. Check if SDK Extension 22+ is available for getCurrentDeviceDataSource()
val isDataSourceApiAvailable =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 22
try {
val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)
// 2. Safely fetch the package name only if the API is available
val currentDeviceSpn = if (isDataSourceApiAvailable && healthConnectManager != null) {
suspendCancellableCoroutine { continuation ->
healthConnectManager.getCurrentDeviceDataSource(
context.mainExecutor,
object : OutcomeReceiver<DeviceDataSource, HealthConnectException> {
override fun onResult(result: DeviceDataSource) {
continuation.resume(result.deviceDataOrigin.packageName)
}
override fun onError(error: HealthConnectException) {
continuation.resumeWithException(error)
}
}
)
}
} else {
null
}
val dataOriginFilters = mutableSetOf(DataOrigin("android"))
// 3. Explicit null-safety check using .let
currentDeviceSpn?.let {
dataOriginFilters.add(DataOrigin(it))
}
val response = healthConnectClient.aggregate(
AggregateRequest(
metrics = setOf(StepsRecord.COUNT_TOTAL),
timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
dataOriginFilter = dataOriginFilters
)
)
val stepCount = response[StepsRecord.COUNT_TOTAL]
} catch (e: Exception) {
// Now this catch block only handles actual runtime exceptions,
// rather than Errors from missing methods.
}
}
온디바이스 걸음 수 측정
- 센서 사용: 헬스 커넥트는
SensorManager의TYPE_STEP_COUNTER센서를 활용합니다. 이 센서는 전력 소비가 낮도록 최적화되어 있어 지속적인 백그라운드 단계 추적에 적합합니다. - 데이터 세분성: 배터리 수명을 절약하기 위해 걸음 수 데이터는 일반적으로 일괄 처리되어 헬스 커넥트 데이터베이스에 분당 한 번 이하로 기록됩니다.
- 기여도: 2026년 6월 이전에 이 기능으로 기록된 걸음 수는
DataOrigin의android패키지 이름에 기여도가 부여됩니다. 이 날짜 이후에는 기기별 SPN으로 귀속됩니다. 온디바이스 단계의 기여 분석 변경사항을 참고하세요. - 활성화: 기기 내 걸음 수 측정 메커니즘은 기기의 하나 이상의 애플리케이션에 헬스 커넥트 내에서
READ_STEPS권한이 부여된 경우에만 활성화됩니다.
헬스 커넥트 사용 가능 여부 확인
헬스 커넥트를 사용하기 전에 앱에서 사용자의 기기에서 헬스 커넥트를 사용할 수 있는지 확인해야 합니다. 헬스 커넥트가 일부 기기에 사전 설치되어 있지 않거나 사용 중지되어 있을 수 있습니다.
HealthConnectClient.getSdkStatus() 메서드를 사용하여 사용 가능 여부를 확인할 수 있습니다.
헬스 커넥트 사용 가능 여부를 확인하는 방법
fun checkHealthConnectAvailability(context: Context) { val providerPackageName = "com.google.android.apps.healthdata" // Or get from HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName) if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) { // Health Connect is not available. Guide the user to install/enable it. // For example, show a dialog. return // early return as there is no viable integration } if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) { // Health Connect is available but requires an update. // Optionally redirect to package installer to find a provider, for example: val uriString = "market://details?id=$providerPackageName&url=healthconnect%3A%2F%2Fonboarding" context.startActivity( Intent(Intent.ACTION_VIEW).apply { setPackage("com.android.vending") data = Uri.parse(uriString) putExtra("overlay", true) putExtra("callerId", context.packageName) } ) return } // Health Connect is available, obtain a HealthConnectClient instance val healthConnectClient = HealthConnectClient.getOrCreate(context) // Issue operations with healthConnectClient }
getSdkStatus()에서 반환된 상태에 따라 필요한 경우 사용자가 Google Play 스토어에서 헬스 커넥트를 설치하거나 업데이트하도록 안내할 수 있습니다.
필수 권한
걸음 수에 대한 액세스는 다음 권한으로 보호됩니다.
android.permission.health.READ_STEPSandroid.permission.health.WRITE_STEPS
앱에 걸음 수 기능을 추가하려면 먼저 Steps 데이터 유형에 대한 권한을 요청하세요.
걸음 수를 쓰기 위해 선언해야 하는 권한은 다음과 같습니다.
<application>
<uses-permission
android:name="android.permission.health.WRITE_STEPS" />
...
</application>
단계를 읽으려면 다음 권한을 요청해야 합니다.
<application>
<uses-permission
android:name="android.permission.health.READ_STEPS" />
...
</application>
사용자에게 권한 요청
클라이언트 인스턴스를 만든 후 앱은 사용자에게 권한을 요청해야 합니다. 사용자는 언제든지 권한을 부여하거나 거부할 수 있어야 합니다. 이렇게 하려면 필요한 데이터 유형의 권한 집합을 만드세요. 세트에 있는 권한이 먼저 Android 매니페스트에 선언되어 있는지 확인합니다.
val permissions = setOf( HealthPermission.getReadPermission(StepsRecord::class), HealthPermission.getWritePermission(StepsRecord::class) )
getGrantedPermissions을 사용하여 앱에 필요한 권한이 이미 부여되어 있는지 확인합니다. 그렇지 않은 경우 createRequestPermissionResultContract을 사용하여 이러한 권한을 요청합니다. 헬스 커넥트 권한 화면이 표시됩니다.
val permissions = setOf( HealthPermission.getReadPermission(StepsRecord::class), HealthPermission.getWritePermission(StepsRecord::class), HealthPermission.getReadPermission(HeartRateRecord::class), HealthPermission.getWritePermission(HeartRateRecord::class) ) val requestPermissionsLauncher = rememberLauncherForActivityResult( contract = PermissionController.createRequestPermissionResultContract() ) { grantedPermissions -> if (grantedPermissions.containsAll(permissions)) { coroutineScope.launch { snackbarHostState.showSnackbar("Permissions granted!") } } else { coroutineScope.launch { snackbarHostState.showSnackbar("Permissions denied.") } } }
Steps 기록에 포함된 정보
각 StepsRecord에는 다음 정보가 포함됩니다.
count: 시간 간격 동안 걸은 걸음 수입니다(Long).startTime: 측정 간격의 시작 시간입니다.endTime: 측정 간격의 종료 시간입니다.startZoneOffset: 시작 시간의 시간대 오프셋입니다.endZoneOffset: 종료 시간의 영역 오프셋입니다.
지원되는 집계
StepsRecord에 사용할 수 있는 집계 값은 다음과 같습니다.
StepsCadenceRecord에 사용할 수 있는 집계 값은 다음과 같습니다.
사용 예시
다음 섹션에서는 StepsRecord 데이터를 읽고 쓰는 방법을 보여줍니다.
걸음 수 데이터 쓰기
앱은 StepsRecord 인스턴스를 삽입하여 걸음 수 데이터를 쓸 수 있습니다. 다음 예는 사용자가 걸은 1,000걸음을 기록하는 방법을 보여줍니다.
val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(startTime) val stepsRecord = StepsRecord( count = 120, startTime = startTime, endTime = endTime, startZoneOffset = zoneOffset, endZoneOffset = zoneOffset, metadata = Metadata.autoRecorded( device = Device(type = Device.TYPE_WATCH) ) ) healthConnectClient.insertRecords(listOf(stepsRecord))
집계 데이터 읽기
걸음 데이터를 읽는 가장 일반적인 방법은 일정 기간 동안의 총 걸음 수를 집계하는 것입니다. 다음 예는 특정 기간 내에서 사용자의 총 걸음 수를 읽는 방법을 보여줍니다.
suspend fun readStepsAggregate(startTime: Instant, endTime: Instant): Long { val response = healthConnectClient.aggregate( AggregateRequest( metrics = setOf(StepsRecord.COUNT_TOTAL), timeRangeFilter = TimeRangeFilter.between(startTime, endTime) ) ) return response[StepsRecord.COUNT_TOTAL] ?: 0L }
원시 데이터 읽기
다음 예는 시작 시간과 종료 시간 사이에 원시 StepsRecord 데이터를 읽는 방법을 보여줍니다.
val response = healthConnectClient.readRecords( ReadRecordsRequest( StepsRecord::class, timeRangeFilter = TimeRangeFilter.between(startTime, endTime) ) ) response.records.forEach { record -> /* Process records */ }