Отслеживайте шаги

Health Connect предоставляет тип данных «Шаги» для регистрации количества шагов с помощью StepsRecord . Шаги — это основополагающий показатель для отслеживания здоровья и физической формы.

Прочитайте мобильные шаги

В Android 14 (уровень API 34) и версии SDK Extension 20 или выше Health Connect обеспечивает подсчёт шагов на устройстве. Если какому-либо приложению предоставлено разрешение READ_STEPS , Health Connect начинает подсчитывать шаги на устройстве Android, и пользователи видят данные о пройденных шагах, автоматически добавляемые в записи Health Connect Steps .

Чтобы проверить, доступен ли подсчет шагов на устройстве, необходимо убедиться, что устройство работает под управлением 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

Для мобильных устройств, отслеживаемых Health Connect, значение DataOrigin задано как имя пакета android . Если ваше приложение просто считывает агрегированные данные о количестве шагов с помощью aggregate и не фильтрует их по DataOrigin , шаги, пройденные на устройстве, автоматически включаются в общую сумму.

Если вашему приложению необходимо считывать шаги на устройстве или отображать данные о шагах с разбивкой по исходному приложению или устройству, вы можете запросить записи, где DataOriginandroid . Если ваше приложение отображает атрибуцию для данных о шагах, необходимо приписать данные из пакета Android текущему устройству. Это можно сделать, используя метку, например «Ваш телефон», получив имя устройства с помощью Settings.Global.getString(resolver, Settings.Global.DEVICE_NAME) или проверив поле Device в метаданных записи.

В следующем примере показано, как считывать агрегированные данные о количестве шагов на мобильном устройстве, фильтруя данные по источнику android :

suspend fun readStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
                dataOriginFilter = setOf(DataOrigin("android"))
            )
        )
        // The result may be null if no data is available in the time range
        val stepCount = response[StepsRecord.COUNT_TOTAL]
    } catch (e: Exception) {
        // Run error handling here
    }
}

Подсчет шагов на устройстве

Более подробное рассмотрение функции подсчета шагов на устройстве:

  • Использование датчика : Health Connect использует датчик TYPE_STEP_COUNTER от SensorManager . Этот датчик оптимизирован для низкого энергопотребления, что делает его идеальным для непрерывного фонового отслеживания шагов.
  • Детализация данных : для экономии заряда батареи данные о шагах обычно пакетируются и записываются в базу данных Health Connect не чаще одного раза в минуту.
  • Атрибуция : как упоминалось ранее, все шаги, записанные этой функцией устройства, приписываются имени пакета android в DataOrigin .
  • Активация : Механизм подсчета шагов на устройстве активен только в том случае, если хотя бы одному приложению на устройстве предоставлено разрешение READ_STEPS в Health Connect.

Проверьте доступность Health Connect

Прежде чем использовать Health Connect, ваше приложение должно проверить наличие Health Connect на устройстве пользователя. Health Connect может быть предустановлен не на всех устройствах или отключен. Проверить наличие Health Connect можно с помощью метода HealthConnectClient.getSdkStatus() .

Как проверить доступность 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
}

В зависимости от статуса, возвращаемого getSdkStatus() , вы можете предложить пользователю установить или обновить Health Connect из Google Play Store, если это необходимо.

Требуемые разрешения

Доступ к шагам защищен следующими разрешениями:

  • android.permission.health.READ_STEPS
  • android.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.

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(StepsRecord::class),
  HealthPermission.getWritePermission(StepsRecord::class)
)

Используйте getGrantedPermissions , чтобы проверить, предоставлены ли приложению необходимые разрешения. Если нет, запросите их с помощью createRequestPermissionResultContract . Откроется экран разрешений Health Connect.

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

Поскольку пользователи могут предоставлять или отзывать разрешения в любое время, ваше приложение должно периодически проверять наличие предоставленных разрешений и обрабатывать ситуации, когда разрешение теряется.

Информация, включенная в запись Steps

Каждый StepsRecord содержит следующую информацию:

  • count : Количество шагов, сделанных за интервал времени, в виде Long .
  • startTime : время начала интервала измерения.
  • endTime : время окончания интервала измерения.
  • startZoneOffset : смещение зоны для времени начала.
  • endZoneOffset : смещение зоны для времени окончания.

Поддерживаемые агрегации

Для StepsRecord доступны следующие агрегированные значения:

Для StepsCadenceRecord доступны следующие агрегированные значения:

Пример использования

В следующих разделах показано, как читать и записывать данные StepsRecord .

Запись данных шагов

Ваше приложение может записывать данные о количестве шагов, добавляя экземпляры StepsRecord . В следующем примере показано, как записать 1000 шагов, сделанных пользователем:

suspend fun writeStepsData(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant,
    startZoneOffset: ZoneOffset,
    endZoneOffset: ZoneOffset
) {
    try {
        val stepsRecord = StepsRecord(
            startTime = startTime,
            startZoneOffset = startZoneOffset,
            endTime = endTime,
            endZoneOffset = endZoneOffset,
            count = 1000
        )
        healthConnectClient.insertRecords(listOf(stepsRecord))
    } catch (e: Exception) {
        // Run error handling
    }
}

Прочитать агрегированные данные

Самый распространённый способ считывания данных о количестве шагов — это агрегация общего количества шагов за определённый период. В следующем примере показано, как получить общее количество шагов пользователя за определённый период времени:

suspend fun readStepsAggregate(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
        // The result may be null if no data is available in the time range
        val stepCount = response[StepsRecord.COUNT_TOTAL]
    } catch (e: Exception) {
        // Run error handling here
    }
}

Чтение необработанных данных

В следующем примере показано, как считывать необработанные данные StepsRecord между начальным и конечным временем:

suspend fun readStepsRaw(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.readRecords(
            ReadRecordsRequest(
                recordType = StepsRecord::class,
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
        for (record in response.records) {
            // Process each record
        }
    } catch (e: Exception) {
        // Run error handling here
    }
}