Shiny.Health.Extensions.AI
2.0.0-beta-0003
Prefix Reserved
dotnet add package Shiny.Health.Extensions.AI --version 2.0.0-beta-0003
NuGet\Install-Package Shiny.Health.Extensions.AI -Version 2.0.0-beta-0003
<PackageReference Include="Shiny.Health.Extensions.AI" Version="2.0.0-beta-0003" />
<PackageVersion Include="Shiny.Health.Extensions.AI" Version="2.0.0-beta-0003" />
<PackageReference Include="Shiny.Health.Extensions.AI" />
paket add Shiny.Health.Extensions.AI --version 2.0.0-beta-0003
#r "nuget: Shiny.Health.Extensions.AI, 2.0.0-beta-0003"
#:package Shiny.Health.Extensions.AI@2.0.0-beta-0003
#addin nuget:?package=Shiny.Health.Extensions.AI&version=2.0.0-beta-0003&prerelease
#tool nuget:?package=Shiny.Health.Extensions.AI&version=2.0.0-beta-0003&prerelease
Shiny Health
Apple HealthKit and Android Health Connect for your .NET MAUI apps.
Features
- Read summary values between timestamps at specified intervals
- Write health data to Apple HealthKit and Android Health Connect
- Real-time observation of health data changes via
IAsyncEnumerable<HealthResult> - 30+ cross-platform data types covering activity, body, vitals, nutrition, reproductive/cycle tracking, and workouts
- Query activity (distance, step count, calories, active/basal energy, floors climbed, wheelchair pushes, speed, power) and heart rate (average, resting, variability)
- Query body metrics (weight, height, body fat, lean body mass) and vitals (blood pressure, oxygen saturation, blood glucose, body temperature, respiratory rate, VO2 max)
- Query lifestyle (sleep duration, hydration, nutrition) and workouts/exercise sessions
- Reproductive & cycle tracking (menstruation flow, sexual activity, ovulation tests, cervical mucus, intermenstrual bleeding)
- Permission management for both platforms with read/write support
How To Use
IHealthService health; // inject via DI
// request read permissions
var result = await health.RequestPermissions(
DataType.Calories,
DataType.Distance,
DataType.StepCount,
DataType.HeartRate
);
// request per-metric read/write permissions in a single call
var result2 = await health.RequestPermissions(
(PermissionType.Read, DataType.StepCount),
(PermissionType.Read, DataType.HeartRate),
(PermissionType.Write, DataType.Weight),
(PermissionType.ReadWrite, DataType.BloodPressure)
);
var end = DateTimeOffset.Now;
var start = DateTimeOffset.Now.AddDays(-1);
// query data
var distance = (await health.GetDistances(start, end, Interval.Days)).Sum(x => x.Value);
var calories = (await health.GetCalories(start, end, Interval.Days)).Sum(x => x.Value);
var steps = (await health.GetStepCounts(start, end, Interval.Days)).Sum(x => x.Value);
var heartRate = (await health.GetAverageHeartRate(start, end, Interval.Days)).Average(x => x.Value);
// body metrics
var weight = (await health.GetWeight(start, end, Interval.Days)).Average(x => x.Value); // kg
var height = (await health.GetHeight(start, end, Interval.Days)).Average(x => x.Value); // meters
var bodyFat = (await health.GetBodyFatPercentage(start, end, Interval.Days)).Average(x => x.Value); // %
var restingHr = (await health.GetRestingHeartRate(start, end, Interval.Days)).Average(x => x.Value); // bpm
// vitals
var o2 = (await health.GetOxygenSaturation(start, end, Interval.Days)).Average(x => x.Value); // %
var bp = await health.GetBloodPressure(start, end, Interval.Days); // BloodPressureResult with Systolic/Diastolic (mmHg)
// lifestyle
var sleep = (await health.GetSleepDuration(start, end, Interval.Days)).Sum(x => x.Value); // hours
var water = (await health.GetHydration(start, end, Interval.Days)).Sum(x => x.Value); // liters
// --- Writing Data ---
// request write permissions (uniform)
await health.RequestPermissions(PermissionType.Write, DataType.Weight, DataType.StepCount, DataType.Hydration);
// or mix read/write per metric
await health.RequestPermissions(
(PermissionType.Write, DataType.Weight),
(PermissionType.ReadWrite, DataType.Hydration)
);
// write a weight measurement
await health.Write(new NumericHealthResult(DataType.Weight, DateTimeOffset.Now, DateTimeOffset.Now, 75.0)); // kg
// write step counts over a time range
await health.Write(new NumericHealthResult(DataType.StepCount, start, end, 500));
// write hydration
await health.Write(new NumericHealthResult(DataType.Hydration, start, end, 0.5)); // liters
// write blood pressure
await health.Write(new BloodPressureResult(DateTimeOffset.Now, DateTimeOffset.Now, 120.0, 80.0)); // mmHg
// --- Observing Real-Time Changes ---
// observe heart rate changes as they arrive
using var cts = new CancellationTokenSource();
await foreach (var result in health.Observe(DataType.HeartRate, cancelToken: cts.Token))
{
if (result is NumericHealthResult numeric)
Console.WriteLine($"Heart rate: {numeric.Value} bpm at {numeric.Start:T}");
}
// observe with custom polling interval (Android only, iOS ignores this - it's push-based)
await foreach (var result in health.Observe(DataType.StepCount, pollingInterval: TimeSpan.FromSeconds(10), cancelToken: cts.Token))
{
if (result is NumericHealthResult numeric)
Console.WriteLine($"Steps: {numeric.Value}");
}
Supported Metrics
| Metric | Unit | iOS (HealthKit) | Android (Health Connect) |
|---|---|---|---|
| Step Count | count | StepCount | StepsRecord |
| Heart Rate | bpm | HeartRate | HeartRateRecord |
| Calories | kcal | ActiveEnergyBurned | TotalCaloriesBurnedRecord |
| Distance | meters | DistanceWalkingRunning | DistanceRecord |
| Weight | kg | BodyMass | WeightRecord |
| Height | meters | Height | HeightRecord |
| Body Fat % | % | BodyFatPercentage | BodyFatRecord |
| Resting Heart Rate | bpm | RestingHeartRate | RestingHeartRateRecord |
| Blood Pressure | mmHg | BloodPressureSystolic/Diastolic | BloodPressureRecord |
| Oxygen Saturation | % | OxygenSaturation | OxygenSaturationRecord |
| Sleep Duration | hours | SleepAnalysis | SleepSessionRecord |
| Hydration | liters | DietaryWater | HydrationRecord |
| Blood Glucose | mg/dL | BloodGlucose | BloodGlucoseRecord |
| Body Temperature | °C | BodyTemperature | BodyTemperatureRecord |
| Basal Body Temperature | °C | BasalBodyTemperature | BasalBodyTemperatureRecord |
| Respiratory Rate | breaths/min | RespiratoryRate | RespiratoryRateRecord |
| VO2 Max | mL/kg/min | VO2Max | Vo2MaxRecord |
| Heart Rate Variability | ms | HeartRateVariabilitySDNN | HeartRateVariabilityRmssdRecord¹ |
| Lean Body Mass | kg | LeanBodyMass | LeanBodyMassRecord |
| Basal Energy Burned | kcal | BasalEnergyBurned | BasalMetabolicRateRecord |
| Active Energy Burned | kcal | ActiveEnergyBurned | ActiveCaloriesBurnedRecord |
| Floors Climbed | count | FlightsClimbed | FloorsClimbedRecord |
| Wheelchair Pushes | count | PushCount | WheelchairPushesRecord |
| Speed | m/s | WalkingSpeed² | SpeedRecord |
| Power | watts | CyclingPower² | PowerRecord |
| Menstruation Flow | flow level | MenstrualFlow | MenstruationFlowRecord |
| Sexual Activity | protection enum | SexualActivity | SexualActivityRecord |
| Ovulation Test | result enum | OvulationTestResult | OvulationTestRecord |
| Cervical Mucus | appearance enum | CervicalMucusQuality | CervicalMucusRecord |
| Intermenstrual Bleeding | event | IntermenstrualBleeding | IntermenstrualBleedingRecord |
| Workout | session | HKWorkout | ExerciseSessionRecord |
| Nutrition | food/macros | Food correlation | NutritionRecord |
¹ HealthKit reports HRV as SDNN while Health Connect reports RMSSD — both are in milliseconds but computed differently, so values are not directly comparable across platforms.
² Health Connect's
SpeedRecord/PowerRecordare generic. HealthKit has no generic equivalents, soSpeedmaps to walking speed andPowermaps to cycling power.
Categorical / event-based / structured metrics (menstruation flow, sexual activity, ovulation tests, cervical mucus, intermenstrual bleeding, workouts, nutrition) are not numeric. Each uses its own result record (e.g.
MenstruationFlowResult,SexualActivityResult,WorkoutResult,NutritionResult), has noIntervalbucketing, and is read via a dedicated method (GetMenstruationFlow,GetSexualActivity,GetOvulationTests,GetCervicalMucus,GetIntermenstrualBleeding,GetWorkouts,GetNutrition). TheMenstrualFlow.Nonelevel andIsCycleStartflag are iOS-only; Health Connect has noNonevalue and ignoresIsCycleStart. AWorkoutResult's energy/distance arenullon Android read (Health Connect stores them as separate records from the exercise session).
AI Tools
Shiny.Health.Extensions.AI exposes IHealthService as Microsoft.Extensions.AI tool functions for LLM agents. It uses a few parameterized tools (one read tool covers all numeric metrics via a metric enum, instead of one tool per metric) so the model's tool list stays short. Opt-in exactly which areas the model can see — read-only by default, write per-area. Resolve HealthAITools from DI and pass .Tools to any IChatClient. AOT-compatible.
dotnet add package Shiny.Health.Extensions.AI
using Shiny.Health.Extensions.AI;
builder.Services.AddHealthIntegration();
builder.Services.AddHealthAITools(tools => tools
.AddAllMetrics() // read every numeric metric
.AddMetric(DataType.Weight, HealthAICapabilities.ReadWrite)
.AddBloodPressure(HealthAICapabilities.ReadWrite)
.AddCycleTracking()
.AddWorkouts(HealthAICapabilities.ReadWrite)
.AddNutrition()
);
// later, hand the tools to a chat client
var tools = sp.GetRequiredService<HealthAITools>().Tools;
var response = await chatClient.GetResponseAsync(
messages,
new ChatOptions { Tools = [.. tools] }
);
Generated tools (only for areas you opt-in to): get_health_metric / write_health_metric, get_blood_pressure / write_blood_pressure, get_cycle_records / write_menstruation_flow, get_workouts / write_workout, get_nutrition / write_nutrition. The tools assume permissions are already granted — call RequestPermissions from your app first.
Setup
dotnet add package Shiny.Health
In your MauiProgram.cs:
public static MauiApp CreateMauiApp()
{
var builder = MauiApp
.CreateBuilder()
.UseMauiApp<App>()
.UseShiny();
builder.Services.AddHealthIntegration();
return builder.Build();
}
iOS Setup
Your app requires a provisioning profile with HealthKit capabilities enabled.
Info.plist
<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
<key>com.apple.developer.healthkit</key>
<true />
<key>com.apple.developer.healthkit.background-delivery</key>
<true />
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
<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_ENERGY_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.ACTIVITY_RECOGNITION" />
<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_ENERGY_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" />
<queries>
<package android:name="com.google.android.apps.healthdata" />
</queries>
Requirements
- The Health Connect app must be installed on the device
- Minimum SDK version must be set to 28 (Android 9)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.AI.Abstractions (>= 10.5.2)
- Shiny.Health (>= 2.0.0-beta-0003)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-beta-0003 | 0 | 6/15/2026 |