واجهة برمجة التطبيقات للتسجيل على الأجهزة الجوّالة

تتيح واجهة برمجة التطبيقات للتسجيل على الجوّال لتطبيقك تسجيل الخطوات من جهاز جوّال بطريقة فعّالة من حيث استهلاك البطارية. ولا تشمل واجهة برمجة التطبيقات هذه حساب، ما يعني أنّها لا تتطلّب حسابًا على Google لاستخدام الخدمة ويتم تخزين البيانات على الجهاز.

يوضح لك هذا الدليل كيفية استخدام واجهة برمجة التطبيقات للتسجيل على الجوّال في تجارب الصحة واللياقة البدنية.

تفاصيل بارزة

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

  • بعد بدء الاشتراك في التسجيل أو تجديده، ستتوفر البيانات منذ آخر اشتراك لمدة تصل إلى 10 أيام.
  • لا تتوفر البيانات إلا عند وجود اشتراك نشط. في حال إزالة اشتراك من خلال طلب الرقم unsubscribe، سيتعذّر الوصول إلى بيانات الخطوة التي تم جمعها.

أنواع البيانات

يمكن لواجهة برمجة تطبيقات التسجيل على الأجهزة الجوّالة تسجيل أنواع البيانات التالية:

البدء

للبدء، أضِف الاعتمادية التالية في ملف build.gradle:

لغة Kotlin DSL

plugin {
  id("com.android.application")
}

...

dependencies {
  implementation("com.google.android.gms:play-services-fitness:21.2.0")
}

DSL رائعة

apply plugin: 'com.android.application'

...

dependencies {
  implementation 'com.google.android.gms:play-services-fitness:21.2.0'
}

طلب الأذونات

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

  • android.permission.ACTIVITY_RECOGNITION

التحقق من إصدار "خدمات Play"

لاستخدام واجهة برمجة تطبيقات التسجيل على الجهاز الجوّال، يجب أن يتم تحديث خدمات Google Play لدى المستخدم إلى LOCAL_RECORDING_CLIENT_MIN_VERSION_CODE. يمكنك التحقّق من ذلك باستخدام طريقة isGooglePlayServicesAvailable:

val hasMinPlayServices = isGooglePlayServicesAvailable(context, LocalRecordingClient.LOCAL_RECORDING_CLIENT_MIN_VERSION_CODE)

if(hasMinPlayServices != ConnectionResult.SUCCESS) {
  // Prompt user to update their device's Google Play services app and return
}

// Continue with Recording API functions

بخلاف ذلك، إذا كان إصدار "خدمات Google Play" للمستخدم منخفضًا جدًا، يعرض النظام استثناء ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED.

الاشتراك في خدمة "بيانات اللياقة البدنية"

لطلب جمع البيانات في الخلفية عن الخطوات أو المسافة أو السعرات الحرارية، استخدِم طريقة subscribe كما هو موضّح في مقتطف الرمز التالي:

val localRecordingClient = FitnessLocal.getLocalRecordingClient(this)
// Subscribe to steps data
localRecordingClient.subscribe(LocalDataType.TYPE_STEP_COUNT_DELTA)
  .addOnSuccessListener {
    Log.i(TAG, "Successfully subscribed!")
  }
  .addOnFailureListener { e ->
    Log.w(TAG, "There was a problem subscribing.", e)
  }

قراءة بيانات اللياقة البدنية ومعالجتها

بعد الاشتراك، اطلب البيانات باستخدام الطريقة readData. بعد ذلك، يمكنك الحصول على LocalDataPoints من LocalDataSet الناتج عن طريق إنشاء LocalDataReadRequest، كما هو موضّح في مقتطف الرمز التالي:

val endTime = LocalDateTime.now().atZone(ZoneId.systemDefault())
val startTime = endTime.minusWeeks(1)
val readRequest =
  LocalDataReadRequest.Builder()
    // The data request can specify multiple data types to return,
    // effectively combining multiple data queries into one call.
    // This example demonstrates aggregating only one data type.
    .aggregate(LocalDataType.TYPE_STEP_COUNT_DELTA)
    // Analogous to a "Group By" in SQL, defines how data should be
    // aggregated. bucketByTime allows bucketing by time span.
    .bucketByTime(1, TimeUnit.DAYS)
    .setTimeRange(startTime.toEpochSecond(), endTime.toEpochSecond(), TimeUnit.SECONDS)
    .build()

  localRecordingClient.readData(readRequest).addOnSuccessListener { response ->
    // The aggregate query puts datasets into buckets, so flatten into a
    // single list of datasets.
    for (dataSet in response.buckets.flatMap { it.dataSets }) {
      dumpDataSet(dataSet)
    }
  }
  .addOnFailureListener { e ->
    Log.w(TAG,"There was an error reading data", e)
  }

fun dumpDataSet(dataSet: LocalDataSet) {
  Log.i(TAG, "Data returned for Data type: ${dataSet.dataType.name}")
  for (dp in dataSet.dataPoints) {
    Log.i(TAG,"Data point:")
    Log.i(TAG,"\tType: ${dp.dataType.name}")
    Log.i(TAG,"\tStart: ${dp.getStartTime(TimeUnit.HOURS)}")
    Log.i(TAG,"\tEnd: ${dp.getEndTime(TimeUnit.HOURS)}")
    for (field in dp.dataType.fields) {
      Log.i(TAG,"\tLocalField: ${field.name.toString()} LocalValue: ${dp.getValue(field)}")
    }
  }
}

تعدّل "LocalRecordingClient" مجموعة البيانات التي تجمعها باستمرار. يمكنك استخدام readData لسحب أحدث الأرقام في أي وقت.

وتجدُر الإشارة إلى أنّ LocalRecordingClient يحفظ بيانات لمدّة تصل إلى 10 أيام. للحد من خطر فقدان البيانات، يمكنك استخدام WorkManager لجمع البيانات بشكل دوري في الخلفية.

إلغاء الاشتراك في بيانات اللياقة البدنية

لتوفير بعض الموارد، يجب التأكد من إلغاء الاشتراك في عملية جمع بيانات جهاز الاستشعار عندما لا يحتاج تطبيقك إليها. لإلغاء الاشتراك، استخدِم الطريقة unsubscribe:

val localRecordingClient = FitnessLocal.getLocalRecordingClient(this)
// Unsubscribe from steps data
localRecordingClient.unsubscribe(LocalDataType.TYPE_STEP_COUNT_DELTA)
  .addOnSuccessListener {
    Log.i(TAG, "Successfully unsubscribed!")
  }
  .addOnFailureListener { e ->
    Log.w(TAG, "There was a problem unsubscribing.", e)
  }