feat(app): export glucose readings to Apple Health (HealthKit) - #10
Open
shroominic wants to merge 1 commit into
Open
feat(app): export glucose readings to Apple Health (HealthKit)#10shroominic wants to merge 1 commit into
shroominic wants to merge 1 commit into
Conversation
Add an opt-in Apple Health integration that writes the app's CgmReadings
to HealthKit as HKQuantityTypeIdentifierBloodGlucose samples (mg/dL).
- HealthKitExportService wraps the `health` package: configures, requests
authorization, and writes blood-glucose samples. iOS-only (Platform.isIOS);
short-circuits everywhere else so Android is unaffected.
- HealthExportController owns the opt-in + last-synced state (persisted via
SharedPreferences) and runs incremental syncs using a recorded-time
watermark so repeated taps don't duplicate samples.
- New "Integrations" tab in the settings sheet with an "Export to Apple
Health" toggle, "Sync now", reading count, and last-synced state. Writes
are gated behind explicit user opt-in. Wellness framing, no medical claims.
- iOS: add HealthKit entitlement (Runner.entitlements + CODE_SIGN_ENTITLEMENTS
on all Runner configs) and NSHealth{Share,Update}UsageDescription strings.
Bump iOS deployment target 13 -> 14 (health plugin minimum).
- Android: bump minSdk to 26 (Health Connect minimum pulled in by the plugin).
Tests: unit coverage for opt-in/auth-decline/incremental-sync/unsupported via
an injected fake exporter. flutter analyze clean; flutter test green; iOS
simulator + Android debug builds pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an opt-in Apple Health export: the app writes its
CgmReadings to HealthKit asHKQuantityTypeIdentifierBloodGlucosesamples (mg/dL). Wellness / self-experimentation framing — no medical claims, no interpretation, nothing leaves the device unless the user turns it on.Approach: package vs platform channel
Used the maintained
healthpackage (^13.3.1) rather than a hand-rolled platform channel. It is the idiomatic, lowest-risk path — it ships the native HealthKit bridge, authorization flow, and unit handling, so the Dart side stays thin and there's no Swift to maintain. All HealthKit calls are guarded byPlatform.isIOS; on every other platform the service short-circuits (the Integrations card shows "only available on iOS"), so Android is unaffected at runtime.What's included
lib/src/healthkit_export.dartHealthKitExportService(implements a smallGlucoseExporterinterface for testability): configure → request authorization → write blood-glucose samples.HealthExportController(ChangeNotifier): owns the opt-in + last-synced state, persisted inSharedPreferences. Incremental syncs use a recorded-time watermark so repeated "Sync now" taps don't duplicate samples.lib/src/integrations_settings_pane.dart— new Integrations tab in the settings sheet: "Export to Apple Health" toggle, "Sync now", reading count, last-synced state. The toggle triggers the HealthKit auth sheet; the actual write is gated behind opt-in. Diff to the shared settings widget (main.dart) is minimal and clearly delimited (--- BEGIN/END Integrations tab ---); the Developer tab is untouched.test/healthkit_export_test.dartcovers opt-in persistence, declined authorization, incremental sync watermarking, and the unsupported-platform path via an injected fake exporter.iOS native changes (entitlement + plist)
ios/Runner/Runner.entitlements(new) —com.apple.developer.healthkit = true, wired viaCODE_SIGN_ENTITLEMENTSon all three Runner build configs (Debug/Release/Profile).ios/Runner/Info.plist—NSHealthUpdateUsageDescriptionandNSHealthShareUsageDescriptionstrings.Android
minSdkbumped to 26 (Health Connect minimum pulled in by the plugin). No Android Health permissions are requested at runtime since the Dart service is iOS-gated.Verification (iPhone 15 Pro Max simulator)
flutter analyzeclean (only a pre-existing lint inlive_activity_payload.dart).flutter test— all 23 pass.flutter build ios --simulator --debugclean;flutter build apk --debugclean.--dart-define=OG_DEMO=true, opened Settings → Integrations, and triggered the toggle. The native HealthKit authorization sheet appears requesting Blood Glucose write access (showing the Info.plist usage description), and the auth + export code path runs with no errors in the logs.Screenshots captured locally (not embeddable in a gh PR body):
/tmp/og-hk-integrations-pane.png/tmp/og-healthkit.pngiOS signing caveat for a real device
The simulator HealthKit store accepts the auth/write path without a provisioning profile. For a real device, the HealthKit capability must be enabled on the App ID in the Apple Developer portal and included in the provisioning profile that signs
Runner(DEVELOPMENT_TEAMis alreadyYLK778Z528). This is a deploy-time signing step — no code change needed.🤖 Generated with Claude Code