Shiny.Health
1.1.0
Prefix Reserved
See the version list below for details.
dotnet add package Shiny.Health --version 1.1.0
NuGet\Install-Package Shiny.Health -Version 1.1.0
<PackageReference Include="Shiny.Health" Version="1.1.0" />
<PackageVersion Include="Shiny.Health" Version="1.1.0" />
<PackageReference Include="Shiny.Health" />
paket add Shiny.Health --version 1.1.0
#r "nuget: Shiny.Health, 1.1.0"
#:package Shiny.Health@1.1.0
#addin nuget:?package=Shiny.Health&version=1.1.0
#tool nuget:?package=Shiny.Health&version=1.1.0
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> - Query distance, step count, calories, and heart rate
- Query weight, height, body fat percentage, and resting heart rate
- Query blood pressure (systolic/diastolic), oxygen saturation, sleep duration, and hydration
- 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 |
| Menstruation Flow | flow level | MenstrualFlow | MenstruationFlowRecord |
Menstruation flow is categorical and event-based rather than numeric. It uses
MenstruationFlowResult/MenstrualFlow, is read viaGetMenstruationFlow(start, end)(no interval bucketing), and written withWrite(MenstruationFlowResult). TheNoneflow level andIsCycleStartflag are iOS-only; Health Connect has noNonevalue and ignoresIsCycleStart.
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-android36.0 is compatible. net10.0-browser was computed. net10.0-ios was computed. net10.0-ios26.0 is compatible. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Shiny.Core (>= 4.0.1)
-
net10.0-android36.0
- Shiny.Core (>= 4.0.1)
- Xamarin.AndroidX.Health.Connect.ConnectClient (>= 1.1.0.2)
- Xamarin.AndroidX.Lifecycle.LiveData.Core (>= 2.10.0.2)
-
net10.0-ios26.0
- Shiny.Core (>= 4.0.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Shiny.Health:
| Package | Downloads |
|---|---|
|
Shiny.Health.Extensions.AI
Microsoft.Extensions.AI tool surface for Shiny.Health — exposes IHealthService reads/writes as AIFunction tools for LLM tool-calling. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-beta-0004 | 44 | 6/17/2026 |
| 2.0.0-beta-0003 | 63 | 6/15/2026 |
| 2.0.0-beta-0002 | 55 | 6/15/2026 |
| 1.1.0 | 60 | 6/15/2026 |
| 1.1.0-beta-0001 | 51 | 6/15/2026 |
| 1.0.0 | 145 | 5/3/2026 |
| 1.0.0-beta-0033 | 92 | 5/2/2026 |
| 1.0.0-beta-0032 | 101 | 5/1/2026 |
| 1.0.0-beta-0030 | 109 | 4/27/2026 |
| 1.0.0-beta-0029 | 91 | 4/27/2026 |
| 1.0.0-beta-0028 | 99 | 4/26/2026 |
| 1.0.0-beta-0027 | 90 | 4/23/2026 |
| 1.0.0-beta-0026 | 93 | 4/23/2026 |
| 1.0.0-beta-0025 | 95 | 4/22/2026 |
| 1.0.0-beta-0024 | 94 | 4/22/2026 |
| 1.0.0-beta-0021 | 419 | 12/14/2023 |
| 1.0.0-beta-0020 | 211 | 12/5/2023 |
| 1.0.0-beta-0018 | 573 | 11/27/2023 |
| 1.0.0-beta-0013 | 263 | 10/4/2023 |
| 1.0.0-beta-0012 | 187 | 10/4/2023 |