「健康資料同步」提供「步數」資料類型,可使用 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 識別的裝置端步驟歸因,可以使用裝置中繼資料,例如 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.
}
}
裝置端步數計算
- 感應器用量:健康資料同步會使用
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 資訊清單中聲明該組權限。
val permissions = setOf( HealthPermission.getReadPermission(StepsRecord::class), HealthPermission.getWritePermission(StepsRecord::class) )
getGrantedPermissions 查看應用程式是否已獲授予必要權限。如果沒有,請使用 createRequestPermissionResultContract 要求這些權限。系統會顯示「健康資料同步」權限畫面。
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.") } } }
步數記錄包含的資訊
每個 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 */ }