تتبُّع الخطوات

يوفّر Health Connect نوع بيانات الخطوات لتسجيل عدد الخطوات باستخدام StepsRecord. الخطوات هي مقياس أساسي لتتبُّع الصحة واللياقة البدنية.

قراءة بيانات الخطوات على الأجهزة الجوّالة

في نظام التشغيل Android 14 (المستوى 34 لواجهة برمجة التطبيقات) والإصدار 20 أو الإصدارات الأحدث من حزمة SDK Extension، يوفّر تطبيق Health Connect ميزة احتساب الخطوات على الجهاز. إذا تم منح أي تطبيق إذن READ_STEPS، سيبدأ تطبيق Health Connect في تسجيل الخطوات من جهاز Android، وسيلاحظ المستخدمون أنّه تتم إضافة بيانات الخطوات تلقائيًا إلى إدخالات الخطوات في Health Connect.

للتأكّد من توفّر ميزة احتساب الخطوات على الجهاز فقط، تحقَّق من أنّ الجهاز يعمل بالإصدار Android 14 (مستوى واجهة برمجة التطبيقات 34) ويتضمّن على الأقل الإصدار 20 من حزمة تطوير البرامج (SDK):

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

إذا كان تطبيقك يقرأ عدد الخطوات المجمّع باستخدام aggregate ولا يفلتر حسب DataOrigin، سيتم تلقائيًا تضمين الخطوات المسجّلة على الجهاز فقط في الإجمالي، ولن تحتاج إلى إجراء أي تغييرات في تحديث يونيو 2026.

تغيير تحديد المصدر للخطوات التي يتم تتبّعها على الجهاز فقط

اعتبارًا من تحديث يونيو 2026، سيتم إسناد الخطوات التي يتتبّعها تطبيق Health Connect تلقائيًا إلى اسم حزمة اصطناعي (SPN)، مثل com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e.

في السابق، كانت الخطوات المضمّنة تُنسَب إلى اسم الحزمة android. تحتفظ بيانات الخطوات السابقة المسجّلة قبل يونيو 2026 باسم الحزمة android.

تكون أرقام التعريف الخاصة بموفّر الشبكة مخصّصة للجهاز ويتم تحديد نطاقها على أساس كل تطبيق على حدة لحماية خصوصية المستخدم:

  • مستقر: رقم تعريف الشبكة الخاصة (SPN) للجهاز الحالي مستقر لتطبيقك.
  • على مستوى التطبيق: تعرض التطبيقات المختلفة على الجهاز نفسه أرقام تعريف خدمة مختلفة لبيانات الخطوات على الجهاز فقط.

طلب خطوات على الجهاز فقط

بما أنّ أسماء SPN محدودة النطاق وخاصة بالجهاز، يجب عدم ترميز قيم أسماء SPN بشكل ثابت. بدلاً من ذلك، استخدِم واجهة برمجة التطبيقات getCurrentDeviceDataSource لاسترداد اسم SPN للجهاز الحالي.

بينما يتطلّب احتساب الخطوات على الجهاز فقط الإصدار 20 أو إصدارًا أحدث من حزمة تطوير البرامج (SDK)، تتوفّر واجهة برمجة التطبيقات getCurrentDeviceDataSource() على نظام التشغيل Android 14 (المستوى 34 من واجهة برمجة التطبيقات) مع الإصدار 22 أو إصدار أحدث من حزمة تطوير البرامج (SDK). لاستخدام واجهة برمجة التطبيقات هذه، اضبط قيمة compileSdkExtension على 22 أو أعلى في ملف build.gradle.kts أو ملف build.gradle على مستوى الوحدة:

Kotlin

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 بمعدّل لا يزيد عن مرة واحدة في الدقيقة.
  • تحديد المصدر: إنّ الخطوات التي تسجّلها هذه الميزة قبل يونيو 2026 يتم تحديد مصدرها على أنّه اسم الحزمة android في DataOrigin. بعد هذا التاريخ، يتم تحديد مصدرها على أنّه شبكة شركاء معيّنة خاصة بالجهاز. اطّلِع على تغيير تحديد المصدر للخطوات التي يتم تنفيذها على الجهاز فقط.
  • التفعيل: لا تكون آلية احتساب الخطوات على الجهاز نشطة إلا عندما يمنح تطبيق واحد على الأقل على الجهاز إذن 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>

طلب الأذونات من المستخدم

بعد إنشاء مثيل العميل، يحتاج تطبيقك إلى طلب الأذونات من المستخدم. يجب السماح للمستخدمين بمنح الأذونات أو رفضها في أي وقت. لإجراء ذلك، أنشئ مجموعة من الأذونات لأنواع البيانات المطلوبة. تأكَّد أولاً من تضمين الأذونات في المجموعة في بيان 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. يوضّح المثال التالي كيفية تسجيل 1,000 خطوة اتّخذها أحد المستخدمين:

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