פיתוח חוויות שינה באמצעות Health Connect

אם אתם רוצים לשלב באפליקציה שלכם מעקב אחר נתוני השינה, אתם יכולים להשתמש ב-Health Connect כדי לבצע פעולות כמו:

  • כתיבה של נתוני השינה
  • כתיבה של נתוני שלב השינה
  • כתיבה של נתוני שינה כמו דופק, רמת החמצן בדם וקצב הנשימה
  • קריאת נתוני שינה מאפליקציות אחרות

במדריך הזה מוסבר איך לפתח את תכונות השינה האלה. הוא כולל מידע על סוגי נתונים, הרשאות, תהליכי עבודה מומלצים ושיטות מומלצות.

סקירה כללית: יצירת כלי מקיף למעקב אחרי השינה

כדי ליצור חוויית מעקב אחר השינה מקיפה באמצעות Health Connect, צריך לבצע את השלבים הבאים:

  • הטמעה נכונה של הרשאות על סמך Health Permissions.
  • הקלטת סשנים באמצעות SleepSessionRecord.
  • כתיבת סוגי נתונים כמו שלבי שינה, דופק ורמת החמצן בדם באופן עקבי במהלך הסשן.
  • ניהול נכון של הרצה ברקע כדי לוודא שמתבצע איסוף רציף של נתונים במהלך הלילה.
  • קריאת נתוני סשן לצורך סיכומים וניתוחים של נתוני שינה.

תהליך העבודה הזה מאפשר אינטראופרביליות עם אפליקציות אחרות של Health Connect ומאמת את הגישה לנתונים שנשלטת על ידי המשתמש.

לפני שמתחילים

לפני שמטמיעים תכונות שינה:

קונספטים מרכזיים

נתוני השינה ב-Health Connect מיוצגים באמצעות כמה רכיבי ליבה. SleepSessionRecord משמש כרשומה מרכזית של נתוני השינה, ומכיל פרטים כמו שעת ההתחלה או הסיום ושלבי השינה. במהלך סשן, יכולים להירשם סוגים שונים של נתונים, כמו HeartRateRecord או OxygenSaturationRecord.

רשומות שינה

נתוני השינה מיוצגים על ידי SleepSessionRecord. כל רשומה מכילה את הפרטים הבאים:

  • startTime
  • endTime
  • stages: רשימה של SleepSessionRecord.Stage כולל שינה עמוקה, שינה קלה, שנת REM ושינה עם התעוררויות.
  • מטא-נתונים אופציונליים של הסשן (שם, הערות)

אפליקציות יכולות לכתוב כמה סוגי נתונים שמשויכים לסשן.

סוגי הנתונים

סוגי הנתונים הנפוצים שנרשמים במהלך רשומת שינה כוללים:

  • SleepSessionRecord: מתעד את משך השינה ואת השלבים שלה, כולל שינה עמוקה, שינה קלה, שנת REM וזמן הערות.
  • HeartRateRecord: תיעוד הדופק במהלך השינה.
  • OxygenSaturationRecord: רמת החמצן בדם (סטורציה) במהלך השינה.
  • RespiratoryRateRecord: מתעד את קצב הנשימה במהלך השינה.

כל סוג נתונים נשמר כרשומה נפרדת.

שיקולי פיתוח

אפליקציות למעקב אחרי השינה צריכות לפעול לפרקי זמן ארוכים, ולעתים קרובות ברקע כשהמסך כבוי. כשמפתחים תכונות שקשורות לשינה, חשוב לחשוב איך לנהל את ההרצה ברקע ולבקש את ההרשאות הנדרשות לנתוני השינה.

ביצוע ברקע

אפליקציות למעקב אחרי שינה פועלות בדרך כלל בלילה כשהמסך כבוי. במצב הזה, צריך להשתמש ב:

  • שירותים שפועלים בחזית לאיסוף נתונים
  • WorkManager לכתיבה או לסנכרון מאוחרים
  • שיטות לאיגום נתונים בכתיבה רגילה של רשומות של נתונים גרנולריים, כמו דופק

כדי לשמור על רציפות, צריך להקפיד שמזהה הסשן יהיה זהה בכל הפעולות.

