8000 feat(app): export glucose readings to Apple Health (HealthKit) by shroominic · Pull Request #10 · shroominic/OpenGlucose · GitHub
[go: up one dir, main page]

Skip to content

feat(app): export glucose readings to Apple Health (HealthKit) - #10

Merged
shroominic merged 2 commits into
mainfrom
feat/healthkit-export
Aug 12, 2026
Merged

shroominic merged 2 commits into
mainfrom
feat/healthkit-export

Conversation

@shroominic
Copy link
Copy Markdown
Owner

Summary

Adds an opt-in Apple Health export: the app writes its CgmReadings to HealthKit as HKQuantityTypeIdentifierBloodGlucose samples (mg/dL). Wellness / self-experimentation framing — no medical claims, no interpretation, nothing leaves the device unless the user turns it on.

Stacked on #4 (feat/sim-demo-mode) — please merge that first. This branch was cut from feat/sim-demo-mode and targets it as base.

Approach: package vs platform channel

Used the maintained health package (^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 by Platform.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.dart
    • HealthKitExportService (implements a small GlucoseExporter interface for testability): configure → request authorization → write blood-glucose samples.
    • HealthExportController (ChangeNotifier): owns the opt-in + last-synced state, persisted in SharedPreferences. 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.
  • Tests — test/healthkit_export_test.dart covers 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 via CODE_SIGN_ENTITLEMENTS on all three Runner build configs (Debug/Release/Profile).
  • ios/Runner/Info.plist — NSHealthUpdateUsageDescription and NSHealthShareUsageDescription strings.
  • iOS deployment target 13 → 14 (health plugin minimum; the Live Activity feature already required 16.1).

Android

  • minSdk bumped 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 analyze clean (only a pre-existing lint in live_activity_payload.dart).
  • flutter test — all 23 pass.
  • flutter build ios --simulator --debug clean; flutter build apk --debug clean.
  • Ran with --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):

  • Integrations tab UI: /tmp/og-hk-integrations-pane.png
  • HealthKit permission sheet: /tmp/og-healthkit.png

iOS 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_TEAM is already YLK778Z528). This is a deploy-time signing step — no code change needed.

🤖 Generated with Claude Code

shroominic and others added 2 commits June 23, 2026 19:24
…ator testing

Add a compile-time OG_DEMO build flag (--dart-define=OG_DEMO=true) so
native/simulator builds run the in-memory DemoCgmDriver instead of the
real BLE Aidex driver, and auto-scan + auto-connect on launch so the app
lands directly on the populated dashboard. The iOS simulator has no
Bluetooth, so this unblocks simulator-based feature verification.

When the flag is false (the default), behavior is unchanged: production
builds keep using the real AidexSensorDriver and the manual scan flow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
@shroominic
shroominic changed the base branch from feat/sim-demo-mode to main August 12, 2026 17:22
@shroominic
shroominic merged commit 6fea6d8 into main Aug 12, 2026
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.

1 participant

0