「健康資料同步」提供「步數」資料類型,可使用 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 月更新推出後,系統會將「健康資料同步」追蹤的步數歸因於合成套件名稱 (SPN),例如 com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e。
先前,內建步驟會歸因於套件名稱 android。2026 年 6 月前記錄的步數資料會保留 android 套件名稱。
SPN 專屬於裝置,且會根據個別應用程式設定範圍,以保護使用者隱私:
- 穩定:目前裝置的 SPN 對應用程式而言是穩定的。
- 應用程式範圍:同一部裝置上的不同應用程式會看到不同的 SPN,用於裝置端步數資料。
查詢裝置上的步數
由於 SPN 具有範圍限制且專屬於特定裝置,因此不得以硬式編碼方式設定 SPN 值。請改用 getCurrentDeviceDataSource() API 擷取目前裝置的 SPN。
雖然裝置端步數計算功能需要 SDK 擴充功能 20 以上版本,但 getCurrentDeviceDataSource() API 適用於搭載 Android 14 (API 級別 34) 的裝置,且 SDK 擴充功能版本為 11 以上。
getCurrentDeviceDataSource() API 尚未在 Health Connect Jetpack 程式庫中提供。下列範例改用 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 在匯總資料中識別的裝置端步驟進行歸因,可以使用裝置中繼資料,例如 model 或 manufacturer (來自 DeviceDataSource),也可以使用「您的手機」等一般標籤來標示裝置端步驟。
以下範例說明如何透過篩選 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.
}
}
裝置端步數計算
- 感應器用量:健康資料同步會使用
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 資訊清單中聲明該組權限。
// 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)
}
}
由於使用者可以隨時授予或撤銷權限,應用程式每次使用權限前都必須先檢查,並處理權限遭撤銷的情況。
步數記錄包含的資訊
每個 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 */ }