مراحل پیگیری

‫Health Connect نوع داده قدم‌ها را برای ثبت تعداد قدم‌ها بااستفاده از StepsRecord ارائه می‌دهد. تعداد قدم‌ها یک اندازه‌گیری اساسی در ردیابی سلامت و تناسب اندام است.

خواندن داده‌های قدم تلفن همراه

با Android 14 (سطح API 34) و «نسخه افزونه کیت توسعه نرم‌افزار» ۲۰ یا بالاتر، ‫Health Connect شمارش قدم‌ها در دستگاه را ارائه می‌دهد. اگر به برنامه‌ای اجازه READ_STEPS داده شده باشد، Health Connect شروع به ضبط تعداد قدم‌ها از دستگاه Android می‌کند و کاربران داده‌های تعداد قدم‌ها را به‌طور خودکار در ورودی‌های قدم‌ها در Health Connect می‌بینند.

برای بررسی اینکه آیا شمارش گام درون‌دستگاهی دردسترس است، مطمئن شوید دستگاه از Android 14 (سطح API 34) استفاده می‌کند و حداقل نسخه افزونه کیت توسعه نرم‌افزار آن ۲۰ است:

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

اگر برنامه شما تعداد گام‌های تجمیعی را بااستفاده از aggregate می‌خواند و براساس DataOrigin فیلتر نمی‌کند، گام‌های درون‌دستگاهی به‌طور خودکار در مجموع گنجانده می‌شود و برای به‌روزرسانی ژوئن ۲۰۲۶ نیازی به تغییر نیست.

تغییر اسنادی برای مراحل درون‌دستگاهی

از به‌روزرسانی ژوئن ۲۰۲۶، تعداد قدم‌هایی که Health Connect به‌صورت بومی ردیابی می‌کند به نام بسته مصنوعی (SPN)، مانند com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e، نسبت داده می‌شود.

قبلاً، مراحل داخلی به نام بسته android نسبت داده می‌شد. داده‌های گام سابقه که قبل‌از ژوئن ۲۰۲۶ ضبط شده است نام بسته android را حفظ می‌کند.

«نام‌های سرویس اصلی» مختص دستگاه هستند و براساس هر برنامه محدود می‌شوند تا از حریم خصوصی کاربر محافظت شود:

  • پایدار: SPN برای دستگاه فعلی برای برنامه شما پایدار است.
  • محدوده برنامه: برنامه‌های مختلف در یک دستگاه، «نام‌های اصلی سرویس» متفاوتی برای داده‌های گام درون‌دستگاهی می‌بینند.

پُرسمان برای مراحل درون‌دستگاهی

ازآنجایی‌که SPNها محدود و مختص دستگاه هستند، نباید مقادیر SPN را کدبندی سخت کنید. به‌جای آن، از getCurrentDeviceDataSource API برای بازیابی نام سرویس اصلی برای دستگاه فعلی استفاده کنید.

درحالی‌که شمارش گام درون‌دستگاهی به نسخه ۲۰ یا بالاتر افزونه کیت توسعه نرم‌افزار نیاز دارد، میانای برنامه کاربردی getCurrentDeviceDataSource() در Android 14 (سطح ای‌پی‌آی ۳۴) با نسخه ۲۲ یا بالاتر افزونه کیت توسعه نرم‌افزار دردسترس است. برای استفاده از این «میانای برنامه‌سازی کاربردی»، compileSdkExtension را در فایل build.gradle.kts یا build.gradle سطح واحد به 22 یا بالاتر تنظیم کنید:

کاتلین

android {
    compileSdk = 35
    compileSdkExtension = 22
}

شیک

android {
    compileSdk 35
    compileSdkExtension 22
}

میانای برنامه‌سازی کاربردی getCurrentDeviceDataSource() هنوز در کتابخانه Health Connect Jetpack دردسترس نیست. مثال‌های زیر از میانای برنامه‌سازی کاربردی چارچوب Android استفاده می‌کنند که به Executor و 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
        }
    }
)

