Shiny .NET v4 is here with BLE Windows Support, Improved GPS, & More! Check It Out
Getting Started
Frameworks
.NET MAUI
Operating Systems
Android
iOS
Shiny Health provides a unified API for querying health data from Apple HealthKit (iOS) and Android Health Connect. It supports permission management, time-bucketed aggregate queries, and 12 cross-platform health metrics.
Features
Section titled “Features”- Single
IHealthServiceinterface that works on both iOS and Android - 12 cross-platform health metrics — activity, body, vitals, and lifestyle
- Time-bucketed aggregate queries at minute, hour, or day intervals
- Permission management for both platforms
- AOT-compatible implementation (no .NET reflection)
- Blood pressure returns a dedicated
BloodPressureResultwith separate systolic/diastolic values
Supported Metrics
Section titled “Supported Metrics”| Metric | Unit | iOS (HealthKit) | Android (Health Connect) |
|---|---|---|---|
| Step Count | count | HKQuantityType.StepCount | StepsRecord |
| Heart Rate | bpm | HKQuantityType.HeartRate | HeartRateRecord |
| Calories | kcal | HKQuantityType.ActiveEnergyBurned | TotalCaloriesBurnedRecord |
| Distance | meters | HKQuantityType.DistanceWalkingRunning | DistanceRecord |
| Weight | kg | HKQuantityType.BodyMass | WeightRecord |
| Height | meters | HKQuantityType.Height | HeightRecord |
| Body Fat % | % | HKQuantityType.BodyFatPercentage | BodyFatRecord |
| Resting Heart Rate | bpm | HKQuantityType.RestingHeartRate | RestingHeartRateRecord |
| Blood Pressure | mmHg | HKQuantityType.BloodPressureSystolic/Diastolic | BloodPressureRecord |
| Oxygen Saturation | % | HKQuantityType.OxygenSaturation | OxygenSaturationRecord |
| Sleep Duration | hours | HKCategoryType.SleepAnalysis | SleepSessionRecord |
| Hydration | liters | HKQuantityType.DietaryWater | HydrationRecord |
Quick Example
Section titled “Quick Example”public class HealthDashboardViewModel(IHealthService health){ async Task LoadDataAsync() { // 1. Request permissions var result = await health.RequestPermissions( DataType.StepCount, DataType.HeartRate, DataType.Calories, DataType.Distance );
// 2. Check which permissions were granted foreach (var (type, success) in result) { if (!success) Console.WriteLine($"Permission denied for {type}"); }
// 3. Query data for the last 24 hours var end = DateTimeOffset.Now; var start = end.AddDays(-1);
var steps = (await health.GetStepCounts(start, end, Interval.Days)).Sum(x => x.Value); var calories = (await health.GetCalories(start, end, Interval.Days)).Sum(x => x.Value); var distance = (await health.GetDistances(start, end, Interval.Days)).Sum(x => x.Value); var heartRate = (await health.GetAverageHeartRate(start, end, Interval.Days)).Average(x => x.Value);
// 4. Blood pressure returns a special result type var bp = await health.GetBloodPressure(start, end, Interval.Days); if (bp.Any()) { var avgSystolic = bp.Average(x => x.Systolic); var avgDiastolic = bp.Average(x => x.Diastolic); }
// 5. Hourly breakdown var hourlySteps = await health.GetStepCounts(start, end, Interval.Hours); foreach (var bucket in hourlySteps) { Console.WriteLine($"{bucket.Start:g} - {bucket.End:g}: {bucket.Value:N0} steps"); } }}Best Practices
Section titled “Best Practices”- Always request permissions first — Call
RequestPermissionsbefore querying data - Use appropriate intervals —
Interval.Daysfor summaries,Interval.Hoursfor detailed breakdowns - Handle empty results — Check
.Any()before calling.Average()to avoidInvalidOperationException - Use CancellationToken — Pass cancellation tokens for long-running queries
- Sum vs Average — Use
.Sum()for cumulative metrics (steps, calories, distance, hydration, sleep) and.Average()for point-in-time metrics (heart rate, weight, height, body fat, O2 sat, resting HR) - Blood pressure is special — It returns
BloodPressureResult(notNumericHealthResult) with separateSystolicandDiastolicvalues
Platform Notes
Section titled “Platform Notes”- HealthKit requires a real device (not simulator) for most data types
RequestPermissionson iOS does NOT tell you if the user denied access (Apple privacy policy) — it may returntrueeven when denied- Percentage values (body fat, O2 saturation) are returned as 0–100, not 0–1
- Your app requires a provisioning profile with HealthKit capabilities enabled
Android
Section titled “Android”- The Health Connect app must be installed on the device
- Minimum SDK version must be 28 (Android 9) or higher
- Body fat percentage and oxygen saturation use individual record queries (Health Connect does not provide aggregate metrics for these types)
Samples
Section titled “Samples”AI Coding Assistant
Section titled “AI Coding Assistant”Step 1 — Add the marketplace:
claude plugin marketplace add shinyorg/skills Step 2 — Install the plugin:
claude plugin install shiny-client@shiny Step 1 — Add the marketplace:
copilot plugin marketplace add https://github.com/shinyorg/skills Step 2 — Install the plugin:
copilot plugin install shiny-client@shiny