Skip to content

Health: Google Health Connect and Apple Health sync support#132

Merged
sjp4 merged 7 commits intocoredevices:masterfrom
michaelthatsit:master
Apr 8, 2026
Merged

Health: Google Health Connect and Apple Health sync support#132
sjp4 merged 7 commits intocoredevices:masterfrom
michaelthatsit:master

Conversation

@michaelthatsit
Copy link
Copy Markdown
Contributor

Implemented with the help of Claude and HealthKMP!

  • added sync for steps, hr, sleep, workouts
  • sync in background, on launch, app wake, and connect
  • added HealthSyncInterval for background sync

@michaelthatsit
Copy link
Copy Markdown
Contributor Author

image

Workouts show up in Apple fitness automatically!

@michaelthatsit
Copy link
Copy Markdown
Contributor Author

Addresses this issue: #76

@sjp4 ready for your review.

private val firestoreLocker: FirestoreLocker,
private val libPebble: LibPebble,
) : CoreBackgroundSync {
) : CoreBackgroundSync, KoinComponent {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't use KoinComponent / by inject() here - just add to the constructor parameters to inject (like libPebble etc)

firestoreLocker.init()
oneTimeSetLockerOrderMode()
// Health: request data from watch, sync to platform, and auto-sync on new data
libPebble.requestHealthData()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't do anything - there won't be any watches connected when the app starts

Comment on lines +127 to +129
platformHealthSync.sync()
}
platformHealthSync.startAutoSync(GlobalScope)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be merged in into one call

scope.launch {
appResumed.appResumed.collect {
libPebble.requestHealthData()
sync()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work (the sync will fire before health data has been collected - the suspending requestHealthData call only waits until the request has been ACKed). The sync call above from healthDataUpdated should handle this.

android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false">
</service>
<activity-alias
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this do?

}
}
healthSyncTracker.enabled = enabled
healthPlatformSyncEnabled = enabled
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this end up wrong if the user rejects the permission request?

return@launch
}
}
healthSyncTracker.enabled = enabled
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should manage this inside PlatformHealthSync (settings screen shouldn't know to have to track this)

topLevelType = TopLevelType.Phone,
section = Section.Health,
checked = healthPlatformSyncEnabled,
description = "Write steps, heart rate, sleep, and workouts to your phone's health platform",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add enabled = healthSettings.trackingEnabled (only show if health is enabled)

description = if (isSyncing) "Syncing..." else "Sync Pebble health data to phone",
topLevelType = TopLevelType.Phone,
section = Section.Health,
show = { healthPlatformSyncEnabled },
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&& healthSettings.trackingEnabled

expect fun makeTokenClipEntry(token: String): ClipEntry

object SettingsKeys {
const val KEY_HEALTH_PLATFORM_SYNC = "health_platform_sync_enabled"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not used?

michaelthatsit and others added 7 commits April 7, 2026 13:35
background syncing.

apple health and google health connect integration complete.

added open workouts to health sync.

fix sleep data sync.

# Conflicts:
#	composeApp/src/commonMain/kotlin/coredevices/coreapp/CommonAppDelegate.kt
#	composeApp/src/commonMain/kotlin/coredevices/coreapp/di/utilModule.kt
#	gradle/libs.versions.toml
#	pebble/src/commonMain/kotlin/coredevices/pebble/ui/WatchSettingsScreen.kt

# Conflicts:
#	composeApp/src/commonMain/kotlin/coredevices/coreapp/ui/screens/OnboardingScreen.kt
It never returned success because WRITE_EXERCISE_ROUTE is implicitly requested and wasn't in the manifest
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ michaelthatsit
❌ sjp4
You have signed the CLA already but the status is still pending? Let us recheck it.

@sjp4 sjp4 merged commit a387666 into coredevices:master Apr 8, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants