Skip to content

Saurus119/Maui.Health

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

"Buy Me A Coffee"

Maui.Health

NuGet Version NuGet Downloads

Abstraction around Android Health Connect and iOS HealthKit with unified DTO-based API ⚠️ Beware, this package is currently just as Proof of concept. There is a lot of work required for proper stability and ease of use. Issues will contain future tasks that should be implemented.

Feel free to contribute ❤️

Features

  • Generic API: Use GetHealthDataAsync<TDto>() for type-safe health data retrieval
  • Unified DTOs: Platform-agnostic data transfer objects with common properties
  • Time Range Support: Duration-based metrics implement IHealthTimeRange interface
  • Cross-Platform: Works with Android Health Connect and iOS HealthKit

Platform Support & Health Data Mapping

Health Data Type Android Health Connect iOS HealthKit Wrapper Implementation
Steps ✅ StepsRecord ✅ StepCount StepsDto
Weight ✅ WeightRecord ✅ BodyMass WeightDto
Height ✅ HeightRecord ✅ Height HeightDto
Heart Rate ✅ HeartRateRecord ✅ HeartRate HeartRateDto
Active Calories ✅ ActiveCaloriesBurnedRecord ✅ ActiveEnergyBurned ActiveCaloriesBurnedDto
Exercise Session ✅ ExerciseSessionRecord ✅ Workout WorkoutDto
Blood Glucose ✅ BloodGlucoseRecord ✅ BloodGlucose ❌ N/A
Body Temperature ✅ BodyTemperatureRecord ✅ BodyTemperature ❌ N/A
Oxygen Saturation ✅ OxygenSaturationRecord ✅ OxygenSaturation ❌ N/A
Respiratory Rate ✅ RespiratoryRateRecord ✅ RespiratoryRate ❌ N/A
Basal Metabolic Rate ✅ BasalMetabolicRateRecord ✅ BasalEnergyBurned ❌ N/A
Body Fat ✅ BodyFatRecord ✅ BodyFatPercentage BodyFatDto
Lean Body Mass ✅ LeanBodyMassRecord ✅ LeanBodyMass ❌ N/A
Hydration ✅ HydrationRecord ✅ DietaryWater ❌ N/A
VO2 Max ✅ Vo2MaxRecord ✅ VO2Max Vo2MaxDto
Resting Heart Rate ✅ RestingHeartRateRecord ✅ RestingHeartRate ❌ N/A
Heart Rate Variability ✅ HeartRateVariabilityRmssdRecord ✅ HeartRateVariabilitySdnn ❌ N/A
Blood Pressure ✅ BloodPressureRecord ✅ Split into Systolic/Diastolic 🚧 WIP (commented out)

Usage

1. Registration

Register the health service in your MauiProgram.cs:

builder.Services.AddHealth();

Then setup all Android and iOS necessities.

  • Android (4) docs, docs2
    • in Google Play console give Health permissions to the app
    • for successful app approval your Policy page must contain Health data collection and use, Data retention policy
    • change of AndroidManifest.xml + new activity showing privacy policy
    • change of min. Android version to v26
  • iOS (3) docs, docs2
    • generating new provisioning profile containing HealthKit permissions. These permissions are changed in Identifiers
    • adding Entitlements.plist
    • adjustment of Info.plist
      • ⚠️ Beware, if your app already exists and targets various devices adding UIRequiredDeviceCapabilities with healthkit can get your release rejected. For that reason I ommited adding this requirement and I just make sure that I check if the device is capable of using healthkit.

After you have everything setup correctly you can use IHealthService from DI container and call it's methods. If you want an example there is a DemoApp project showing number of steps for Current day

2. Basic Usage

public class HealthExampleService
{
    private readonly IHealthService _healthService;

    public HealthExampleService(IHealthService healthService)
    {
        _healthService = healthService;
    }

