המדריך הזה תואם לגרסה 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))Upsert נתונים ל-Health Connect באמצעות
insertRecords. הוספה או עדכון של נתונים (Upsert) פירושה שכל הנתונים הקיימים ב-Health Connect יימחקו אם הערכים שלclientRecordIdקיימים במאגר הנתונים של Health Connect, והערך שלclientRecordVersionגבוה מהערך הקיים. אחרת, הנתונים שנוספו ייכתבו כנתונים חדשים.healthConnectClient.insertRecords(arrayListOf(record))
כדי לקבל מידע על שיקולים מעשיים לגבי הזנת נתונים, אפשר לעיין בשיטות המומלצות בנושא כתיבת נתונים.
שמירת מזהים של Health Connect
אם האפליקציה שלכם גם קוראת נתונים מ-Health Connect, צריך לאחסן את id
של הרשומות אחרי שמעדכנים אותן. אתם צריכים את 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, האפליקציה צריכה לעקוב אחרי טוקנים של שינויים. אפשר להשתמש בהם כשמבקשים שינויים כדי לקבל גם רשימה של שינויים בנתונים וגם טוקן שינויים חדש לשימוש בפעם הבאה.
כדי לקבל טוקן Changes, קוראים ל-getChangesToken ומספקים את סוגי הנתונים הנדרשים.
val changesToken = healthConnectClient.getChangesToken(
ChangesTokenRequest(recordTypes = setOf(WeightRecord::class))
)
בדיקת שינויים בנתונים
אחרי שמקבלים את אסימון השינויים, משתמשים בו כדי לקבל את כל השינויים. מומלץ ליצור לולאה כדי לעבור על כל השינויים ולבדוק אם יש שינויים זמינים בנתונים. אלה השלבים:
- מתקשרים אל
getChangesבאמצעות הטוקן כדי לקבל רשימה של שינויים. - בודקים את סוג השינוי של כל שינוי:
UpsertionChangeאוDeletionChange, ומבצעים את הפעולות הנדרשות.- במקרה של
UpsertionChange, צריך לקחת בחשבון רק שינויים שלא בוצעו באפליקציה שקוראת ל-API, כדי לוודא שלא מייבאים מחדש נתונים.
- במקרה של
- מקצים את האסימון הבא של שינויים כאסימון החדש.
- חוזרים על שלבים 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 כדי לעדכן או להוסיף את הרשומה.
במקרה של DeletionChange, משתמשים בid שמופיע כדי למחוק את הרשומה.
כדי לעשות זאת, צריך לשמור את הרשומה id כמו שמתואר במאמר שמירת מזהים של Health Connect.
מחיקת נתונים מ-Health Connect
כשמשתמש מוחק את הנתונים שלו מהאפליקציה שלכם, חשוב לוודא שהנתונים מוסרים גם מ-Health Connect. כדי לעשות את זה, משתמשים בפקודה deleteRecords. הפונקציה מקבלת סוג רשומה ורשימה של ערכים id ו-clientRecordId
ומאפשרת למחוק כמה נתונים בבת אחת. אפשר גם להשתמש בחלופה deleteRecords שמקבלת timeRangeFilter.
סנכרון עם זמן אחזור נמוך ממכשירים לבישים
כדי לסנכרן נתונים ממכשיר לביש לכושר אל Health Connect עם זמן אחזור נמוך,
משתמשים ב-CompanionDeviceService. הגישה הזו מתאימה למכשירים שתומכים בהתראות או באינדיקציות של BLE GATT ולמכשירים שמיועדים ל-Android 8.0 (API ברמה 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. השירות הזה מטפל בחיבור למכשיר הלביש ומקבל נתונים באמצעות קריאות חוזרות (callback) של BLE 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()
}
}
שיטות מומלצות לסינכרון נתונים
הגורמים הבאים משפיעים על תהליך הסנכרון.
תפוגת התוקף של הטוקן
אסימון Changes שלא נעשה בו שימוש יפוג תוך 30 יום, ולכן צריך להשתמש באסטרטגיית סנכרון שתמנע אובדן מידע במקרה כזה. האסטרטגיה שלכם יכולה לכלול את הגישות הבאות:
- מחפשים במאגר הנתונים של האפליקציה את הרשומה האחרונה שהייתה בשימוש, שכוללת גם
idמ-Health Connect. - שליחת בקשה לרישומים מ-Health Connect שמתחילים בחותמת זמן ספציפית, ואז הוספה או עדכון שלהם במאגר הנתונים של האפליקציה.
- שליחת בקשה לקבלת אסימון שינויים כדי לשריין אותו לפעם הבאה שיהיה צורך בו.
שיטות מומלצות לניהול שינויים
אם האפליקציה מקבלת טוקנים של שינויים שהם פסולים או שתוקפם פג, מומלץ להשתמש באסטרטגיות הניהול הבאות בהתאם ליישום שלהן בלוגיקה שלכם:
- קריאה וביטול כפילויות של כל הנתונים. זו השיטה האידיאלית ביותר.
- שומרים את חותמת הזמן של הפעם האחרונה שבה האפליקציה קראה נתונים מ-Health Connect.
- כשפג תוקף האסימון, צריך לקרוא מחדש את כל הנתונים מהחותמת האחרונה או מ-30 הימים האחרונים. לאחר מכן, מסירים את הכפילויות מהנתונים שנקראו קודם באמצעות מזהים.
- מומלץ להטמיע Client-ID, כי הוא נדרש לעדכוני נתונים.
- קריאת נתונים רק מאז חותמת הזמן האחרונה של הקריאה. כתוצאה מכך, יכול להיות שיהיו אי-התאמות בנתונים בסביבות הזמן של תפוגת טוקן השינויים, אבל התקופה קצרה יותר ויכולה להימשך כמה שעות עד כמה ימים.
- שומרים את חותמת הזמן של הפעם האחרונה שבה האפליקציה קראה נתונים מ-Health Connect.
- כשפג תוקף האסימון, כל הנתונים נקראים מהחותמת הזו ואילך.
- מחיקה ואז קריאת נתונים מ-30 הימים האחרונים. ההתנהגות הזו דומה יותר למה שקורה בשילוב הראשון.
- מחיקת כל הנתונים שהאפליקציה קראה מ-Health Connect ב-30 הימים האחרונים.
- אחרי המחיקה, קוראים שוב את כל הנתונים האלה.
- קריאת נתונים מ-30 הימים האחרונים ללא ביטול כפילויות. זוהי האסטרטגיה הכי פחות מומלצת, והיא גורמת לכך שיוצגו למשתמשים נתונים כפולים.
- מחיקת כל הנתונים שהאפליקציה קראה מ-Health Connect ב-30 הימים האחרונים.
- אפשר להזין ערכים כפולים.
אסימוני שינויים בסוג הנתונים
אם האפליקציה צורכת יותר מסוג נתונים אחד באופן עצמאי, צריך להשתמש ב-Changes Tokens נפרדים לכל סוג נתונים. אפשר להשתמש ברשימה של כמה סוגי נתונים עם Changes Sync API רק אם סוגי הנתונים האלה נצרכים ביחד או לא נצרכים בכלל.
קריאות בחזית
אפליקציות יכולות לקרוא נתונים מ-Health Connect רק כשהן פועלות ברקע. במהלך סנכרון הנתונים מ-Health Connect, יכול להיות שהגישה ל-Health Connect תיקטע בכל שלב. לדוגמה, האפליקציה צריכה לטפל בהפרעות באמצע הסנכרון כשקוראים כמות גדולה של נתונים מ-Health Connect, ולהמשיך בפעם הבאה שהאפליקציה תיפתח.
קריאה ברקע
אתם יכולים לבקש שהאפליקציה שלכם תפעל ברקע ותקרא נתונים מ-Health Connect. אם תבקשו את ההרשאה Background Read, המשתמש יוכל להעניק לאפליקציה שלכם גישה לקריאת נתונים ברקע.
ייבוא תזמונים
מכיוון שלא ניתן לשלוח לאפליקציה שלך התראות על נתונים חדשים, צריך לבדוק אם יש נתונים חדשים בשני מקומות:
- בכל פעם שהאפליקציה שלך הופכת לפעילה בחזית. במקרה כזה, כדאי להשתמש באירועים במחזור החיים.
- מדי פעם, כשהאפליקציה פועלת בחזית. התראה למשתמשים כשנתונים חדשים זמינים, כדי שיוכלו לעדכן את המסך שלהם בהתאם לשינויים.