إذا كنت تتطلّع إلى إنشاء تجربة لتتبُّع النوم في تطبيقك، يمكنك استخدام Health Connect لتنفيذ إجراءات مثل:
- كتابة بيانات جلسات النوم
- كتابة بيانات مرحلة النوم
- كتابة بيانات النوم، مثل معدّل نبضات القلب ونسبة الأكسجين في الدم ومعدّل التنفس
- قراءة بيانات النوم من تطبيقات أخرى
يوضّح هذا الدليل كيفية إنشاء ميزات النوم هذه، ويشمل أنواع البيانات والتنفيذ في الخلفية والأذونات وسير العمل المقترَح وأفضل الممارسات.
نظرة عامة: إنشاء أداة شاملة لتتبُّع النوم
يمكنك إنشاء تجربة شاملة لتتبُّع النوم باستخدام Health Connect من خلال اتّباع الخطوات الأساسية التالية:
- تنفيذ الأذونات بشكل صحيح استنادًا إلى "أذونات الصحة"
- تسجيل الجلسات باستخدام
SleepSessionRecord - كتابة أنواع البيانات، مثل مراحل النوم ومعدّل نبضات القلب ونسبة الأكسجين في الدم، بشكل متّسق أثناء الجلسة.
- إدارة عملية التنفيذ في الخلفية بشكل صحيح للتحقّق من إمكانية تسجيل البيانات بشكل مستمر طوال الليل
- قراءة بيانات جلسة النوم للحصول على ملخّصات وتحليلات ما بعد النوم
تتيح سير العمل هذا إمكانية التشغيل التفاعلي مع تطبيقات Health Connect الأخرى، كما يتحقّق من إمكانية وصول المستخدم إلى البيانات.
قبل البدء
قبل تنفيذ ميزات النوم، يُرجى مراعاة ما يلي:
- ادمج Health Connect باستخدام التبعية المناسبة.
- أنشئ مثيلاً من
HealthConnectClient. - تأكَّد من أنّ تطبيقك ينفّذ مسارات الأذونات أثناء التشغيل استنادًا إلى Health Permissions.
المفاهيم الرئيسية
يعرض تطبيق Health Connect بيانات النوم باستخدام بعض المكوّنات الأساسية. يعمل
SleepSessionRecord كسجل مركزي للنوم،
ويتضمّن تفاصيل، مثل أوقات البدء أو الانتهاء ومراحل النوم. أثناء الجلسة، يمكن تسجيل أنواع مختلفة من البيانات، مثل HeartRateRecord أو OxygenSaturationRecord.
جلسات النوم
يتم تمثيل بيانات النوم باستخدام SleepSessionRecord. يخزّن كل سجلّ ما يلي:
startTimeendTimestages: قائمةSleepSessionRecord.Stageتتضمّن النوم العميق والخفيف ونوم حركة العين السريعة (REM) والنوم مع الاستيقاظ.- البيانات الوصفية الاختيارية للجلسة (العنوان والملاحظات)
يمكن أن تكتب التطبيقات أنواعًا متعددة من البيانات المرتبطة بجلسة.
أنواع البيانات
تشمل أنواع البيانات الشائعة التي يتم تسجيلها أثناء جلسة النوم ما يلي:
SleepSessionRecord: تسجّل هذه السمة مدة النوم ومراحله، بما في ذلك النوم العميق والخفيف والنوم مع حركة العين السريعة (REM) والنوم مع الاستيقاظ.-
HeartRateRecord: تسجّل هذه السمة معدّل نبضات القلب أثناء النوم. OxygenSaturationRecord: تسجّل نسبة الأكسجين في الدم (SpO2) أثناء النوم.RespiratoryRateRecord: تسجّل هذه السمة معدّل التنفس أثناء النوم.
يتم تخزين كل نوع من البيانات كسجلّ فردي.
اعتبارات التطوير
غالبًا ما تحتاج تطبيقات تتبُّع النوم إلى العمل لفترات طويلة، وكثيرًا ما تعمل في الخلفية عندما تكون الشاشة مطفأة. وعند إنشاء ميزات تتبُّع النوم، من المهم مراعاة كيفية إدارة التنفيذ في الخلفية وطلب الأذونات اللازمة لبيانات النوم.
التنفيذ في الخلفية
تعمل تطبيقات تتبُّع النوم عادةً طوال الليل مع إيقاف تشغيل الشاشة. وعندما تكون في هذه الحالة، عليك استخدام:
- الخدمات التي تعمل في المقدّمة لجمع البيانات
-
WorkManagerللكتابة المؤجّلة أو المزامنة - استراتيجيات تجميع البيانات لكتابة السجلات العادية للبيانات التفصيلية، مثل معدّل نبضات القلب
الحفاظ على الاستمرارية من خلال إبقاء معرّف الجلسة متسقًا في جميع عمليات الكتابة
الأذونات
يجب أن يطلب تطبيقك أذونات Health Connect ذات الصلة قبل قراءة بيانات النوم أو كتابتها. للحصول على قائمة كاملة بأنواع البيانات، راجِع أنواع بيانات Health Connect. تشمل الأذونات الشائعة للنوم جلسات النوم ومقاييس مثل معدّل نبضات القلب أو نسبة الأكسجين في الدم.
يتم حماية إمكانية الوصول إلى بيانات النوم من خلال الأذونات التالية:
android.permission.health.READ_SLEEPandroid.permission.health.WRITE_SLEEP
لإضافة إمكانية تتبُّع النوم إلى تطبيقك، ابدأ بطلب أذونات لنوع البيانات SleepSession.
في ما يلي الإذن الذي يجب الإفصاح عنه لتتمكّن من كتابة بيانات النوم:
<application>
<uses-permission
android:name="android.permission.health.WRITE_SLEEP" />
...
</application>
لقراءة بيانات النوم، عليك طلب الأذونات التالية:
<application>
<uses-permission
android:name="android.permission.health.READ_SLEEP" />
...
</application>
يوضّح المثال التالي كيفية طلب أذونات لنومتك تتضمّن بيانات معدّل نبضات القلب ونسبة الأكسجين في الدم ومعدّل التنفس:
بعد إنشاء مثيل للعميل، يحتاج تطبيقك إلى طلب أذونات من المستخدم. يجب السماح للمستخدمين بمنح الأذونات أو رفضها في أي وقت.
لإجراء ذلك، أنشئ مجموعة من الأذونات لأنواع البيانات المطلوبة. تأكَّد أولاً من أنّ الأذونات في المجموعة مضمّنة في بيان Android.
// Create a set of permissions for required data types
val PERMISSIONS =
setOf(
HealthPermission.getReadPermission(SleepSessionRecord::class),
HealthPermission.getWritePermission(SleepSessionRecord::class),
HealthPermission.getReadPermission(HeartRateRecord::class),
HealthPermission.getWritePermission(HeartRateRecord::class),
HealthPermission.getReadPermission(OxygenSaturationRecord::class),
HealthPermission.getWritePermission(OxygenSaturationRecord::class),
HealthPermission.getReadPermission(RespiratoryRateRecord::class),
HealthPermission.getWritePermission(RespiratoryRateRecord::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)
}
}
بما أنّ المستخدمين يمكنهم منح الأذونات أو إبطالها في أي وقت، يجب أن يتحقّق تطبيقك من الأذونات في كل مرة قبل استخدامها، وأن يتعامل مع الحالات التي يتم فيها فقدان الإذن.
تنفيذ جلسة نوم
يوضّح هذا القسم سير العمل المقترَح لتسجيل بيانات النوم.
لمواءمة أنواع البيانات، مثل HeartRateRecord أو OxygenSaturationRecord، مع جلسة نوم، سجِّلها باستخدام الطوابع الزمنية التي تقع بين startTime وendTime للجلسة. لا يستخدم تطبيق Health Connect معرّف جلسة لربط جلسات النوم بالبيانات التفصيلية. بدلاً من ذلك، يكون الربط ضمنيًا من خلال الفواصل الزمنية المتداخلة. عند قراءة بيانات النوم، يمكنك استخدام النطاق الزمني لجلسة معيّنة للاستعلام عن أنواع البيانات المرتبطة بها، كما هو موضّح في قراءة بيانات النوم.
كتابة جلسة
مع أنّ البيانات التفصيلية، مثل معدّل نبضات القلب، يمكن تسجيلها طوال جلسة النوم، يجب ألا يتم تسجيل SleepSessionRecord نفسها في Health Connect إلا بعد انتهاء الجلسة، مثلاً عندما يستيقظ المستخدم. يجب أن يتضمّن السجلّ الجلسة startTime وendTime وقائمة بعناصر SleepSessionRecord.Stage التي تم تسجيلها خلال الجلسة، لأنّ SleepSessionRecord يتطلّب أن يكون endTime بعد startTime.
لكتابة بيانات جلسة نوم، اتّبِع الخطوات التالية:
- أنشئ معرّفًا فريدًا لسجلّ العميل.
- عندما يستيقظ المستخدم أو يتم إيقاف ميزة تتبُّع النوم، اجمع كل مراحل النوم وأنشئ
SleepSessionRecord. - أدرِج السجلّ باستخدام
insertRecords.
مثال:
val clientRecordId = UUID.randomUUID().toString()
val sessionStartTime = LocalDateTime.of(2023, 10, 30, 22, 0).toInstant(ZoneOffset.UTC)
val sessionEndTime = LocalDateTime.of(2023, 10, 31, 7, 0).toInstant(ZoneOffset.UTC)
val stages = mutableListOf<SleepSessionRecord.Stage>()
// Add recorded stages, for example:
stages.add(SleepSessionRecord.Stage(
startTime = sessionStartTime.plusSeconds(3600),
endTime = sessionStartTime.plusSeconds(7200),
stage = SleepSessionRecord.STAGE_TYPE_LIGHT)
)
stages.add(SleepSessionRecord.Stage(
startTime = sessionStartTime.plusSeconds(7200),
endTime = sessionStartTime.plusSeconds(10800),
stage = SleepSessionRecord.STAGE_TYPE_DEEP)
)
// ... other stages
val session = SleepSessionRecord(
startTime = sessionStartTime,
startZoneOffset = ZoneOffset.UTC,
endTime = sessionEndTime,
endZoneOffset = ZoneOffset.UTC,
stages = stages,
metadata = Metadata(clientRecordId = clientRecordId)
)
healthConnectClient.insertRecords(listOf(session))
قراءة بيانات النوم
يمكن للتطبيقات قراءة جلسات النوم والبيانات المرتبطة بها لتلخيص النشاط أو تقديم إحصاءات صحية أو مزامنة البيانات مع خادم خارجي. على سبيل المثال، يمكنك قراءة SleepSessionRecord ثم طلب البحث عن HeartRateRecord الذي حدث خلال الفترة الزمنية نفسها.
قراءة الجلسة مع البيانات المرتبطة بها
يمكنك قراءة جلسات النوم باستخدام ReadRecordsRequest مع SleepSessionRecord كنوع البيانات، مع فلترتها حسب النطاق الزمني. لقراءة البيانات المرتبطة بجلسة معيّنة، أرسِل طلبًا ثانيًا لنوع البيانات المحدّد، مثل HeartRateRecord، مع الفلترة حسب startTime وendTime لجلسة النوم.
يوضّح المثال التالي كيفية قراءة جلسات النوم التي تتضمّن بيانات معدّل ضربات القلب المرتبطة بها خلال نطاق زمني معيّن:
suspend fun readSleepSessionsWithAssociatedData(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = SleepSessionRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
for (sleepRecord in response.records) {
// Process each session
val stages = sleepRecord.stages
val notes = sleepRecord.notes
// To read specific granular data (like heart rate) that occurred during
// this session, use the session's startTime and endTime to filter
// the request for that data type.
val hrResponse = healthConnectClient.readRecords(
ReadRecordsRequest(
recordType = HeartRateRecord::class,
timeRangeFilter = TimeRangeFilter.between(
sleepRecord.startTime,
sleepRecord.endTime
)
)
)
for (heartRateRecord in hrResponse.records) {
for (sample in heartRateRecord.samples) {
val bpm = sample.beatsPerMinute
}
}
}
}
أفضل الممارسات
اتّبِع الإرشادات التالية لتحسين موثوقية البيانات وتجربة المستخدم:
- الكتابة بشكل متكرّر أثناء التتبُّع النشط: بالنسبة إلى التتبُّع النشط، اكتب البيانات فور توفّرها أو بفاصل زمني أقصاه 15 دقيقة.
- استخدام WorkManager للمزامنات في الخلفية: استخدِم
WorkManagerلعمليات الكتابة المؤجّلة. ننصحك بتحديد فترة زمنية مدتها 15 دقيقة لتحقيق التوازن بين البيانات في الوقت الفعلي وكفاءة البطارية. - طلبات الكتابة المجمّعة: لا تكتب كل حدث من أحداث المستشعر بشكل فردي. تقسيم طلباتك إلى أجزاء يتعامل تطبيق Health Connect مع ما يصل إلى 1,000 سجلّ لكل طلب تعديل.
- الحفاظ على ثبات معرّفات الجلسات وفرادتها: استخدِم معرّفات متّسقة لجلساتك. في حال تعديل جلسة أو تحديثها، يمنع استخدام المعرّف نفسه التعامل معها كجلسة جديدة منفصلة.
- استخدام التجميع لأنواع البيانات: لتقليل الحمل الزائد للإدخال/الإخراج والحفاظ على عمر البطارية، عليك تجميع نقاط البيانات في طلب
insertRecordsواحد بدلاً من كتابة كل نقطة على حدة. - تجنُّب كتابة بيانات مكرّرة: استخدام أرقام تعريف العملاء: عند إنشاء سجلّات، اضبط
metadata.clientRecordId. يستخدم تطبيق Health Connect هذا المعرّف لتحديد السجلّات الفريدة. إذا حاولت كتابة سجلّ باستخدامclientRecordIdسبق أن تم إنشاؤه، سيتجاهل Health Connect النسخة المكرّرة أو سيعدّل السجلّ الحالي بدلاً من إنشاء سجلّ جديد. يُعدّ ضبطmetadata.clientRecordIdالطريقة الأكثر فعالية لمنع تكرار البيانات أثناء إعادة محاولات المزامنة أو إعادة تثبيت التطبيق.val record = StepsRecord( count = 100, startTime = startTime, endTime = endTime, startZoneOffset = ZoneOffset.UTC, endZoneOffset = ZoneOffset.UTC, metadata = Metadata( // Use a unique ID from your own database clientRecordId = "daily_steps_2023_10_27_user_123" ) )
- التحقّق من البيانات الحالية: قبل المزامنة، ابحث عن النطاق الزمني لمعرفة ما إذا كانت السجلات من تطبيقك متوفّرة من قبل.
- التأكّد من عدم تداخل الطوابع الزمنية: تأكَّد من أنّ الجلسة الجديدة لا تبدأ قبل انتهاء الجلسة السابقة. يمكن أن تتسبّب الجلسات المتداخلة في حدوث تعارضات في لوحات بيانات اللياقة البدنية واحتساب الملخّصات.
- تقديم أسباب واضحة للحصول على الإذن: استخدِم مسار
Permission.createIntentلتوضيح سبب حاجة تطبيقك إلى الوصول إلى البيانات الصحية، على سبيل المثال: "لمراقبة مؤشرات ضغط الدم وتقديم إحصاءات". - اختبار الجلسات الطويلة: راقِب استهلاك البطارية خلال الجلسات التي تستغرق عدة ساعات للتأكّد من أنّ الفاصل الزمني لتجميع البيانات واستخدام المستشعر لا يستنزفان البطارية.
- مواءمة الطوابع الزمنية مع معدّلات أجهزة الاستشعار: يمكنك مطابقة الطوابع الزمنية لسجلّك مع معدّل تكرار أجهزة الاستشعار الفعلي للحفاظ على دقة البيانات العالية.
الاختبار
للتحقّق من صحة البيانات وتوفير تجربة عالية الجودة للمستخدم، اتّبِع استراتيجيات الاختبار التالية وراجِع مستندات أهم حالات الاستخدام للاختبار الرسمية.
أدوات التحقّق
- أداة Health Connect: استخدِم هذا التطبيق المصاحب لفحص السجلات يدويًا وحذف البيانات التجريبية ومحاكاة التغييرات في قاعدة البيانات. وهي أفضل طريقة للتأكّد من تخزين سجلاتك بشكل صحيح.
- اختبار الوحدات باستخدام
FakeHealthConnectClient: استخدِم مكتبة الاختبار للتحقّق من طريقة تعامل تطبيقك مع الحالات الحدّية، مثل إلغاء الإذن أو استثناءات واجهة برمجة التطبيقات، بدون الحاجة إلى جهاز فعلي.
قائمة التحقّق من الجودة
البنية النموذجية
يتضمّن تنفيذ ميزة تتبُّع النوم عادةً ما يلي:
| المكوّن | إدارة |
|---|---|
| وحدة التحكّم في الجلسة | حالة الجلسة المؤقّت منطق تجميع البيانات عناصر التحكّم في أنواع البيانات جمع البيانات |
| طبقة المستودع (تتضمّن عمليات Health Connect): | إدراج جلسة إدراج أنواع البيانات إدراج مراحل النوم قراءة ملخّصات الجلسات |
| طبقة واجهة المستخدم (شاشات العرض): | المدة أنواع البيانات المباشرة تمثيل مراحل النوم |
تحديد المشاكل وحلّها
| المشكلة | السبب المحتمَل | درجة الدقة |
|---|---|---|
| أنواع البيانات غير متوفّرة (مثل معدّل نبضات القلب) | عدم توفّر أذونات الكتابة أو فلاتر الوقت غير الصحيحة | تأكَّد من أنّك طلبت من المستخدم منح الإذن لنوع البيانات المحدّد. تأكَّد من أنّ ReadRecordsRequest يستخدم TimeRangeFilter مطابقًا للجلسة. اطّلِع على الأذونات. |
| تعذُّر كتابة الجلسة | طوابع زمنية متداخلة | قد يرفض Health Connect السجلّات التي تتداخل مع البيانات الحالية من التطبيق نفسه. تأكَّد من أنّ startTime جلسة جديدة يقع بعد endTime الجلسة السابقة. |
| لم يتم تسجيل أي بيانات من أجهزة الاستشعار أثناء النوم | تم إيقاف الخدمة التي تعمل في المقدّمة أو كانت غير نشطة. | لجمع بيانات جهاز الاستشعار طوال الليل أثناء إيقاف الشاشة، يمكنك استخدام خدمة تعمل في المقدّمة مع foregroundServiceType="health". |
| تظهر السجلات المكررة | السمة clientRecordId غير متوفّرة. |
خصِّصوا clientRecordId فريدًا في Metadata لكل سجلّ. يتيح ذلك لتطبيق Health Connect إزالة البيانات المكرّرة إذا تمت كتابة البيانات نفسها مرتين أثناء إعادة محاولة المزامنة. اطّلِع على أفضل الممارسات. |
خطوات تصحيح الأخطاء الشائعة
| التحقّق من حالة الإذن | يجب دائمًا استدعاء getPermissionStatus() قبل محاولة إجراء عملية قراءة أو كتابة. يمكن للمستخدمين إبطال الأذونات في إعدادات النظام في أي وقت. |
| تحقَّق من وضع التنفيذ. | إذا كان تطبيقك لا يجمع البيانات في الخلفية، تأكَّد من أنّك أدرجت الأذونات الصحيحة في ملف AndroidManifest.xml وأنّ المستخدم لم يضع التطبيق في وضع "استخدام البطارية محدود". |