Field-reported on the alpha APK: the Samsung/Pixel row failed with
'Health permissions were denied' without ever showing a dialog, and the
Google Health connect reported the same error despite a successful OAuth.
- MainActivity now extends FlutterFragmentActivity: package:health v13
casts the host activity to androidx ComponentActivity to call
registerForActivityResult, so with plain FlutterActivity the permission
launcher stayed null and requestAuthorization() silently returned false
(HealthPlugin.kt:317 'Permission launcher not found')
- add the androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE intent-filter
required by the health package README on the main activity
- drop STEPS / READ_STEPS from the Android permission set: steps are never
fetched anywhere and the README ties step access to ACTIVITY_RECOGNITION,
which this app does not declare (weight, total + active calories, blood
glucose remain, all declared in the manifest)
- syncFromHealth treats a native permission denial as fatal only when no
cloud partner holds a grant, so a Google Health-connected sync proceeds
without the OS permission (native reads degrade to empty)
- tests: biometric controller covers native-denial + cloud-ready sync
(cloudReady fake override); suite 185/185, analyze clean, debug APK
builds (also clears the standing flutter build apk --debug gate)
- BUILD_STATE: record both fixes, check off the Android OAuth client and
connect gates, add the Health Connect on-device verification gate
Cloud connector framework: ICloudHealthConnector contract, supportsCloudSync / isCloudSyncReady on IHealthGateway, and a HealthProviderType.googleHealth slot; a conditional-import shim (io implementation / web stub) keeps platform channels out of web builds.
Google Health connector (successor to the retired Fitbit Web API, shutdown 2026-10-30): OAuth2 authorization-code + PKCE through the system browser with a loopback redirect; read-only activity-and-fitness + health-metrics scopes; tokens in flutter_secure_storage with transparent refresh; paginated weight and active-energy-burned dataPoints reads with kg-to-lb normalization from the per-point unit field; pure unit-tested parsers.
Gateway wiring: both drivers store injected connectors (desktop runs MobileHealthGateway through the io conditional import; the fallback driver is web-only); cloud status/authorize/disconnect route first and reads merge native + cloud non-fatally; syncFromHealth accepts cloud-only sources and imports persist as BiometricSource.cloudSync.
UI: Google Health row in Settings with Connect/Disconnect and auto-import on connect; explanatory desktop copy on the Apple Health and Health Connect rows; the Nutrition weight card syncs through a connected cloud partner and surfaces the outcome as a snackbar, degrading to the manual dialog when no source is connected.
Field fixes recorded in BUILD_STATE: io-driver connector wiring, duplicate-implementation merge correction, weight-card sync gate. Tests: google_health_parser_test suite; settings_screen_test updated for the fourth integration row. The legacy Fitbit connector was fully removed before shipping.