اگر برنامه شما نیاز دارد تعداد گام‌های روی دستگاه را بخواند، یا اگر داده‌های گام را براساس برنامه یا دستگاه منبع تفکیک‌شده نمایش می‌دهد، باید برای گزارش‌هایی که در آن‌ها DataOrigin android یا با SPN دستگاه مطابقت دارد پُرسمان کنید. اگر برنامه شما اسناد استنادی برای داده‌های گام نشان می‌دهد، از metadata.device برای شناسایی دستگاه منبع برای سوابق فردی استفاده کنید. برای مراحل درون‌دستگاهی که با SPN در داده‌های تجمیعی شناسایی شده‌اند، می‌توانید از فراداده‌های دستگاه مثل model یا manufacturer از DeviceDataSource برای اسناد استفاده کنید، یا از برچسب عمومی مثل «تلفن شما» برای مراحل درون‌دستگاهی استفاده کنید.

مثال زیر نحوه خواندن داده‌های تعداد گام‌های انبوهشی درون‌دستگاهی را با فیلتر کردن هم android و هم SPN دستگاه فعلی نشان می‌دهد:

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

شمارش گام درون‌دستگاهی

  • استفاده از حسگر: Health Connect از حسگر TYPE_STEP_COUNTER SensorManager استفاده می‌کند. این حسگر برای مصرف کم انرژی بهینه‌سازی شده است، که آن را برای ردیابی گام‌های پس‌زمینه‌ای مداوم ایده‌آل می‌کند.
  • جزئیات داده: برای حفظ عمر باتری، داده‌های قدم معمولاً دسته‌ای می‌شوند و حداکثر یک بار در دقیقه در پایگاه داده Health Connect نوشته می‌شوند.
  • اسناد: گام‌هایی که این ویژگی قبل‌از ژوئن ۲۰۲۶ ثبت کرده است به نام بسته android در DataOrigin نسبت داده می‌شود. پس‌از این تاریخ، آن‌ها به SPN مختص دستگاه نسبت داده می‌شوند. به تغییر اسنادی برای مراحل درون‌دستگاهی مراجعه کنید.
  • فعال‌سازی: سازوکار شمارش قدم درون‌دستگاهی فقط زمانی فعال است که حداقل یک برنامه در دستگاه اجازه READ_STEPS را در Health Connect دریافت کرده باشد.

بررسی دردسترس بودن Health Connect

برنامه شما باید قبل‌از تلاش برای استفاده از Health Connect، بررسی کند که آیا Health Connect در دستگاه کاربر دردسترس است یا نه. ‫Health Connect ممکن است در همه دستگاه‌ها پیش‌نصب نشده باشد یا ممکن است غیرفعال باشد. بااستفاده از روش HealthConnectClient.getSdkStatus() می‌توانید دردسترس بودن را بررسی کنید.

نحوه بررسی دردسترس بودن Health Connect

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_STEPS
  • android.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 برای درخواست این اجازه‌ها استفاده کنید. با این کار، صفحه اجازه‌های 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.") }
    }
}
ازآنجایی‌که کاربران می‌توانند در هر زمانی اجازه‌ها را اعطا یا لغو کنند، برنامه شما باید هر بار قبل‌از استفاده از اجازه‌ها، آن‌ها را بررسی کند و سناریوهایی را که اجازه ازدست می‌رود مدیریت کند.

اطلاعات موجود در سابقه «گام‌ها»

هر StepsRecord حاوی اطلاعات زیر است:

  • count: تعداد قدم‌های برداشته‌شده در بازه زمانی، به‌صورت Long.
  • startTime: زمان شروع فاصله اندازه‌گیری.
  • endTime: زمان پایان فاصله اندازه‌گیری.
  • startZoneOffset: فاصله زمانی منطقه زمانی برای زمان شروع.
  • endZoneOffset: فاصله زمانی منطقه زمانی برای زمان پایان.

تجمع‌های پشتیبانی‌شده

مقادیر تجمیعی زیر برای StepsRecord دردسترس است:

مقادیر تجمیعی زیر برای StepsCadenceRecord دردسترس است:

نمونه استفاده

بخش‌های زیر نحوه خواندن و نوشتن داده‌های StepsRecord را نشان می‌دهد.

نوشتن داده‌های تعداد قدم‌ها

برنامه شما می‌تواند با درج نمونه‌های StepsRecord ، داده‌های تعداد گام را بنویسد. مثال زیر نحوه ثبت ۱۰۰۰ قدم برداشته‌شده توسط کاربر را نشان می‌دهد:

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

خواندن داده‌های تجمیعی

رایج‌ترین روش برای خواندن داده‌های تعداد قدم، تجمیع تعداد کل قدم‌ها در یک دوره زمانی است. مثال زیر نحوه خواندن تعداد کل گام‌های کاربر در محدوده زمانی معینی را نشان می‌دهد:

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 */
}