مراحل را دنبال کنید

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

مراحل موبایل را بخوانید

با اندروید ۱۴ (سطح API ۳۴) و افزونه SDK نسخه ۲۰ یا بالاتر، Health Connect امکان شمارش گام‌ها را روی دستگاه فراهم می‌کند. اگر به هر برنامه‌ای مجوز READ_STEPS اعطا شده باشد، Health Connect شروع به ثبت گام‌ها از دستگاه مبتنی بر اندروید می‌کند و کاربران می‌توانند داده‌های گام‌ها را که به طور خودکار به ورودی‌های Health Connect Steps اضافه می‌شوند، مشاهده کنند.

برای بررسی اینکه آیا شمارش گام روی دستگاه در دسترس است، تأیید کنید که دستگاه از اندروید ۱۴ (سطح API ۳۴) استفاده می‌کند و حداقل نسخه ۲۰ افزونه SDK را دارد:

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 های متفاوتی را برای داده‌های مرحله‌ای روی دستگاه مشاهده می‌کنند.

پرس و جو برای مراحل روی دستگاه

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

در حالی که شمارش گام روی دستگاه به افزونه SDK نسخه 20 یا بالاتر نیاز دارد، API getCurrentDeviceDataSource() در اندروید 14 (سطح API 34) با افزونه SDK نسخه 11 یا بالاتر در دسترس است.

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

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

  • کاربرد حسگر : 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() ، می‌توانید در صورت لزوم کاربر را برای نصب یا به‌روزرسانی Health Connect از فروشگاه 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>

درخواست مجوز از کاربر

پس از ایجاد یک نمونه کلاینت، برنامه شما باید از کاربر درخواست مجوز کند. کاربران باید بتوانند در هر زمانی مجوزها را اعطا یا رد کنند.

برای انجام این کار، مجموعه‌ای از مجوزها را برای انواع داده‌های مورد نیاز ایجاد کنید. مطمئن شوید که مجوزهای موجود در مجموعه ابتدا در مانیفست اندروید شما تعریف شده‌اند.

// 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 داده‌های شمارش گام را بنویسد. مثال زیر نحوه ثبت ۱۰۰۰ گام برداشته شده توسط یک کاربر را نشان می‌دهد:

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