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

המדריך הזה תואם לגרסה 1.1.0 של Health Connect ואילך.

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

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

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

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

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

  • להטמיע הרשאות בצורה נכונה בהתאם למדיניות בנושא הרשאות גישה לנתוני בריאות.
  • הקלטת סשנים באמצעות 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.

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.
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.") }
    }
}
המשתמשים יכולים לתת או לבטל הרשאות בכל שלב, ולכן האפליקציה צריכה לבדוק אם ההרשאות ניתנו בכל פעם לפני שהיא משתמשת בהן, ולטפל במקרים שבהם הרשאה כלשהי בוטלה.

הטמעה של רשומת שינה

בקטע הזה מתואר תהליך העבודה המומלץ לתיעוד נתוני השינה.

כדי להתאים סוגי נתונים כמו 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 ושהמשתמש לא העביר את האפליקציה למצב "מוגבלת על ידי הסוללה".