    public async Task<List<StepsDto>> GetTodaysStepsAsync()
    {
        var timeRange = HealthTimeRange.FromDateTime(DateTime.Today, DateTime.Now);

        var steps = await _healthService.GetHealthDataAsync<StepsDto>(timeRange);
        return steps.ToList();
    }

    public async Task<List<WeightDto>> GetRecentWeightAsync()
    {
        var timeRange = HealthTimeRange.FromDateTime(DateTime.Now.AddDays(-7), DateTime.Now);

        var weights = await _healthService.GetHealthDataAsync<WeightDto>(timeRange);
        return weights.ToList();
    }
}

3. Working with Time Ranges

Duration-based metrics implement IHealthTimeRange:

public async Task AnalyzeStepsData()
{
    var timeRange = HealthTimeRange.FromDateTime(DateTime.Today, DateTime.Now);
    var steps = await _healthService.GetHealthDataAsync<StepsDto>(timeRange);
    
    foreach (var stepRecord in steps)
    {
        // Common properties from BaseHealthMetricDto
        Console.WriteLine($"ID: {stepRecord.Id}");
        Console.WriteLine($"Source: {stepRecord.DataOrigin}");
        Console.WriteLine($"Recorded: {stepRecord.Timestamp}");
        
        // Steps-specific data
        Console.WriteLine($"Steps: {stepRecord.Count}");
        
        // Time range data (IHealthTimeRange)
        Console.WriteLine($"Period: {stepRecord.StartTime} to {stepRecord.EndTime}");
        Console.WriteLine($"Duration: {stepRecord.Duration}");
        
        // Type-safe duration checking
        if (stepRecord is IHealthTimeRange timeRange)
        {
            Console.WriteLine($"This measurement lasted {timeRange.Duration.TotalMinutes} minutes");
        }
    }
}

public async Task AnalyzeWeightData()
{
    var timeRange = HealthTimeRange.FromDateTime(DateTime.Today.AddDays(-30), DateTime.Now);
    var weights = await _healthService.GetHealthDataAsync<WeightDto>(timeRange);
    
    foreach (var weightRecord in weights)
    {
        // Instant measurements only have Timestamp
        Console.WriteLine($"Weight: {weightRecord.Value} {weightRecord.Unit}");
        Console.WriteLine($"Measured at: {weightRecord.Timestamp}");
        Console.WriteLine($"Source: {weightRecord.DataOrigin}");
    }
}

4. Permission Handling

public async Task RequestPermissions()
{
    var permissions = new List<HealthPermissionDto>
    {
        new() { HealthDataType = HealthDataType.Steps, PermissionType = PermissionType.Read },
        new() { HealthDataType = HealthDataType.Weight, PermissionType = PermissionType.Read },
        new() { HealthDataType = HealthDataType.Height, PermissionType = PermissionType.Read }
    };

    var result = await _healthService.RequestPermissions(permissions);
    
    if (result.IsSuccess)
    {
        Console.WriteLine("Permissions granted!");
    }
    else
    {
        Console.WriteLine($"Permission error: {result.Error}");
    }
}

Testing Tips

iOS Simulator/Device:

  • If no health data exists, open the Health app
  • Navigate to the desired metric (e.g., Steps)
  • Tap "Add Data" in the top-right corner
  • Manually add test data for development

Android Emulator:

  • Install Google Health Connect app
  • Add sample health data for testing
  • Ensure proper permissions are granted

Credits

  • @aritchie - https://github.com/shinyorg/Health
  • @0xc3u - https://github.com/0xc3u/Plugin.Maui.Health
  • @EagleDelux - https://github.com/EagleDelux/androidx.health-connect-demo-.net-maui
  • @b099l3 - https://github.com/b099l3/ios-samples/tree/65a4ab1606cfd8beb518731075e4af526c4da4ad/ios8/Fit/Fit

Other Sources

About

Abstraction around `Android Health Connect` and `iOS HealthKit`

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 100.0%