Skip to main content

shiny-health

Generate cross-platform health data queries, write health data, and observe real-time health changes using Shiny Health for Apple HealthKit and Android Health Connect

Jump to install

Source facts

Repository
shinyorg/Health
Last source activity
August 5, 2026 at 19:27
Detected SKILL.md language
English
Stars
13
Forks
3

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
shiny-health
description
Generate cross-platform health data queries, write health data, and observe real-time health changes using Shiny Health for Apple HealthKit and Android Health Connect
auto_invoke
true
triggers
["health data","health kit","healthkit","health connect","step count","heart rate","calories","distance","weight","height","body fat","blood pressure","oxygen saturation","sleep duration","hydration","resting heart rate","health metrics","health permissions","IHealthService","DataType","NumericHealthResult","BloodPressureResult","HealthResult","GetStepCounts","GetCalories","GetDistances","GetAverageHeartRate","GetWeight","GetHeight","GetBodyFatPercentage","GetRestingHeartRate","GetBloodPressure","[Truncated]"]
# Shiny Health Skill You are an expert in Shiny Health, a .NET MAUI library that provides a unified API for reading and writing health data from Apple HealthKit (iOS) and Android Health Connect. ## When to Use This Skill Invoke this skill when the user wants to: - Query health metrics (steps, heart rate, calories, distance, weight, height, body fat, blood pressure, oxygen saturation, sleep, hydration) - Write/log health data (steps, weight, hydration, blood pressure, etc.) - Observe real-time health data changes (e.g., monitor step counts or heart rate as they are recorded) - Set up health data access in a .NET MAUI application - Request health data permissions (read and/or write) on iOS or Android - Work with time-bucketed health data aggregations - Understand which health metrics are available cross-platform - Configure iOS HealthKit entitlements or Android Health Connect permissions ## Library Overview **GitHub**: https://github.com/shinyorg/health **NuGet**: `Shiny.Health` **Namespace**: `Shiny.Health` Shiny Health provides: - A single `IHealthService` interface that works on both iOS and Android - Read and write support for 30+ cross-platform health metrics spanning activity, body, vitals, nutrition, reproductive/cycle tracking, and workouts - Real-time observation of health data changes via `IAsyncEnumerable<HealthResult>` - Time-bucketed aggregate queries at minute, hour, or day intervals - Permission management with read/write granularity via `PermissionType` - AOT-compatible implementation (no .NET reflection) ## Setup ### 1. Install NuGet Package ```bash dotnet add package Shiny.Health ``` ### 2. Configure in MauiProgram.cs ```csharp public static MauiApp CreateMauiApp() { var builder = MauiApp .CreateBuilder() .UseMauiApp<App>() .UseShiny(); builder.Services.AddHealthIntegration(); return builder.Build(); } ``` ### 3. iOS Setup Your app requires a provisioning profile with HealthKit capabilities enabled. **Info.plist:** ```xml <key>UIRequiredDeviceCapabilities</key> <array> <string>healthkit</string> </array> <key>NSHealthUpdateUsageDescription</key> <string>We need access to update your health data</string> <key>NSHealthShareUsageDescription</key> <string>We need access to read your health data</string> ``` **Entitlements.plist:** ```xml <key>com.apple.developer.healthkit</key> <true /> <key>com.apple.developer.healthkit.background-delivery</key> <true /> ``` ### 4. Android Setup (Health Connect) Android uses Health Connect (the replacement for the deprecated Google Fit API). Health Connect requires Android 9 (API 28) or higher. **AndroidManifest.xml:** ```xml <!-- Declare which health data your app reads (only include the types you use) --> <uses-permission android:name="android.permission.health.READ_STEPS" /> <uses-permission android:name="android.permission.health.READ_HEART_RATE" /> <uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED" /> <uses-permission android:name="android.permission.health.READ_DISTANCE" /> <uses-permission android:name="android.permission.health.READ_WEIGHT" /> <uses-permission android:name="android.permission.health.READ_HEIGHT" /> <uses-permission android:name="android.permission.health.READ_BODY_FAT" /> <uses-permission android:name="android.permission.health.READ_RESTING_HEART_RATE" /> <uses-permission android:name="android.permission.health.READ_BLOOD_PRESSURE" /> <uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION" /> <uses-permission android:name="android.permission.health.READ_SLEEP" /> <uses-permission android:name="android.permission.health.READ_HYDRATION" /> <uses-permission android:name="android.permission.health.READ_MENSTRUATION" /> <uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE" /> <uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE" /> <uses-permission android:name="android.permission.health.READ_BASAL_BODY_TEMPERATURE" /> <uses-permission android:name="android.permission.health.READ_RESPIRATORY_RATE" /> <uses-permission android:name="android.permission.health.READ_VO2_MAX" /> <uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY" /> <uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS" /> <uses-permission android:name="android.permission.health.READ_BASAL_METABOLIC_RATE" /> <uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED" /> <uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" /> <uses-permission android:name="android.permission.health.READ_WHEELCHAIR_PUSHES" /> <uses-permission android:name="android.permission.health.READ_SPEED" /> <uses-permission android:name="android.permission.health.READ_POWER" /> <uses-permission android:name="android.permission.health.READ_SEXUAL_ACTIVITY" /> <uses-permission android:name="android.permission.health.READ_OVULATION_TEST" /> <uses-permission android:name="android.permission.health.READ_CERVICAL_MUCUS" /> <uses-permission android:name="android.permission.health.READ_INTERMENSTRUAL_BLEEDING" /> <uses-permission android:name="android.permission.health.READ_EXERCISE" /> <uses-permission android:name="android.permission.health.READ_NUTRITION" /> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" /> <!-- Optional: declare which health data your app writes (only include the types you need) --> <uses-permission android:name="android.permission.health.WRITE_STEPS" /> <uses-permission android:name="android.permission.health.WRITE_HEART_RATE" /> <uses-permission android:name="android.permission.health.WRITE_TOTAL_CALORIES_BURNED" /> <uses-permission android:name="android.permission.health.WRITE_DISTANCE" /> <uses-permission android:name="android.permission.health.WRITE_WEIGHT" /> <uses-permission android:name="android.permission.health.WRITE_HEIGHT" /> <uses-permission android:name="android.permission.health.WRITE_BODY_FAT" /> <uses-permission android:name="android.permission.health.WRITE_RESTING_HEART_RATE" /> <uses-permission android:name="android.permission.health.WRITE_BLOOD_PRESSURE" /> <uses-permission android:name="android.permission.health.WRITE_OXYGEN_SATURATION" /> <uses-permission android:name="android.permission.health.WRITE_SLEEP" /> <uses-permission android:name="android.permission.health.WRITE_HYDRATION" /> <uses-permission android:name="android.permission.health.WRITE_MENSTRUATION" /> <uses-permission android:name="android.permission.health.WRITE_BLOOD_GLUCOSE" /> <uses-permission android:name="android.permission.health.WRITE_BODY_TEMPERATURE" /> <uses-permission android:name="android.permission.health.WRITE_BASAL_BODY_TEMPERATURE" /> <uses-permission android:name="android.permission.health.WRITE_RESPIRATORY_RATE" /> <uses-permission android:name="android.permission.health.WRITE_VO2_MAX" /> <uses-permission android:name="android.permission.health.WRITE_HEART_RATE_VARIABILITY" /> <uses-permission android:name="android.permission.health.WRITE_LEAN_BODY_MASS" /> <uses-permission android:name="android.permission.health.WRITE_BASAL_METABOLIC_RATE" /> <uses-permission android:name="android.permission.health.WRITE_ACTIVE_CALORIES_BURNED" /> <uses-permission android:name="android.permission.health.WRITE_FLOORS_CLIMBED" /> <uses-permission android:name="android.permission.health.WRITE_WHEELCHAIR_PUSHES" /> <uses-permission android:name="android.permission.health.WRITE_SPEED" /> <uses-permission android:name="android.permission.health.WRITE_POWER" /> <uses-permission android:name="android.permission.health.WRITE_SEXUAL_ACTIVITY" /> <uses-permission android:name="android.permission.health.WRITE_OVULATION_TEST" /> <uses-permission android:name="android.permission.health.WRITE_CERVICAL_MUCUS" /> <uses-permission android:name="android.permission.health.WRITE_INTERMENSTRUAL_BLEEDING" /> <uses-permission android:name="android.permission.health.WRITE_EXERCISE" /> <uses-permission android:name="android.permission.health.WRITE_NUTRITION" /> <!-- Allow your app to discover Health Connect --> <queries> <package android:name="com.google.android.apps.healthdata" /> </queries> <!-- REQUIRED on Android 14+ (API 34) where Health Connect is part of the platform. Without this alias Health Connect silently refuses to grant health permissions. android:targetActivity must match your MainActivity's android:name --> <application> <activity-alias android:name="ViewPermissionUsageActivity" android:exported="true" android:targetActivity="com.companyname.myapp.MainActivity" android:permission="android.permission.START_VIEW_PERMISSION_USAGE"> <intent-filter> <action android:name="android.intent.action.VIEW_PERMISSION_USAGE" /> <category android:name="android.intent.category.HEALTH_PERMISSIONS" /> </intent-filter> </activity-alias> </application> ``` **Platforms/Android/MainActivity.cs** — Health Connect links to your privacy policy from the permission dialog and will not grant permissions unless the activity handles the rationale action. Set an explicit `Name` so the `activity-alias` can target it: ```csharp [Activity( Name = "com.companyname.myapp.MainActivity", Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density )] [IntentFilter(["androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE"])] public class MainActivity : MauiAppCompatActivity { } ``` **Requirements:** - The Health Connect app must be installed on the device — on Android 14+ (API 34) it is built into the platform - Minimum SDK version must be set to **28** (Android 9) - Set `targetSdkVersion` to the platform you build against. An empty `<uses-sdk />` element suppresses it and falls back to `minSdkVersion`, which recent Android versions block at install time with "Unsafe app blocked - built for an older version of Android" - Permission names follow the **Health Connect record**, not the HealthKit type — `DataType.Calories` reads `TotalCaloriesBurnedRecord` and needs `READ_TOTAL_CALORIES_BURNED`. There is no `…_TOTAL_ENERGY_BURNED` permission on Android. A name Android does not recognize is silently unknown: it can never be granted and every read of that type fails - Never request health permissions with `Permissions.RequestAsync<>` or the AndroidX activity-result contracts directly — always go through `IHealthService.RequestPermissions`, which picks the right flow for the OS version ## API Reference ### Core Types ```csharp // Permission type for read/write access [Flags] public enum PermissionType { Read = 1, Write = 2, ReadWrite = Read | Write } // Time interval for bucketed queries public enum Interval { Minutes, Hours, Days } // Available health data types public enum DataType { // numeric (NumericHealthResult) StepCount, HeartRate, Calories, Distance, Weight, Height, BodyFatPercentage, RestingHeartRate, BloodPressure, OxygenSaturation, SleepDuration, Hydration, BloodGlucose, BodyTemperature, BasalBodyTemperature, RespiratoryRate, Vo2Max, HeartRateVariability, LeanBodyMass, BasalEnergyBurned, ActiveEnergyBurned, FloorsClimbed, WheelchairPushes, Speed, Power, // categorical / event-based MenstruationFlow, SexualActivity, OvulationTest, CervicalMucus, IntermenstrualBleeding, // structured records Workout, Nutrition } // Menstrual flow level (categorical). None is iOS-only; Android maps it to Unspecified. public enum MenstrualFlow { Unspecified, None, Light, Medium, Heavy } // Reproductive / cycle-tracking enums public enum SexualActivityProtection { Unspecified, Protected, Unprotected } public enum OvulationTestOutcome { Inconclusive, Positive, High, Negative } public enum CervicalMucusAppearance { Unspecified, Dry, Sticky, Creamy, Watery, EggWhite } // Workout activity (subset mapped on both platforms; unmapped -> Other) and meal type public enum WorkoutType { Other, Running, Walking, Hiking, Cycling, Swimming, Rowing, Elliptical, StairClimbing, StrengthTraining, HighIntensityIntervalTraining, Yoga, Pilates, Tennis, Basketball, Soccer, Baseball, Golf, Boxing, MartialArts, Dancing } public enum MealType { Unknown, Breakfast, Lunch, Dinner, Snack } // Categorical / structured result records public record SexualActivityResult(DateTimeOffset Start, DateTimeOffset End, SexualActivityProtection Protection) : HealthResult(DataType.SexualActivity, Start, End); public record OvulationTestResult(DateTimeOffset Start, DateTimeOffset End, OvulationTestOutcome Outcome) : HealthResult(DataType.OvulationTest, Start, End); public record CervicalMucusResult(DateTimeOffset Start, DateTimeOffset End, CervicalMucusAppearance Appearance) : HealthResult(DataType.CervicalMucus, Start, End); public record IntermenstrualBleedingResult(DateTimeOffset Start, DateTimeOffset End) : HealthResult(DataType.IntermenstrualBleeding, Start, End); public record WorkoutResult(DateTimeOffset Start, DateTimeOffset End, WorkoutType Workout, double? TotalEnergyKilocalories = null, double? TotalDistanceMeters = null, string? Title = null) : HealthResult(DataType.Workout, Start, End); public record NutritionResult(DateTimeOffset Start, DateTimeOffset End, MealType Meal = MealType.Unknown, string? Name = null, double? EnergyKilocalories = null, double? ProteinGrams = null, double? CarbohydratesGrams = null, double? TotalFatGrams = null, double? FiberGrams = null, double? SugarGrams = null, double? SodiumGrams = null, double? CholesterolGrams = null) : HealthResult(DataType.Nutrition, Start, End); // Result for single-value metrics public record NumericHealthResult( DataType DataType, DateTimeOffset Start, DateTimeOffset End, double Value ) : HealthResult(DataType, Start, End); // Result for blood pressure (dual-value) public record BloodPressureResult( DateTimeOffset Start, DateTimeOffset End, double Systolic, double Diastolic ) : HealthResult(DataType.BloodPressure, Start, End); // Result for menstruation flow (categorical, event-based) // IsCycleStart marks the first day of the cycle (iOS only; always false on Android) public record MenstruationFlowResult( DateTimeOffset Start, DateTimeOffset End, MenstrualFlow Flow, bool IsCycleStart = false ) : HealthResult(DataType.MenstruationFlow, Start, End); ``` ### IHealthService Interface ```csharp public interface IHealthService { // True if the platform health store is usable (iOS: always; Android: Health Connect installed & SDK OK) bool IsAvailable { get; } // Observe real-time health data changes (forward-only, yields new samples as recorded) // iOS: push-based HKAnchoredObjectQuery; Android: polls Health Connect change tokens
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub