Theo dõi số bước

Health Connect cung cấp loại dữ liệu bước để ghi lại số bước bằng StepsRecord. Số bước là một chỉ số đo lường cơ bản trong việc theo dõi sức khoẻ và hoạt động thể chất.

Hướng dẫn này tương thích với Health Connect phiên bản 1.1.0-alpha12 trở lên.

Đọc số bước trên thiết bị di động

Với Android 14 (cấp độ API 34) và Tiện ích SDK phiên bản 20 trở lên, Health Connect cung cấp tính năng đếm bước trên thiết bị. Nếu bất kỳ ứng dụng nào được cấp quyền READ_STEPS, Health Connect sẽ bắt đầu ghi lại số bước trên thiết bị Android và người dùng sẽ thấy dữ liệu về số bước được tự động thêm vào mục Số bước trong Health Connect.

Để kiểm tra xem tính năng đếm bước trên thiết bị có hoạt động hay không, hãy xác minh rằng thiết bị đang chạy Android 14 (cấp độ API 34) và có ít nhất tiện ích SDK phiên bản 20:

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

Nếu ứng dụng của bạn đọc số bước tổng hợp bằng aggregate và không lọc theo DataOrigin, thì số bước trên thiết bị sẽ tự động được tính vào tổng số và bạn không cần thay đổi gì cho bản cập nhật tháng 6 năm 2026.

Thay đổi về mô hình phân bổ cho các bước trên thiết bị

Kể từ bản cập nhật tháng 6 năm 2026, các bước được Health Connect theo dõi tự nhiên sẽ được phân bổ cho một Tên gói tổng hợp (SPN), chẳng hạn như com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e.

Trước đây, các bước tích hợp sẵn được phân bổ cho tên gói android. Dữ liệu bước trước đây được ghi lại trước tháng 6 năm 2026 sẽ giữ lại tên gói android.

SPN dành riêng cho thiết bị và được xác định phạm vi theo từng ứng dụng để bảo vệ quyền riêng tư của người dùng:

  • Ổn định: SPN cho thiết bị hiện tại ổn định cho ứng dụng của bạn.
  • Phạm vi ứng dụng: Các ứng dụng khác nhau trên cùng một thiết bị sẽ thấy các SPN khác nhau cho dữ liệu bước trên thiết bị.

Truy vấn các bước trên thiết bị

Vì SPN có phạm vi và dành riêng cho thiết bị, nên bạn không được cố định giá trị SPN trong mã. Thay vào đó, hãy sử dụng API getCurrentDeviceDataSource để truy xuất SPN cho thiết bị hiện tại.

Mặc dù tính năng đếm bước trên thiết bị yêu cầu tiện ích SDK phiên bản 20 trở lên, nhưng API getCurrentDeviceDataSource() có trên Android 14 (cấp độ API 34) với tiện ích SDK phiên bản 22 trở lên. Để sử dụng API này, hãy đặt compileSdkExtension thành 22 trở lên trong tệp build.gradle.kts hoặc build.gradle ở cấp mô-đun:

Kotlin

android {
    compileSdk = 35
    compileSdkExtension = 22
}

Groovy

android {
    compileSdk 35
    compileSdkExtension 22
}

API getCurrentDeviceDataSource() chưa có trong thư viện Jetpack của Health Connect. Các ví dụ sau đây sử dụng API khung Android, yêu cầu lệnh gọi lại Executor và 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
        }
    }
)

Nếu ứng dụng của bạn cần đọc số bước trên thiết bị hoặc nếu ứng dụng hiển thị dữ liệu số bước được phân tích theo ứng dụng hoặc thiết bị nguồn, thì bạn phải truy vấn các bản ghi có DataOrigin là android hoặc khớp với SPN của thiết bị. Nếu ứng dụng của bạn cho thấy thông tin ghi nhận tác giả cho dữ liệu về số bước, hãy sử dụng metadata.device để xác định thiết bị nguồn cho từng bản ghi. Đối với các bước trên thiết bị được xác định bằng SPN trong dữ liệu tổng hợp, bạn có thể sử dụng siêu dữ liệu của thiết bị như model hoặc manufacturer từ DeviceDataSource để phân bổ hoặc sử dụng nhãn chung như "Điện thoại của bạn" cho các bước trên thiết bị.

Ví dụ sau đây cho thấy cách đọc dữ liệu tổng hợp về số bước trên thiết bị bằng cách lọc cả android và SPN của thiết bị hiện tại:

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

