Adımları izleme

Health Connect, StepsRecord kullanılarak adım sayılarının kaydedilmesi için adım veri türünü sağlar. Adımlar, sağlık ve fitness takibinde temel bir ölçümdür.

Mobil cihazdaki adımları okuma

Android 14 (API düzeyi 34) ve SDK Uzantısı sürüm 20 veya sonraki sürümlerde Health Connect, cihaz üzerinde adım sayma özelliği sunar. Herhangi bir uygulamaya READ_STEPS izni verildiyse Health Connect, Android destekli cihazdaki adımları yakalamaya başlar ve kullanıcılar, adım verilerinin Health Connect Adımlar girişlerine otomatik olarak eklendiğini görür.

Cihaz üzerinde adım sayma özelliğinin kullanılabilir olup olmadığını kontrol etmek için cihazda Android 14 (API düzeyi 34) sürümünün yüklü olduğundan ve SDK uzantısı sürümünün en az 20 olduğundan emin olun:

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

Uygulamanız, aggregate kullanarak toplu adım sayılarını okuyor ve DataOrigin ile filtrelemiyorsa cihaz üzerindeki adımlar otomatik olarak toplama dahil edilir ve Haziran 2026 güncellemesi için herhangi bir değişiklik yapılması gerekmez.

Cihaz üzerinde yapılan adımlar için ilişkilendirme değişikliği

Haziran 2026 güncellemesinden itibaren, Health Connect tarafından yerel olarak izlenen adımlar Sentetik Paket Adı (SPN) ile ilişkilendirilecek. Örneğin, com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e.

Daha önce yerleşik adımlar android paket adıyla ilişkilendiriliyordu. Haziran 2026'dan önce kaydedilen geçmiş adım verileri android paket adını korur.

SPN'ler cihaza özeldir ve kullanıcı gizliliğini korumak için uygulama bazında kapsamlandırılır:

  • Kararlı: Mevcut cihazın SPN'si uygulamanız için kararlıdır.
  • Uygulama Kapsamlı: Aynı cihazdaki farklı uygulamalar, cihaz üzerindeki adım verileri için farklı SPN'ler görür.

Cihaz üzerinde adımlar için sorgu

SPN'ler kapsamlı ve cihaza özel olduğundan SPN değerlerini kesinlikle sabit kodlamamalısınız. Bunun yerine, mevcut cihazın SPN'sini almak için getCurrentDeviceDataSource API'yi kullanın.

Cihaz üzerinde adım sayma özelliği için SDK uzantısı sürümü 20 veya sonraki sürümler gerekirken getCurrentDeviceDataSource() API, Android 14'te (API düzeyi 34) SDK uzantısı sürümü 22 veya sonraki sürümlerle kullanılabilir. Bu API'yi kullanmak için modül düzeyindeki build.gradle.kts veya build.gradle dosyanızda compileSdkExtension değerini 22 veya daha yüksek bir değere ayarlayın:

Kotlin

android {
    compileSdk = 35
    compileSdkExtension = 22
}

Modern

android {
    compileSdk 35
    compileSdkExtension 22
}

getCurrentDeviceDataSource() API'si henüz Health Connect Jetpack kitaplığında kullanılamamaktadır. Aşağıdaki örneklerde, Executor ve OutcomeReceiver geri çağırma işlevinin gerekli olduğu Android framework API'si kullanılmaktadır:

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

Uygulamanızın cihaz üzerindeki adımları okuması gerekiyorsa veya adım verilerini kaynak uygulamaya ya da cihaza göre ayrılmış şekilde gösteriyorsa DataOrigin değerinin android olduğu veya cihazın SPN'siyle eşleştiği kayıtları sorgulamanız gerekir. Uygulamanız adım verileri için ilişkilendirme gösteriyorsa tek tek kayıtların kaynak cihazını belirlemek için metadata.device kullanın. Toplu verilerde SPN ile tanımlanan cihaz üzerinde adımlar için ilişkilendirme amacıyla DeviceDataSource model veya manufacturer gibi cihaz meta verilerini kullanabilir ya da cihaz üzerinde adımlar için "Telefonunuz" gibi genel bir etiket kullanabilirsiniz.

Aşağıdaki örnekte, hem android hem de mevcut cihaz SPN'si için filtreleme yapılarak cihaz üzerinde toplanan adım sayısı verilerinin nasıl okunacağı gösterilmektedir:

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

