Monitorare i passi

Health Connect fornisce un tipo di dati passi per registrare i conteggi dei passi utilizzando StepsRecord. I passi sono una misurazione fondamentale nel monitoraggio della salute e del fitness.

Lettura dei passi da dispositivo mobile

Con Android 14 (livello API 34) e la versione 20 o successive dell'estensione SDK, Health Connect fornisce il conteggio dei passi sul dispositivo. Se a un'app è stata concessa l'autorizzazione READ_STEPS, Health Connect inizia a registrare i passi dal dispositivo Android e gli utenti vedono i dati sui passi aggiunti automaticamente alle voci Passi di Health Connect.

Per verificare se il conteggio dei passi sul dispositivo è disponibile, controlla che il dispositivo utilizzi Android 14 (livello API 34) e abbia almeno la versione 20 dell'estensione SDK:

val isStepTrackingAvailable =
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
        SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 20

Se la tua app legge i conteggi dei passi aggregati utilizzando aggregate e non filtra per DataOrigin, i passi sul dispositivo vengono inclusi automaticamente nel totale e non sono necessarie modifiche per l'aggiornamento di giugno 2026.

Modifica dell'attribuzione per i passi sul dispositivo

A partire dall'aggiornamento di giugno 2026, i passi monitorati in modo nativo da Health Connect vengono attribuiti a un nome del pacchetto sintetico (SPN), ad esempio com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e.

In precedenza, i passaggi integrati venivano attribuiti al nome del pacchetto android. I dati storici sui passi registrati prima di giugno 2026 conservano il nome del pacchetto android.

I nomi principali del servizio sono specifici per dispositivo e vengono definiti in base all'applicazione per proteggere la privacy degli utenti:

  • Stabile:l'SPN per il dispositivo attuale è stabile per la tua applicazione.
  • Ambito dell'applicazione:diverse applicazioni sullo stesso dispositivo visualizzano SPN diversi per i dati dei passi sul dispositivo.

Query per i passaggi on-device

Poiché gli SPN sono specifici per ambito e dispositivo, non devi codificare i valori SPN. Utilizza invece l'API getCurrentDeviceDataSource per recuperare l'SPN per il dispositivo attuale.

Mentre il conteggio dei passi sul dispositivo richiede la versione 20 o successive dell'estensione SDK, l'API getCurrentDeviceDataSource() è disponibile su Android 14 (livello API 34) con la versione 22 o successive dell'estensione SDK. Per utilizzare questa API, imposta compileSdkExtension su 22 o versioni successive nel file build.gradle.kts o build.gradle a livello di modulo:

Kotlin

android {
    compileSdk = 35
    compileSdkExtension = 22
}

Alla moda

android {
    compileSdk 35
    compileSdkExtension 22
}

L'API getCurrentDeviceDataSource() non è ancora disponibile nella libreria Jetpack di Connessione Salute. Gli esempi seguenti utilizzano l'API del framework Android, che richiede un callback Executor e un callback OutcomeReceiver:

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
        }
    }
)

Se la tua app deve leggere i passi sul dispositivo o se mostra i dati dei passi suddivisi per applicazione o dispositivo di origine, devi eseguire query per i record in cui DataOrigin è android o corrisponde all'SPN del dispositivo. Se la tua app mostra l'attribuzione per i dati dei passi, utilizza metadata.device per identificare il dispositivo di origine per i singoli record. Per i passaggi on-device identificati da un SPN nei dati aggregati, puoi utilizzare i metadati del dispositivo, ad esempio model o manufacturer di DeviceDataSource per l'attribuzione oppure utilizzare un'etichetta generica come "Il tuo smartphone" per i passaggi on-device.

L'esempio seguente mostra come leggere i dati aggregati del conteggio dei passi sul dispositivo filtrando sia android sia l'SPN del dispositivo corrente:

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.
    }
}

