يتوافق هذا الدليل مع الإصدار 1.1.0-alpha12 من Health Connect.
تتضمّن معظم التطبيقات التي تتكامل مع Health Connect مخزن بيانات خاصًا بها يعمل كمصدر موثوق. يوفّر Health Connect طرقًا لمزامنة تطبيقك.
استنادًا إلى بنية تطبيقك، قد تتضمّن عملية المزامنة بعض الإجراءات التالية أو جميعها:
- إدخال بيانات جديدة أو معدَّلة من مستودع بيانات تطبيقك إلى Health Connect
- استرداد تغييرات البيانات من Health Connect إلى مستودع بيانات تطبيقك
- حذف البيانات من Health Connect عند حذفها في مستودع بيانات تطبيقك
في كلتا الحالتين، تأكَّد من أنّ عملية المزامنة تحافظ على توافق كلّ من Health Connect ومخزن بيانات تطبيقك.
إرسال البيانات إلى Health Connect
الجزء الأول من عملية المزامنة هو نقل البيانات من مستودع بيانات تطبيقك إلى مستودع بيانات Health Connect.
إعداد بياناتك
عادةً ما تتضمّن السجلات في مستودع بيانات تطبيقك التفاصيل التالية:
- مفتاح فريد، مثل
UUID - إصدار أو طابع زمني
عند مزامنة البيانات مع Health Connect، يجب تحديد البيانات التي تم إدراجها أو تعديلها أو حذفها منذ آخر عملية مزامنة وإرسالها فقط.
كتابة البيانات في Health Connect
لإدخال البيانات في Health Connect، اتّبِع الخطوات التالية:
- الحصول على قائمة بالإدخالات الجديدة أو المعدَّلة أو المحذوفة من مستودع بيانات تطبيقك
- لكل إدخال، أنشئ عنصر
Recordمناسبًا لنوع البيانات هذا. على سبيل المثال، أنشئ عنصرWeightRecordللبيانات المتعلقة بالوزن. حدِّد عنصر
Metadataمع كلRecord. ويشمل ذلكclientRecordId، وهو معرّف من مستودع بيانات تطبيقك يمكنك استخدامه لتحديد السجلّ بشكل فريد. يمكنك استخدام مفتاحك الفريد الحالي لهذا الغرض. إذا كانت بياناتك تتضمّن إصدارات، يجب أيضًا تقديمclientRecordVersionيتوافق مع نظام تحديد الإصدارات المستخدَم في بياناتك. إذا لم يكن الإصدار متاحًا، يمكنك استخدام القيمةLongللطابع الزمني الحالي كبديل.val recordVersion = 0L // Specify as needed // The clientRecordId is an ID that you choose for your record. This // is often the same ID you use in your app's datastore. val clientRecordId = "<your-record-id>" val record = WeightRecord( metadata = Metadata.activelyRecorded( clientRecordId = clientRecordId, clientRecordVersion = recordVersion, device = Device(type = Device.TYPE_SCALE) ), weight = Mass.kilograms(62.0), time = Instant.now(), zoneOffset = ZoneOffset.UTC, ) healthConnectClient.insertRecords(listOf()(record))إضافة/تعديل البيانات في Health Connect باستخدام
insertRecordsتعني عملية إدراج البيانات وتعديلها أنّه سيتم استبدال أي بيانات حالية في Health Connect طالما أنّ قيمclientRecordIdمتوفّرة في مستودع بيانات Health Connect، وأنّ قيمةclientRecordVersionأعلى من القيمة الحالية. وفي حال عدم توفّرها، تتم كتابة البيانات التي تم إدراجها أو تعديلها كبيانات جديدة.healthConnectClient.insertRecords(arrayListOf(record))
للتعرّف على الاعتبارات العملية المتعلقة بتوفير البيانات، يمكنك الاطّلاع على أفضل الممارسات المتعلّقة بكتابة البيانات.
تخزين أرقام تعريف Health Connect
إذا كان تطبيقك يقرأ البيانات أيضًا من Health Connect، خزِّن id
في Health Connect للسجلات بعد إدراجها أو تعديلها. تحتاج إلى id لمعالجة عمليات الحذف عند سحب تغييرات البيانات من Health Connect.
تعرض الدالة insertRecords InsertRecordsResponse يحتوي على قائمة بقيم id.
استخدِم الردّ للحصول على معرّفات السجلات وتخزينها.
val response = healthConnectClient.insertRecords(arrayListOf(record))
for (recordId in response.recordIdsList) {
// Store recordId to your app's datastore
}
سحب البيانات من Health Connect
الجزء الثاني من عملية المزامنة هو استرداد أي تغييرات في البيانات من Health Connect إلى مستودع بيانات تطبيقك. يمكن أن تشمل تغييرات البيانات التعديلات وعمليات الحذف.
الحصول على رمز مميّز للتغييرات
للحصول على قائمة بالتغييرات التي يجب استردادها من Health Connect، يجب أن يحتفظ تطبيقك برموز التغييرات المميزة. يمكنك استخدامها عند طلب التغييرات لعرض قائمة بالتغييرات التي تم إجراؤها على البيانات ورمز مميز جديد للتغييرات لاستخدامه في المرة التالية.
للحصول على رمز مميّز للتغييرات، اتّصِل بـ getChangesToken وقدِّم أنواع البيانات المطلوبة.
val changesToken = healthConnectClient.getChangesToken(
ChangesTokenRequest(recordTypes = setOf(WeightRecord::class))
)
التحقّق من التغييرات في البيانات
بعد الحصول على رمز مميّز للتغييرات، استخدِمه للحصول على جميع التغييرات. ننصحك بإنشاء حلقة لتصفّح جميع التغييرات والتحقّق مما إذا كانت هناك تغييرات متاحة في البيانات. في ما يلي الخطوات التي يجب اتّباعها:
- اتّصِل بـ
getChangesباستخدام الرمز المميز للحصول على قائمة بالتغييرات. - تحقَّق من نوع التغيير، سواء كان
UpsertionChangeأوDeletionChange، ونفِّذ العمليات اللازمة.- بالنسبة إلى
UpsertionChange، يجب ألا يتم استيراد التغييرات التي لم يتم إجراؤها من خلال تطبيق الاتصال، وذلك للتأكّد من عدم إعادة استيراد البيانات.
- بالنسبة إلى
- عيِّن الرمز المميّز التالي للتغييرات كرمز مميّز جديد.
- كرِّر الخطوات من 1 إلى 3 إلى أن لا يتبقى أي تغييرات.
- تخزين الرمز المميز التالي وحجزه لعملية استيراد مستقبلية
suspend fun processChanges(token: String): String {
var nextChangesToken = token
do {
val response = healthConnectClient.getChanges(nextChangesToken)
response.changes.forEach { change ->
when (change) {
is UpsertionChange ->
if (change.record.metadata.dataOrigin.packageName != context.packageName) {
processUpsertionChange(change)
}
is DeletionChange -> processDeletionChange(change)
}
}
nextChangesToken = response.nextChangesToken
} while (response.hasMore)
// Return and store the changes token for use next time.
return nextChangesToken
}
للتعرّف على الاعتبارات العملية المتعلقة باسترداد البيانات، اطّلِع على أفضل الممارسات المتعلّقة بمزامنة البيانات.
معالجة تغييرات البيانات
عكس التغييرات على مستودع بيانات تطبيقك بالنسبة إلى UpsertionChange، استخدِم id
وlastModifiedTime من metadata إلى upsert السجلّ.
بالنسبة إلى DeletionChange، استخدِم id المقدَّم لحذف السجلّ.
يتطلّب ذلك أن تكون قد خزّنت السجلّ id كما هو موضّح في
تخزين معرّفات Health Connect.
حذف البيانات من Health Connect
عندما يحذف المستخدم بياناته من تطبيقك، تأكَّد من إزالتها أيضًا من Health Connect. استخدِم deleteRecords
لإجراء ذلك. يأخذ هذا النوع نوع سجل وقائمة بقيم id وclientRecordId، ما يجعله مناسبًا لحذف عدة بيانات دفعة واحدة. يتوفّر أيضًا deleteRecords بديل يتضمّن timeRangeFilter.
مزامنة البيانات بوقت استجابة سريع من الأجهزة القابلة للارتداء
لمزامنة البيانات من جهاز تتبُّع اللياقة البدنية القابل للارتداء مع Health Connect بزمن انتقال منخفض، استخدِم CompanionDeviceService. تعمل هذه الطريقة مع الأجهزة التي تتوافق مع إشعارات أو مؤشرات BLE GATT وتستهدف الإصدار 8.0 من نظام التشغيل Android (المستوى 26 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث. يسمح الإذن CompanionDeviceService لتطبيقك بتلقّي البيانات من الأجهزة القابلة للارتداء وكتابتها في Health Connect، حتى عندما لا يكون التطبيق قيد التشغيل. لمزيد من التفاصيل حول أفضل ممارسات BLE، راجِع
نظرة عامة على تقنية Bluetooth Low Energy.
ربط الجهاز
أولاً، يجب أن يرشد تطبيقك المستخدم خلال عملية لمرة واحدة لربط الجهاز القابل للارتداء بتطبيقك باستخدام CompanionDeviceManager. يمنح هذا الإذن تطبيقك الأذونات اللازمة للتفاعل مع الجهاز. لمزيد من المعلومات، اطّلِع على مقالة إقران الأجهزة المصاحبة.
تعريف الخدمة في ملف البيان
بعد ذلك، عليك تعريف CompanionDeviceService في ملف بيان تطبيقك. أضِف ما يلي إلى AndroidManifest.xml:
<manifest ...>
<application ...>
<service
android:name=".MyWearableService"
android:exported="true"
android:permission="android.permission.BIND_COMPANION_DEVICE_SERVICE">
<intent-filter>
<action android:name="android.companion.CompanionDeviceService" />
</intent-filter>
</service>
</application>
</manifest>
إنشاء CompanionDeviceService
وأخيرًا، أنشئ فئة توسّع CompanionDeviceService. تتولّى هذه الخدمة
إدارة عملية الاتصال بالجهاز القابل للارتداء وتتلقّى البيانات من خلال عمليات رد الاتصال الخاصة ببروتوكول GATT عبر البلوتوث المنخفض الطاقة. عند تلقّي بيانات جديدة، يتم نقلها على الفور إلى Health Connect.
import android.companion.CompanionDeviceService
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import androidx.health.connect.client.permission.HealthPermission
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.records.HeartRateRecord
import androidx.health.connect.client.records.StepsRecord
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
class MyWearableService : CompanionDeviceService() {
// A coroutine scope for handling suspend functions like writing to Health Connect
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private var healthConnectClient: HealthConnectClient? = null
private var bluetoothGatt: BluetoothGatt? = null
// This is called by the system when your wearable connects
override fun onDeviceAppeared(address: String) {
super.onDeviceAppeared(address)
healthConnectClient = HealthConnectClient.getOrCreate(this)
serviceScope.launch {
// Check which permissions have been granted before subscribing to data from the wearable.
// A service cannot request permissions, so your app must have already requested
// and been granted them from an Activity.
val granted = healthConnectClient?.permissionController?.getGrantedPermissions()
// ... set up your GATT connection here ...
// Once connected, subscribe to notifications for the data types you have
// permission to write.
if (granted?.contains(HealthPermission.getWritePermission(HeartRateRecord::class)) == true) {
// subscribeToHeartRate(bluetoothGatt)
}
}
}
// The core of your low-latency pipeline is the BLE callback
private val gattCallback = object : BluetoothGattCallback() {
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray) {
super.onCharacteristicChanged(gatt, characteristic, value)
// 1. Instantly receive the data
val rawData = value
// 2. Parse the data from the wearable
val healthData = parseWearableData(rawData) // Your custom parsing logic
// 3. Immediately process it. For simplicity, this example writes
// directly to Health Connect. A real-world app might write to its
// own datastore first and then sync with Health Connect.
serviceScope.launch {
writeToHealthConnect(healthData)
}
}
}
private suspend fun writeToHealthConnect(healthData: HealthData) {
val records = prepareHealthConnectRecords(healthData) // Convert to Health Connect records
try {
healthConnectClient?.insertRecords(records)
} catch (e: Exception) {
// Handle exceptions
}
}
// This is called by the system when your wearable disconnects
override fun onDeviceDisappeared(address: String) {
super.onDeviceDisappeared(address)
// Clean up your GATT connection and other resources
bluetoothGatt?.close()
}
}
أفضل الممارسات لمزامنة البيانات
تؤثر العوامل التالية في عملية المزامنة.
انتهاء صلاحية الرمز المميز
بما أنّ رمز التغييرات غير المستخدَم تنتهي صلاحيته خلال 30 يومًا، عليك استخدام استراتيجية مزامنة تتجنّب فقدان المعلومات في مثل هذه الحالة. يمكن أن تتضمّن استراتيجيتك الأساليب التالية:
- ابحث في مستودع بيانات تطبيقك عن السجلّ الذي تم استخدامه مؤخرًا والذي يتضمّن أيضًا
idمن Health Connect. - يمكنك طلب سجلّات من Health Connect تبدأ بطابع زمني محدّد، ثم إدراجها أو تعديلها في مستودع بيانات تطبيقك.
- اطلب رمزًا مميزًا للتغييرات لحجزه لاستخدامه في المرة القادمة التي تحتاج فيها إليه.
استراتيجيات إدارة "التغييرات المقترَحة"
في حال كان تطبيقك يتلقّى رموز تغييرات غير صالحة أو منتهية الصلاحية، ننصحك باتّباع استراتيجيات الإدارة التالية حسب تطبيقها في منطقك:
- قراءة جميع البيانات وإزالة التكرار هذه هي الاستراتيجية الأنسب.
- تخزين الطابع الزمني لآخر مرة قرأ فيها البيانات من Health Connect
- عند انتهاء صلاحية الرمز المميّز، أعِد قراءة جميع البيانات من الطابع الزمني الأحدث أو لآخر 30 يومًا. بعد ذلك، أزِل التكرار من البيانات التي تمت قراءتها سابقًا باستخدام المعرّفات.
- يُفضَّل تنفيذ أرقام تعريف العملاء لأنّها مطلوبة لتعديل البيانات.
- قراءة البيانات فقط منذ الطابع الزمني لآخر قراءة: ويؤدي ذلك إلى بعض التناقضات في البيانات في وقت انتهاء صلاحية رمز التغييرات، ولكن الفترة الزمنية أقصر وقد تستغرق بضع ساعات إلى يومين.
- تخزين الطابع الزمني لآخر مرة قرأ فيها البيانات من Health Connect
- عند انتهاء صلاحية الرمز المميز، اقرأ جميع البيانات من هذا الطابع الزمني فصاعدًا.
- حذف البيانات ثم قراءتها لآخر 30 يومًا ويتماشى ذلك بشكل أكبر مع ما يحدث عند إجراء عملية الدمج الأولى.
- حذف جميع البيانات التي قرأها التطبيق من Health Connect خلال آخر 30 يومًا
- بعد حذفها، عليك قراءة كل هذه البيانات مرة أخرى.
- قراءة البيانات لآخر 30 يومًا بدون إزالة التكرار هذه الاستراتيجية هي الأقل ملاءمة، وتؤدي إلى عرض بيانات مكرّرة للمستخدمين.
- حذف جميع البيانات التي قرأها التطبيق من Health Connect خلال آخر 30 يومًا
- السماح بإدخالات مكرّرة
رموز تغيير نوع البيانات
إذا كان تطبيقك يستهلك أكثر من نوع بيانات واحد بشكل مستقل، استخدِم رموزًا مميّزة منفصلة لتتبُّع التغييرات لكل نوع بيانات. لا تستخدِم قائمة بأنواع بيانات متعددة مع واجهة برمجة التطبيقات Changes Sync API إلا إذا كان يتم استخدام أنواع البيانات هذه معًا أو لا يتم استخدامها على الإطلاق.
القراءات في المقدّمة
لا يمكن للتطبيقات قراءة البيانات من Health Connect إلا عندما تكون في المقدّمة. عند مزامنة البيانات من Health Connect، قد يتم في أي وقت مقاطعة إمكانية الوصول إلى Health Connect. على سبيل المثال، يجب أن يتعامل تطبيقك مع حالات الانقطاع في منتصف عملية المزامنة عند قراءة كمية كبيرة من البيانات من Health Connect، وأن يواصل المزامنة في المرة التالية التي يتم فيها فتح التطبيق.
القراءة في الخلفية
يمكنك طلب تشغيل تطبيقك في الخلفية وقراءة البيانات من Health Connect. إذا طلبت الإذن
Background Read، يمكن للمستخدم منح تطبيقك
إذن الوصول إلى البيانات وقراءتها في الخلفية.
توقيتات الاستيراد
بما أنّه لا يمكن إرسال إشعارات إلى تطبيقك بشأن البيانات الجديدة، تحقَّق من البيانات الجديدة في نقطتَين:
- في كل مرة يصبح تطبيقك نشطًا في المقدّمة في هذه الحالة، استخدِم أحداث مراحل النشاط.
- بشكل دوري، أثناء بقاء تطبيقك في المقدّمة إبلاغ المستخدمين عند توفّر بيانات جديدة، ما يتيح لهم تعديل شاشتهم لعرض التغييرات