Đếm bước trên thiết bị

  • Mức sử dụng cảm biến: Health Connect sử dụng cảm biến TYPE_STEP_COUNTER của SensorManager. Cảm biến này được tối ưu hoá để tiêu thụ ít điện năng, nhờ đó rất phù hợp để theo dõi bước liên tục trong nền.
  • Mức độ chi tiết của dữ liệu: Để tiết kiệm pin, dữ liệu về số bước thường được gộp và ghi vào cơ sở dữ liệu Health Connect không quá một lần mỗi phút.
  • Ghi nhận tác giả: Các bước được tính năng này ghi lại trước tháng 6 năm 2026 được ghi nhận cho tên gói android trong DataOrigin. Sau ngày này, các lượt cài đặt đó sẽ được phân bổ cho một SPN dành riêng cho thiết bị. Xem phần Thay đổi về mô hình phân bổ cho số bước trên thiết bị.
  • Kích hoạt: Cơ chế đếm bước trên thiết bị chỉ hoạt động khi ít nhất một ứng dụng trên thiết bị được cấp quyền READ_STEPS trong Health Connect.

Kiểm tra phạm vi cung cấp của Health Connect

Trước khi cố gắng sử dụng Health Connect, ứng dụng của bạn nên xác minh rằng Health Connect có sẵn trên thiết bị của người dùng. Health Connect có thể không được cài đặt sẵn trên một số thiết bị hoặc có thể bị tắt. Bạn có thể kiểm tra xem có thể sử dụng tính năng này hay không bằng phương thức HealthConnectClient.getSdkStatus().

Cách kiểm tra xem Health Connect có hoạt động hay không

fun checkHealthConnectAvailability(context: Context) {
    val providerPackageName = "com.google.android.apps.healthdata"
    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
}

Tuỳ thuộc vào trạng thái mà getSdkStatus() trả về, bạn có thể hướng dẫn người dùng cài đặt hoặc cập nhật Health Connect từ Cửa hàng Google Play nếu cần.

Các quyền bắt buộc

Quyền truy cập vào số bước được bảo vệ bằng các quyền sau:

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

Để thêm chức năng số bước vào ứng dụng, hãy bắt đầu bằng cách yêu cầu quyền cho kiểu dữ liệu Steps.

Dưới đây là quyền bạn cần khai báo để có thể ghi số bước:

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

Để đọc dữ liệu về số bước, bạn cần yêu cầu các quyền sau:

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

Yêu cầu người dùng cấp quyền

Sau khi tạo một phiên bản ứng dụng, ứng dụng của bạn cần yêu cầu người dùng cấp quyền. Người dùng phải được phép cấp hoặc từ chối cấp quyền bất cứ lúc nào. Để thực hiện việc này, hãy tạo một tập hợp quyền cho các kiểu dữ liệu bắt buộc. Trước tiên, bạn cần khai báo các quyền trong tập hợp này ở tệp kê khai Android.

val permissions =
    setOf(
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class)
    )
Hãy sử dụng getGrantedPermissions để xem ứng dụng của bạn đã được cấp các quyền cần thiết chưa. Nếu chưa, hãy sử dụng createRequestPermissionResultContract để yêu cầu các quyền đó. Thao tác này sẽ hiện màn hình các quyền của 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.") }
    }
}
Vì người dùng có thể cấp hoặc thu hồi quyền bất cứ lúc nào, nên ứng dụng của bạn cần kiểm tra quyền mỗi lần trước khi sử dụng và xử lý các trường hợp mất quyền.

Thông tin có trong bản ghi Số bước

Mỗi StepsRecord chứa thông tin sau:

  • count: Số bước đã thực hiện trong khoảng thời gian, dưới dạng Long.
  • startTime: Thời gian bắt đầu của khoảng thời gian đo lường.
  • endTime: Thời gian kết thúc của khoảng thời gian đo lường.
  • startZoneOffset: Độ lệch múi giờ cho thời gian bắt đầu.
  • endZoneOffset: Độ lệch múi giờ cho thời gian kết thúc.

Các phương pháp tổng hợp được hỗ trợ

Các giá trị tổng hợp sau đây có sẵn cho StepsRecord:

Các giá trị tổng hợp sau đây có sẵn cho StepsCadenceRecord:

Ví dụ về cách sử dụng

Các phần sau đây cho biết cách đọc và ghi dữ liệu StepsRecord.

Ghi dữ liệu về số bước

Ứng dụng của bạn có thể ghi dữ liệu số bước bằng cách chèn các thực thể StepsRecord. Ví dụ sau đây cho thấy cách ghi lại 1.000 bước mà người dùng đã thực hiện:

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

Đọc dữ liệu tổng hợp

Cách phổ biến nhất để đọc dữ liệu về số bước là tổng hợp tổng số bước trong một khoảng thời gian. Ví dụ sau đây cho biết cách đọc tổng số bước của một người dùng trong một phạm vi thời gian nhất định:

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
}

Đọc dữ liệu thô

Ví dụ sau đây cho biết cách đọc dữ liệu thô StepsRecord giữa thời gian bắt đầu và thời gian kết thúc:

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