Conteggio dei passi on-device

  • Utilizzo dei sensori: Health Connect utilizza il sensore TYPE_STEP_COUNTER di SensorManager. Questo sensore è ottimizzato per un basso consumo energetico, il che lo rende ideale per il monitoraggio continuo dei passi in background.
  • Granularità dei dati: per risparmiare batteria, i dati sui passi vengono in genere raggruppati e scritti nel database di Health Connect non più di una volta al minuto.
  • Attribuzione: i passi registrati da questa funzionalità prima di giugno 2026 sono attribuiti al nome del pacchetto android in DataOrigin. Dopo questa data, vengono attribuite a un SPN specifico per dispositivo. Vedi Modifica dell'attribuzione per i passaggi sul dispositivo.
  • Attivazione: il meccanismo di conteggio dei passi sul dispositivo è attivo solo quando ad almeno un'applicazione sul dispositivo è stata concessa l'autorizzazione READ_STEPS in Health Connect.

Controlla la disponibilità di Connessione Salute

Prima di tentare di utilizzare Health Connect, la tua app deve verificare che Health Connect sia disponibile sul dispositivo dell'utente. Health Connect potrebbe non essere preinstallata su tutti i dispositivi o potrebbe essere disattivata. Puoi verificare la disponibilità utilizzando il metodo HealthConnectClient.getSdkStatus().

Come controllare la disponibilità di Health Connect

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
}

A seconda dello stato restituito da getSdkStatus(), puoi guidare l'utente all'installazione o all'aggiornamento di Connessione Salute dal Google Play Store, se necessario.

Autorizzazioni obbligatorie

L'accesso ai passi è protetto dalle seguenti autorizzazioni:

  • android.permission.health.READ_STEPS
  • android.permission.health.WRITE_STEPS

Per aggiungere la funzionalità di passi alla tua app, inizia richiedendo le autorizzazioni per il tipo di dati Steps.

Ecco l'autorizzazione che devi dichiarare per poter scrivere i passi:

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

Per leggere i passi, devi richiedere le seguenti autorizzazioni:

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

Richiedi le autorizzazioni all'utente

Dopo aver creato un'istanza client, l'app deve richiedere le autorizzazioni all'utente. Gli utenti devono poter concedere o negare le autorizzazioni in qualsiasi momento. A questo scopo, crea un set di autorizzazioni per i tipi di dati richiesti. Assicurati che le autorizzazioni nel set siano dichiarate prima nel manifest di Android.

val permissions =
    setOf(
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class)
    )
Utilizza getGrantedPermissions per verificare se alla tua app sono già state concesse le autorizzazioni richieste. In caso contrario, utilizza createRequestPermissionResultContract per richiedere queste autorizzazioni. Viene visualizzata la schermata delle autorizzazioni di Health Connect.
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.") }
    }
}
Poiché gli utenti possono concedere o revocare le autorizzazioni in qualsiasi momento, la tua app deve controllare le autorizzazioni ogni volta prima di utilizzarle e gestire gli scenari in cui l'autorizzazione viene revocata.

Informazioni incluse in un record Passi

Ogni StepsRecord contiene le seguenti informazioni:

  • count: il numero di passi effettuati nell'intervallo di tempo, come Long.
  • startTime: l'ora di inizio dell'intervallo di misurazione.
  • endTime: l'ora di fine dell'intervallo di misurazione.
  • startZoneOffset: l'offset della zona per l'ora di inizio.
  • endZoneOffset: l'offset della zona per l'ora di fine.

Aggregazioni supportate

Per StepsRecord sono disponibili i seguenti valori aggregati:

Per StepsCadenceRecord sono disponibili i seguenti valori aggregati:

Esempio di utilizzo

Le sezioni seguenti mostrano come leggere e scrivere i dati StepsRecord.

Scrittura dei dati sui passi

La tua app può scrivere i dati del conteggio dei passi inserendo istanze di StepsRecord. Il seguente esempio mostra come registrare 1000 passi compiuti da un utente:

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))

Leggere i dati aggregati

Il modo più comune per leggere i dati dei passi è aggregare il totale dei passi in un periodo di tempo. Il seguente esempio mostra come leggere il conteggio totale dei passi per un utente in un determinato intervallo di tempo:

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
}

Leggere i dati non elaborati

Il seguente esempio mostra come leggere i dati StepsRecord grezzi tra un'ora di inizio e di fine:

val response = healthConnectClient.readRecords(
    ReadRecordsRequest(
        StepsRecord::class,
        timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
    )
)
response.records.forEach { record ->
    /* Process records */
}