Cihaz Üzerinde Adım Sayma

  • Sensör Kullanımı: Health Connect, SensorManager uygulamasındaki TYPE_STEP_COUNTER sensörünü kullanır. Bu sensör, düşük güç tüketimi için optimize edilmiştir. Bu nedenle, arka planda sürekli adım takibi için idealdir.
  • Veri ayrıntı düzeyi: Pil ömrünü korumak için adım verileri genellikle gruplandırılır ve Health Connect veritabanına dakikada en fazla bir kez yazılır.
  • İlişkilendirme: Bu özellik tarafından Haziran 2026'dan önce kaydedilen adımlar, android paket adıyla DataOrigin içinde ilişkilendirilir. Bu tarihten sonra, cihaza özel bir SPN ile ilişkilendirilirler. Cihaz üzerinde yapılan adımlarla ilgili ilişkilendirme değişikliği başlıklı makaleyi inceleyin.
  • Etkinleştirme: Cihazdaki adım sayma mekanizması yalnızca cihazda bulunan en az bir uygulamaya Health Connect'te READ_STEPS izni verildiğinde etkin olur.

Health Connect'in kullanılabilirliğini kontrol etme

Uygulamanız, Health Connect'i kullanmaya çalışmadan önce kullanıcının cihazında Health Connect'in kullanılabilir olduğunu doğrulamalıdır. Health Connect, bazı cihazlara önceden yüklenmemiş veya devre dışı bırakılmış olabilir. HealthConnectClient.getSdkStatus() yöntemini kullanarak kullanılabilirliği kontrol edebilirsiniz.

Health Connect'in kullanılabilirliğini kontrol etme

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() tarafından döndürülen duruma bağlı olarak, gerekirse kullanıcıyı Google Play Store'dan Health Connect'i yüklemeye veya güncellemeye yönlendirebilirsiniz.

Gerekli izinler

Adımlara erişim aşağıdaki izinlerle korunur:

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

Uygulamanıza adım sayma özelliği eklemek için öncelikle Steps veri türüyle ilgili izin isteğinde bulunun.

Adım yazabilmek için beyan etmeniz gereken izin aşağıda verilmiştir:

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

Adımları okumak için aşağıdaki izinleri istemeniz gerekir:

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

Kullanıcıdan izin isteme

İstemci örneği oluşturduktan sonra uygulamanızın kullanıcıdan izin istemesi gerekir. Kullanıcılar, izinleri diledikleri zaman verebilmeli veya reddedebilmelidir. Bunu yapmak için gerekli veri türleri için bir izin grubu oluşturun. Gruptaki izinlerin önce Android manifestinizde beyan edildiğinden emin olun.

val permissions =
    setOf(
        HealthPermission.getReadPermission(StepsRecord::class),
        HealthPermission.getWritePermission(StepsRecord::class)
    )
Uygulamanıza gerekli izinlerin verilip verilmediğini görmek için getGrantedPermissions kullanın. Aksi takdirde, bu izinleri istemek için createRequestPermissionResultContract seçeneğini kullanın. Bu işlem, Health Connect izinleri ekranını gösterir.
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.") }
    }
}
Kullanıcılar izinleri istedikleri zaman verebilir veya iptal edebilir. Bu nedenle, uygulamanız izinleri kullanmadan önce her seferinde kontrol etmeli ve izinlerin kaybedildiği senaryoları ele almalıdır.

Adımlar kaydında yer alan bilgiler

Her StepsRecord aşağıdaki bilgileri içerir:

  • count: Zaman aralığında atılan adım sayısıdır (Long).
  • startTime: Ölçüm aralığının başlangıç zamanı.
  • endTime: Ölçüm aralığının bitiş zamanı.
  • startZoneOffset: Başlangıç zamanının saat dilimi.
  • endZoneOffset: Bitiş zamanının saat dilimi.

Desteklenen toplamalar

Aşağıdaki toplama değerleri StepsRecord için kullanılabilir:

Aşağıdaki toplama değerleri StepsCadenceRecord için kullanılabilir:

Örnek kullanım

Aşağıdaki bölümlerde StepsRecord verilerinin nasıl okunacağı ve yazılacağı gösterilmektedir.

Adım verilerini yazma

Uygulamanız, StepsRecord örnekleri ekleyerek adım sayısı verilerini yazabilir. Aşağıdaki örnekte, bir kullanıcının attığı 1.000 adımın nasıl kaydedileceği gösterilmektedir:

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

Birleştirilmiş verileri okuma

Adım verilerini okumanın en yaygın yolu, belirli bir dönemdeki toplam adımları toplamaktır. Aşağıdaki örnekte, belirli bir zaman aralığında bir kullanıcının toplam adım sayısının nasıl okunacağı gösterilmektedir:

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
}

Ham verileri okuma

Aşağıdaki örnekte, başlangıç ve bitiş zamanı arasındaki ham StepsRecord verilerinin nasıl okunacağı gösterilmektedir:

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