Usage: Sync health data automatically
Schedule automatic syncs with every app launch or in background.
You can implement automatic syncs using any of the following:
- Background Sync: Syncs every hour without opening the app, recommended if your project supports Android 15 (SDK 35).
- Continuous Upload: Syncs every time you call it on foreground, recommended if your project is still on Android 14 (SDK 34) or lower.
- Yesterday Sync: Syncs every time an
Activity
is in a specific lifecycle state (CREATED, STARTED or RESUMED).
You should not use them at the same time as that could negatively affect your Health Connect request quota, however you can use them conditionally to cover edge cases like a user whose device does not support Background Sync, in that case using Continuous Upload will ensure that data is synced when your app is in foreground.
Background sync
Background Sync
is only available in 2.0.0-alpha01+
version.
Background Sync
allows to schedule an automatic syncs every hour in the background.
You can call its functions by creating an instance with a context:
val rookBackgroundSyncManager = RookBackgroundSyncManager(context)
rookBackgroundSyncManager.doSomething()
Or using the Companion object and providing a context with each call:
RookBackgroundSyncManager.doSomething(context)
The following table describes Background Sync
frequency of synchronization and historical range of each Health
structure:
Health structure | Frequency | Historical range |
---|---|---|
Sleep Summary | Once per day | 29 days in the past until yesterday |
Body Summary | Once per day | 29 days in the past until yesterday |
Physical Summary | Once per day | 29 days in the past until yesterday |
Physical Activity | Once per hour | 29 days in the past until today |
Steps | Once per hour | Today |
Body metrics | Once per hour | Today |
Heart rate | Once per hour | Today |
Blood pressure | Once per hour | Today |
Blood glucose | Once per hour | Today |
Oxygenation | Once per hour | Today |
Temperature | Once per hour | Today |
Permissions
To use Background Sync
you will need:
- Health Connect permissions: Go to the main Health Connect Permissions section to see the implementation.
- Background read permissions: Go to the main Background Read permissions section to see the implementation.
Background Sync
also requires a user id, so it's possible that the
first time nothing will happen, only after a user id is configured and all necessary permissions are
granted the automatic sync will happen within the next hour.
Usage
To schedule a background sync for every hour call schedule
:
rookBackgroundSyncManager.schedule(enableLogs = isDebug)
We recommend calling schedule
in the onCreate
callback of your Application class:
class MyAplication : Application() {
override fun onCreate() {
super.onCreate()
// It's a good practice to ask your users if they want to enable this behaviour
// and wrap this line inside an if which checks a preferences-stored flag
if (userAllowedBackgroundSync) {
RookBackgroundSyncManager.schedule(this, enableLogs = isDebug)
}
}
}
It's a good practice to ask your users if they want to enable this behaviour, then save their preference in local
storage and call schedule
conditionally.
Once started Background Sync
will attempt to sync all historic data, and will stop after it
finishes or until the Health Connect request quota is
exceeded.
To cancel any scheduled background sync call cancel
:
rookBackgroundSyncManager.cancel()
If you want to check the current state of Background Sync
call isScheduled
or isScheduledFlow
(Experimental):
fun howToCheckBackgroundSyncState() {
// Get latest state
coroutineScope.launch {
val isScheduled: Boolean = rookBackgroundSyncManager.isScheduled().getOrDefault(defaultValue = false)
// Update UI
}
// Receive real-time updates
@OptIn(ExperimentalRookApi::class)
viewModelScope.launch {
rookBackgroundSyncManager.isScheduledFlow().collectLatest { isScheduled: Boolean ->
// Update UI
}
}
}
Don't use isScheduled
or isScheduledFlow
to decide if you should call schedule
, if you do this future improvements
to the Background Sync behavior may not be applied, the "isScheduled" functions are only meant for UI related purposes.
Execution/Skip conditions
Each periodic execution of Background Sync
will check for some requirements, and will skip the execution if one the
following conditions is true:
- The device battery is low.
- The device storage is low.
- The device is not connected to the internet.
- The userID hasn't been configured.
- The most recent request exceeded the Health Connect request quota.
- The device has previously exceeded the Health Connect request quota and less than 60 minutes have passed.
- The user hasn't granted Health Connect Permissions.
- The user hasn't granted Background Read Permissions.
- There is an error initializing the SDK.
Continuous upload
RookContinuousUploadManager
allows to launch 29 days historic health data synchronizations.
You can call its functions by creating an instance with a context:
val rookContinuousUploadManager = RookContinuousUploadManager(context)
rookContinuousUploadManager.doSomething()
Or using the Companion object and providing a context with each call:
RookContinuousUploadManager.doSomething(context)
The following table describes Continuous upload
frequency of synchronization and historical range of each Health
structure:
Health structure | Frequency | Historical range |
---|---|---|
Sleep Summary | Each time launch or launchInForegroundService is called | 29 days in the past until yesterday |
Body Summary | Each time launch or launchInForegroundService is called | 29 days in the past until yesterday |
Physical Summary | Each time launch or launchInForegroundService is called | 29 days in the past until yesterday |
Physical Activity | Each time launch or launchInForegroundService is called | 29 days in the past until today |
Steps | Each time launch or launchInForegroundService is called | Today |
launch
Starts an immediate health data synchronization. This function won't display a notification, if the app goes to the background the synchronization will fail.
Requirements:
coroutineScope.launch {
RookContinuousUploadManager.launch(context, enableLogs)
}
launchInForegroundService
Starts an immediate health data synchronization in a foreground service. This function will display a notification, if the app goes to the background the synchronization will continue until it finishes, then the notification will be removed.
Requirements:
coroutineScope.launch {
RookContinuousUploadManager.launchInForegroundService(context, enableLogs)
}
Recommendations
We recommend calling launch
or launchInForegroundService
in the onCreate
callback of your Application class:
class MyAplication : Application() {
override fun onCreate() {
super.onCreate()
coroutineScope.launch {
// It's a good practice to ask your users if they want to enable this behaviour
// and wrap this line inside an if which checks a preferences-stored flag
// Without notification
if (userAllowedContinuousUpload) {
// Call launch or launchInForegroundService
}
}
}
}
It's a good practice to ask your users if they want to enable this behaviour, then save their preference in local
storage and call launch
or launchInForegroundService
conditionally.
Once started launch
or launchInForegroundService
will attempt to sync all historic data, and it will shut down
itself after it
finishes or until the Health Connect request quota is
exceeded.
launch
or launchInForegroundService
are intended to be called only once in your apps lifecycle, like the Application
class onCreate callback.
Customizing the foreground service notification
launchInForegroundService
runs in a Foreground Service is used, this service requires a notification to be displayed
until the synchronization finishes.
The notification has the next default values:
- Icon
- Title: Sync service
- Content: Syncing your health data…
To use your own resources you need to reference them in the AndroidManifest.xml file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<meta-data
android:name="io.tryrook.service.notification.SYNC_ICON"
android:resource="@drawable/my_custom_icon"/>
<meta-data
android:name="io.tryrook.service.notification.SYNC_TITLE"
android:resource="@string/my_custom_title"/>
<meta-data
android:name="io.tryrook.service.notification.SYNC_CONTENT"
android:resource="@string/my_custom_content"/>
</application>
</manifest>
Starting on Android 13 (SDK 33) this notification can be dismissed without finishing the service associated with it, then the service will be displayed in the active apps section (This may vary depending on device brand).
Launch/Stop conditions
launch
/ launchInForegroundService
won't start or will stop if one the following conditions is true:
- The device battery is low.
- The device storage is low.
- The device is not connected to the internet.
- The userID hasn't been configured.
- The most recent request exceeded the Health Connect request quota.
- The device has previously exceeded the Health Connect request quota and less than 60 minutes have passed.
- The user hasn't granted Health Connect Permissions.
- There is an error initializing the SDK.
- The user hasn't granted Android Permissions (only applies for
launchInForegroundService
). - The app is in the background when calling
launch
/launchInForegroundService
.
Yesterday sync
RookYesterdaySync
is a preconfigured component to execute an automatic sync for the past 29-day summaries and
activities.
The following table describes Yesterday sync
frequency of synchronization and historical range of each Health
structure:
Health structure | Frequency | Historical range |
---|---|---|
Sleep Summary | Each time CREATED , STARTED or RESUMED is triggered | 29 days in the past until yesterday |
Body Summary | Each time CREATED , STARTED or RESUMED is triggered | 29 days in the past until yesterday |
Physical Summary | Each time CREATED , STARTED or RESUMED is triggered | 29 days in the past until yesterday |
Physical Activity | Each time CREATED , STARTED or RESUMED is triggered | 29 days in the past until today |
Steps | Each time CREATED , STARTED or RESUMED is triggered | Today |
To create a RookYesterdaySync
instance use the rookYesterdaySync
delegate providing:
- enableLogs: See the logs generated by this SDK.
- state: Lifecycle state to trigger the sync process at. Supported values:
CREATED
(Default),STARTED
,RESUMED
.
class HomeActivity : AppCompatActivity() {
private val rookYesterdaySync by rookYesterdaySync(
enableLogs = true,
state = Lifecycle.State.CREATED,
)
override fun onCreate(savedInstanceState: Bundle?) {
// Must be before super.onCreate(savedInstanceState)
// Using userAcceptedYesterdaySync we ensure to enable the YesterdaySync feature only if the user accepted it
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && homeViewModel.userAcceptedYesterdaySync) {
rookYesterdaySync.enable(this)
}
super.onCreate(savedInstanceState)
}
}
We recommend you to ask your users if they want to enable this behaviour, then save their preference in local storage
and call enable
conditionally.
Once started rookYesterdaySync
will attempt to sync all historic data, and it will shut down itself after it
finishes or until the Health Connect request quota is
exceeded.
rookYesterdaySync
is intended to be used once in your app, if your app has multiple activities, try to
configure rookYesterdaySync
in the Home/Main activity that you display when your app's users are logged in.
Permissions
To use rookYesterdaySync
you will need:
- Health Connect permissions: Go to the main Health Connect Permissions section to see the implementation.
- Android permissions: Go to the main Android Permissions section to see the implementation.
rookYesterdaySync
also requires a user id, so it's possible that the
first time you launch your app nothing will happen, only after a user id is configured and all necessary permissions are
granted the automatic sync will happen the next time the app is launched.
Customizing the foreground service notification
To sync health data automatically a Foreground Service is used, this service requires a notification to be displayed until the synchronization finishes.
The notification has the next default values:
- Icon
- Title: Sync service
- Content: Syncing your health data…
To use your own resources you need to reference them in the AndroidManifest.xml file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<meta-data
android:name="io.tryrook.service.notification.SYNC_ICON"
android:resource="@drawable/my_custom_icon"/>
<meta-data
android:name="io.tryrook.service.notification.SYNC_TITLE"
android:resource="@string/my_custom_title"/>
<meta-data
android:name="io.tryrook.service.notification.SYNC_CONTENT"
android:resource="@string/my_custom_content"/>
</application>
</manifest>
Starting on Android 13 (SDK 33) this notification can be dismissed without finishing the service associated with it, then the service will be displayed in the active apps section (This may vary depending on device brand).
Launch/Stop conditions
rookYesterdaySync
won't start or will stop if one the following conditions is true:
- The device battery is low.
- The device storage is low.
- The device is not connected to the internet.
- The userID hasn't been configured.
- The most recent request exceeded the Health Connect request quota.
- The device has previously exceeded the Health Connect request quota and less than 60 minutes have passed.
- The user hasn't granted Health Connect Permissions.
- There is an error initializing the SDK.
- The user hasn't granted Android Permissions.