הרשאות

האפליקציה צריכה לבקש את ההרשאות הרלוונטיות ל-Health Connect לפני שהיא קוראת או כותבת נתוני שינה. רשימה מלאה של סוגי הנתונים זמינה במאמר סוגי הנתונים ב-Health Connect. הרשאות נפוצות לשינה כוללות רשומות שינה ומדדים כמו דופק או רמת החמצן בדם.

הגישה לנתוני השינה מוגנת על ידי ההרשאות הבאות:

  • android.permission.health.READ_SLEEP
  • android.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.

כדי לכתוב רשומת שינה:

  1. יוצרים מזהה ייחודי של רשומת לקוח.
  2. כשהמשתמש מתעורר או כשמעקב אחר השינה מופסק, אוספים את כל שלבי השינה ויוצרים SleepSessionRecord.
  3. מוסיפים את ההקלטה באמצעות 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 Toolbox: אפליקציית העזר הזו מאפשרת לבדוק רשומות באופן ידני, למחוק נתוני בדיקה ולדמות שינויים במסד הנתונים. זו הדרך הכי טובה לוודא שהרשומות שלכם מאוחסנות בצורה נכונה.
  • בדיקות יחידה באמצעות FakeHealthConnectClient: אפשר להשתמש בספריית הבדיקות כדי לבדוק איך האפליקציה מטפלת במקרים חריגים, כמו ביטול הרשאה או חריגות ב-API, בלי להזדקק למכשיר פיזי.

רשימת משימות לבדיקת איכות

ארכיטקטורה אופיינית

הטמעה של מעקב אחר השינה כוללת בדרך כלל:

רכיב מנהל
בקר סשנים מצב הסשן
טיימר
לוגיקה של עיבוד באצווה
סוגי נתונים של אמצעי בקרה
איסוף נתונים
שכבת מאגר (עוטפת פעולות של Health Connect:) הוספת סשן
הוספת סוגי נתונים
הוספת שלבי שינה
קריאת סיכומי סשנים
שכבת ממשק המשתמש (מסכים): משך זמן
סוגי נתונים בזמן אמת
תרשים להמחשת שלבי השינה

פתרון בעיות

תיאור הבעיה סיבה אפשרית רזולוציה
סוגי נתונים חסרים (לדוגמה, דופק) הרשאות כתיבה חסרות או שהמסננים של הזמן שגויים. בודקים שביקשתם מהמשתמש הרשאה לסוג הנתונים הספציפי והמשתמש אישר את הבקשה. צריך לוודא שReadRecordsRequest משתמש בTimeRangeFilter שתואם לסשן. מידע נוסף על הרשאות
הכתיבה של הסשן נכשלת חותמות זמן חופפות. יכול להיות שאפליקציית Health Connect תדחה רשומות שחופפות לנתונים קיימים מאותה אפליקציה. צריך לוודא שstartTime של סשן חדש מופיע אחרי endTime של הסשן הקודם.
לא מתועדים נתוני חיישנים במהלך השינה השירות שפועל בחזית הופסק או לא פעיל. כדי לאסוף נתוני חיישנים במהלך הלילה כשהמסך כבוי, אפשר להשתמש בשירות שפועל בחזית עם foregroundServiceType="health".
מופיעות רשומות כפולות חסר: clientRecordId להקצות clientRecordId ייחודי בMetadata של כל רשומה. כך, אם אותם נתונים נכתבים פעמיים במהלך ניסיון חוזר של סנכרון, אפליקציית Health Connect יכולה לבצע הסרת כפילויות. שיטות מומלצות

שלבים נפוצים לניפוי באגים

בודקים את מצב ההרשאה. תמיד מתקשרים אל getPermissionStatus() לפני שמנסים לבצע פעולת קריאה או כתיבה. המשתמשים יכולים לבטל את ההרשאות בהגדרות המערכת בכל שלב.
מאמתים את מצב ההפעלה. אם האפליקציה לא אוספת נתונים ברקע, צריך לוודא שהצהרתם על ההרשאות הנכונות בקובץ AndroidManifest.xml ושהמשתמש לא העביר את האפליקציה למצב 'הגבלת השימוש בסוללה'.