健康数据共享 提供了一个 步数 数据类型,用于使用
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 本机跟踪的步数将归因于合成软件包名称 (SPN),例如
com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e。
以前,内置步数归因于软件包名称 android。
2026 年 6 月之前记录的历史步数数据会保留 android 软件包名称。
SPN 是设备专用的,并且按应用进行限定,以保护用户隐私:
- 稳定 :当前设备的 SPN 对于您的应用是稳定的。
- 应用限定 :同一设备上的不同应用会看到不同的设备端步数数据 SPN。
查询设备端步数
由于 SPN 是限定范围的且设备专用,因此您不得 对 SPN 值进行硬编码。请改用 getCurrentDeviceDataSource() API 来检索当前设备的 SPN。
虽然设备端步数统计功能需要 SDK 扩展版本 20 或更高版本,但 getCurrentDeviceDataSource() API 在搭载 SDK 扩展版本 11 或更高版本的 Android 14(API 级别 34)上可用。
Health Connect Jetpack 库中尚不提供 getCurrentDeviceDataSource() API。以下示例改用 Android 框架 API:
import android.content.Context
import android.health.connect.HealthConnectManager
val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)
val deviceDataSource = healthConnectManager?.getCurrentDeviceDataSource()
val currentDeviceSpn = deviceDataSource?.deviceDataOrigin?.packageName
如果您的应用需要读取设备端步数,或者显示按来源应用或设备细分的步数数据,则必须查询 DataOrigin 为 android 或 与设备的 SPN 匹配的记录。如果您的应用显示步数数据的归因,请使用 metadata.device来标识各个记录的来源设备。对于汇总数据中由 SPN 标识的设备端步数,您可以使用 DeviceDataSource 中的设备元数据(例如 model 或 manufacturer)进行归因,也可以使用通用标签(例如“您的手机”)来表示设备端步数。
以下示例展示了如何通过过滤 android 和当前设备 SPN 来读取汇总的设备端步数数据:
import android.content.Context
import android.health.connect.HealthConnectManager
import android.os.Build
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
suspend fun readDeviceStepsByTimeRange(
healthConnectClient: HealthConnectClient,
context: Context,
startTime: Instant,
endTime: Instant
) {
// 1. Check if SDK Extension 11+ is available for getCurrentDeviceDataSource()
val isDataSourceApiAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.U &&
SdkExtensions.getExtensionVersion(Build.VERSION_CODES.U) >= 11
try {
val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)
// 2. Safely fetch the package name only if API is available and data exists
val currentDeviceSpn = if (isDataSourceApiAvailable) {
healthConnectManager?.getCurrentDeviceDataSource()?.deviceDataOrigin?.packageName
} 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.
}
}
设备端步数统计
- 传感器使用情况:健康数据共享 使用
TYPE_STEP_COUNTER传感器,该传感器来自SensorManager。此传感器经过优化,可降低功耗,非常适合持续的后台步数跟踪。 - 数据粒度:为了节省电池电量,步数数据通常会批量处理,并写入健康数据共享数据库,频率不超过每分钟一次。
- 归因:2026 年 6 月之前通过此功能记录的步数
归因于
android软件包名称(位于DataOrigin中)。在此日期之后,这些步数归因于设备专用的 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 清单中声明。
// Create a set of permissions for required data types
val PERMISSIONS =
setOf(
HealthPermission.getReadPermission(StepsRecord::class),
HealthPermission.getWritePermission(StepsRecord::class)
)
使用 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)
}
}
由于用户可以随时授予或撤消权限,因此您的应用需要在每次使用权限之前检查权限,并处理权限丢失的情况。
步数记录中包含的信息
每个 StepsRecord 都包含以下信息:
count:时间间隔内采取的步数,以Long表示。startTime:测量间隔的开始时间。endTime:测量间隔的结束时间。startZoneOffset:开始时间的时区偏移量。endZoneOffset:结束时间的时区偏移量。
支持的聚合
`StepsRecord` 可使用以下聚合值:
`StepsCadenceRecord` 可使用以下聚合值:
用法示例
以下部分展示了如何读取和写入 StepsRecord 数据。
写入步数数据
您的应用可以通过插入 StepsRecord
实例来写入步数数据。以下示例展示了如何记录用户采取的 1000 步:
val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(startTime) val stepsRecord = StepsRecord( count = 120, startTime = startTime, endTime = endTime, startZoneOffset = zoneOffset, endZoneOffset = zoneOffset, metadata = Metadata( device = Device(type = Device.TYPE_WATCH), recordingMethod = Metadata.RECORDING_METHOD_AUTOMATICALLY_RECORDED ) ) 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 */ }