Skip to content

Repository files navigation

HealthMetricsKit

A comprehensive Swift package for accessing HealthKit data with a clean architecture demo application.

๐Ÿ“‹ Overview

HealthMetricsKit provides a robust, protocol-oriented solution for querying key health metrics from HealthKit. The package includes both live HealthKit integration and mock data providers, making it perfect for development, testing, and production use.

Key Features

  • ๐Ÿฅ Complete HealthKit Integration: Access steps, HRV, resting heart rate, VOโ‚‚Max, and sleep data
  • ๐ŸŽญ Mock Data Provider: Deterministic mock data for consistent testing and development
  • ๐Ÿ”’ Permission Management: Proper HealthKit authorization handling
  • ๐Ÿ—๏ธ Clean Architecture: Protocol-oriented design with comprehensive dependency injection
  • ๐Ÿ“ฑ SwiftUI Demo App: Modern iOS app demonstrating best practices
  • โœ… Comprehensive Testing: Full test coverage for all components with mocked dependencies
  • ๐ŸŽฏ MVVM + Use Cases: Clean separation of concerns with business logic isolation
  • ๐Ÿ”„ Dependency Injection: Centralized DI system for better testability and maintainability
  • ๐Ÿ“… Smart Date Handling: Future date prevention and contextual UI updates
  • ๐Ÿ” Health Validation: Built-in validation and health insights system

๐Ÿš€ Quick Start

Swift Package Manager

Add HealthMetricsKit to your project:

dependencies: [
    .package(url: "https://github.com/yourusername/HealthMetricsKit.git", from: "1.0.0")
]

Basic Usage

import HealthMetricsKit

// Use mock data for testing
let mockProvider = MockHealthDataProvider()

// Use mock HealthKit data for development
let healthKitProvider = MockDataWithInjectionProvider()

// Use real HealthKit data for production
let healthKitProvider = HealthKitDataProvider()


// Fetch today's metrics
do {
    let metrics = try await mockProvider.fetchHealthMetrics(for: Date())
    print("Steps: \\(metrics.steps ?? 0)")
    print("Heart Rate Variability: \\(metrics.heartRateVariability ?? 0) ms")
} catch {
    print("Error: \\(error.localizedDescription)")
}

๐Ÿ—๏ธ Architecture

Package Structure

The HealthMetricsKit package is organized into logical modules for better maintainability:

Sources/HealthMetricsKit/
โ”œโ”€โ”€ HealthMetricsKit.swift           # Main module entry point
โ”œโ”€โ”€ Protocols/
โ”‚   โ””โ”€โ”€ HealthDataProvider.swift    # Core protocol interface
โ”œโ”€โ”€ Models/
โ”‚   โ”œโ”€โ”€ HealthMetrics.swift         # Health metrics data model
โ”‚   โ””โ”€โ”€ HealthDataError.swift       # Error definitions
โ”œโ”€โ”€ Implementations/
โ”‚   โ”œโ”€โ”€ HealthKitDataProvider.swift # Live HealthKit implementation
โ”‚   โ””โ”€โ”€ MockHealthDataProvider.swift # Mock data provider
โ”‚   โ””โ”€โ”€ MockDataWithInjectionProvider.swift # Mock data injection provider
โ”œโ”€โ”€ Extensions/
โ”‚   โ””โ”€โ”€ HealthMetrics+Extensions.swift # Convenience extensions
โ””โ”€โ”€ Utilities/
    โ””โ”€โ”€ HealthMetricsFormatter.swift # Formatting and validation utilities

Core Components

HealthDataProvider Protocol

The main interface for accessing health data:

public protocol HealthDataProvider {
    func requestPermissions() async throws
    func fetchHealthMetrics(for date: Date) async throws -> HealthMetrics
    func isHealthDataAvailable() -> Bool
}

HealthMetrics Model

Structured representation of daily health data with helpful extensions:

public struct HealthMetrics {
    public let steps: Int?
    public let heartRateVariability: Double?
    public let restingHeartRate: Double?
    public let vo2Max: Double?
    public let sleepDuration: TimeInterval?
    public let date: Date
    
    // Convenience properties
    public var formattedSleepDuration: String { ... }
    public var isComplete: Bool { ... }
    public var completedMetricsCount: Int { ... }
}

Implementations

  1. HealthKitDataProvider: Live HealthKit integration with proper permission handling and resilient data fetching
  2. MockHealthDataProvider: Deterministic mock data based on date seeds with improved data generation
  3. MockDataWithInjectionProvider: HealthKit injection for realistic testing - writes controlled mock data to HealthKit and reads it back using real HealthKit queries

Utilities

  • HealthMetricsFormatter: Utility for formatting health metrics into user-friendly strings
  • Validation Methods: Range validation for all health metrics
  • Extensions: Convenient methods for working with health data

Demo App Architecture

The included SwiftUI demo app follows Clean Architecture principles with a comprehensive dependency injection system:

DemoApp/
โ”œโ”€โ”€ Domain/
โ”‚   โ”œโ”€โ”€ HealthMetricsRepository/          # Data access abstraction
โ”‚   โ”‚   โ”œโ”€โ”€ HealthMetricsRepository.swift
โ”‚   โ”‚   โ””โ”€โ”€ DefaultHealthMetricsRepository.swift
โ”‚   โ”œโ”€โ”€ UseCases/                         # Business logic layer
โ”‚   โ”‚   โ”œโ”€โ”€ UseCase.swift                 # Base use case protocols
โ”‚   โ”‚   โ”œโ”€โ”€ FetchHealthMetricsUseCase.swift
โ”‚   โ”‚   โ”œโ”€โ”€ RequestPermissionsUseCase.swift
โ”‚   โ”‚   โ””โ”€โ”€ ValidateHealthMetricsUseCase.swift
โ”‚   โ””โ”€โ”€ DependencyInjection/              # Dependency injection system
โ”‚       โ”œโ”€โ”€ DIContainer.swift             # Centralized dependency container
โ”‚       โ””โ”€โ”€ ViewModelFactory.swift       # ViewModel factory with DI
โ”œโ”€โ”€ Navigation/                           # Navigation coordination
โ”‚   โ”œโ”€โ”€ NavigationCoordinator.swift       # Centralized navigation state
โ”‚   โ””โ”€โ”€ MainNavigationView.swift         # TabView-based navigation
โ”œโ”€โ”€ ViewModels/
โ”‚   โ””โ”€โ”€ HealthDashboardViewModel.swift    # MVVM presentation layer
โ”œโ”€โ”€ Views/
โ”‚   โ”œโ”€โ”€ HealthDashboardView.swift         # Main dashboard view with DI
โ”‚   โ”œโ”€โ”€ MetricsListView.swift             # List of all metrics
โ”‚   โ”œโ”€โ”€ SettingsView.swift                # App settings
โ”‚   โ”œโ”€โ”€ AboutView.swift                   # App information
โ”‚   โ””โ”€โ”€ Components/                       # Reusable UI components
โ”‚       โ”œโ”€โ”€ HealthMetricCard.swift
โ”‚       โ”œโ”€โ”€ LoadingView.swift
โ”‚       โ””โ”€โ”€ ErrorView.swift
โ””โ”€โ”€ Tests/
    โ”œโ”€โ”€ HealthDashboardViewModelTests.swift # Comprehensive ViewModel tests
    โ”œโ”€โ”€ NavigationCoordinatorTests.swift  # Navigation system tests
    โ”œโ”€โ”€ MockUseCases/                     # Mock implementations for testing
    โ””โ”€โ”€ DemoAppTests.swift                # Integration tests

Clean Architecture Benefits

  • Domain Layer (Use Cases): Contains business logic and rules, independent of external frameworks
  • Data Layer (Repository): Abstracts data sources, allowing easy switching between HealthKit and mock data
  • Presentation Layer (ViewModels): Coordinates between Use Cases and Views, handles UI state
  • UI Layer (Views): Pure SwiftUI components focused on user interface
  • Dependency Injection: Centralized dependency management for better testability and maintainability

Dependency Injection System

The app uses a sophisticated dependency injection system for better testability and maintainability:

// DIContainer manages all app dependencies
let container = DIContainer.shared

// ViewModelFactory creates ViewModels with proper DI
let factory = ViewModelFactory(diContainer: container)

// Views receive pre-configured ViewModels
let viewModel = factory.makeHealthDashboardViewModel()

Key Features:

  • Centralized Management: All dependencies managed in DIContainer
  • SwiftUI Integration: Environment-based dependency injection
  • Testing Support: Easy mock injection for unit tests
  • Configuration Flexibility: Switch between production and test configurations
  • MainActor Compliance: Proper Swift concurrency support

Navigation System

The app features a comprehensive navigation system built with SwiftUI's latest navigation APIs:

// NavigationCoordinator manages navigation state
class NavigationCoordinator: ObservableObject {
    @Published var navigationPath = NavigationPath()
    @Published var selectedTab: Int = 0
    
    func navigate(to destination: NavigationDestination) {
        navigationPath.append(destination)
    }
    
}

Navigation Features:

  • TabView-based Architecture: Three main tabs (Dashboard, Metrics, Settings)
  • Centralized State Management: All navigation state handled by NavigationCoordinator
  • Type-safe Navigation: NavigationDestination enum ensures compile-time safety
  • Deep Linking Support: Navigate to specific metrics or settings from any tab
  • Stack Management: Proper navigation stack handling with back/root navigation
  • Environment Integration: Navigation coordinator available throughout the app

Available Views:

  • Dashboard: Main health metrics overview with date selection
  • Metrics List: Comprehensive list of all available health metrics
  • Metric Detail: In-depth view of individual metrics with insights
  • Settings: App configuration and health data management
  • About: App information and version details

MetricType System:

  • Visual Consistency: Each metric has dedicated icon and color
  • Comprehensive Coverage: Steps, Heart Rate, HRV, VOโ‚‚Max, Sleep
  • Extensible Design: Easy to add new metrics with proper styling

๐Ÿš€ Recent Improvements

Latest Updates - Scheme-Based Configuration & Enhanced Testing

๐ŸŽฏ Three-Environment Architecture

  • Test: Pure mock data with MockHealthDataProvider - no HealthKit dependencies
  • Dev: Realistic testing with MockDataWithInjectionProvider - injects controlled data into HealthKit for end-to-end testing
  • Production: Real user data with HealthKitDataProvider - live HealthKit integration

๐Ÿ”ง Scheme-Based Configuration

  • Automatic environment detection via APP_CONFIGURATION environment variables
  • DemoApp-Test.xcscheme: Uses MockHealthDataProvider for rapid development
  • DemoApp-Dev.xcscheme: Uses MockDataWithInjectionProvider for realistic HealthKit testing
  • DemoApp-Production.xcscheme: Uses HealthKitDataProvider for production deployment
  • Centralized configuration in DIContainer with automatic provider selection

๐Ÿงช MockDataWithInjectionProvider - Revolutionary Testing

  • Real HealthKit Integration: Writes mock data to actual HealthKit store and reads it back
  • 7 Days of Realistic Data: Automatically injects varied, realistic health metrics for a full week
  • Controlled Testing Environment: Predictable data for consistent UI testing and demos
  • Graceful Error Handling: Robust clearing and injection with detailed console logging
  • One-Time Injection: Smart caching prevents repeated data injection per app launch
  • Production-Like Flow: Tests complete HealthKit permission and data flow

๐Ÿ”„ Automatic UI Refresh System

  • NotificationCenter Integration: Automatic UI refresh after HealthKit permissions are granted
  • Real-Time Updates: No manual refresh needed when permissions change
  • Seamless UX: Dashboard immediately shows data after permission grant
  • Decoupled Architecture: Clean separation between permission flow and UI updates

๐Ÿ’ช Resilient Data Fetching

  • Partial Data Support: HealthKitDataProvider now handles missing metrics gracefully
  • Graceful Degradation: Shows available data even when some metrics are unavailable
  • Error Isolation: Individual metric failures don't prevent other data from displaying
  • User-Friendly Experience: No more "all or nothing" data fetching

๐Ÿ—๏ธ Enhanced Dependency Injection

  • Three-Tier Configuration: Automatic provider selection based on app configuration
  • Environment Variables: Dynamic configuration without code changes
  • Testing Support: Easy switching between environments for different testing scenarios
  • Production Ready: Seamless deployment with proper HealthKit integration

Enhanced Architecture Updates

๐Ÿ—๏ธ Advanced Dependency Injection

  • Centralized DIContainer for all app dependencies
  • ViewModelFactory with environment-based injection
  • Support for both production and testing configurations
  • MainActor-compliant dependency resolution

๐Ÿ“‹ Use Cases Implementation

  • FetchHealthMetricsUseCase with business rule validation
  • RequestPermissionsUseCase with availability checks
  • ValidateHealthMetricsUseCase with health insights
  • Clear separation between data access and business logic

๐ŸŽจ Enhanced User Interface

  • Dynamic header titles based on selected date
  • Future date prevention in DatePicker
  • Metrics completion percentage indicator
  • Health validation warnings and insights
  • Improved accessibility support

๐Ÿงญ Navigation System

  • Comprehensive NavigationCoordinator with centralized state management
  • TabView-based architecture with Dashboard, Metrics, and Settings tabs
  • Type-safe navigation using NavigationDestination enum
  • New views: MetricsListView, SettingsView, AboutView
  • Deep linking support for specific metrics and settings
  • Proper navigation stack management with back/root navigation
  • Environment-based navigation coordinator injection

๐Ÿงช Comprehensive Testing

  • Full dependency injection testing
  • Mock implementations for all use cases
  • ViewModel testing with injected dependencies
  • Date functionality and validation tests
  • Comprehensive error handling scenarios

๐Ÿ“ฑ Demo App Features

The SwiftUI demo app demonstrates:

  • Clean Dashboard: Modern card-based layout showing all health metrics
  • Smart Date Selection: DatePicker with future date prevention and contextual titles
  • Dynamic Headers: Shows "Today's Metrics" for current date, "Metrics for:" for other dates
  • TabView Navigation: Three main tabs for Dashboard, Metrics, and Settings
  • Metrics List: Comprehensive list of all health metrics with navigation to details
  • Metric Detail Views: In-depth information for each metric with insights and ranges
  • Settings Panel: App configuration, health data management, and debug options
  • About Page: App information, version details, and credits
  • Loading States: Elegant loading animations during data fetch
  • Error Handling: User-friendly error messages with retry functionality
  • Pull to Refresh: Standard iOS refresh gesture support
  • Metrics Completion: Progress indicator showing data completeness percentage
  • Validation Warnings: Health insights and warnings for unusual readings
  • Mock Data: Uses MockHealthDataProvider for consistent demo experience
  • Accessibility: Full Dynamic Type and VoiceOver support

Screenshots

The dashboard displays:

  • ๐Ÿ‘ฃ Daily step count
  • โค๏ธ Resting heart rate (BPM)
  • ๐Ÿ“Š Heart rate variability (ms)
  • ๐Ÿซ VOโ‚‚Max (ml/kg/min)
  • ๐Ÿ˜ด Sleep duration (hours and minutes)

๐Ÿงช Testing

Package Tests

Run the complete test suite:

swift test

Demo App Tests

The demo app includes comprehensive tests for:

  • ViewModels with dependency injection: Full ViewModel testing with mocked dependencies
  • Repository pattern implementation: Data layer abstraction testing
  • Use Cases business logic: Domain layer rule validation
  • Navigation system: NavigationCoordinator state management and routing logic
  • MetricType system: Visual consistency and extensibility testing
  • Error handling scenarios: Comprehensive error state testing
  • Mock data consistency: Deterministic test data validation
  • Date functionality: Date selection and validation logic
  • UI state management: Loading, error, and success states
# In Xcode, run tests for DemoApp target
โŒ˜ + U

# Run specific test classes
xcodebuild -project DemoApp.xcodeproj -scheme DemoApp-Test -destination 'platform=iOS Simulator,name=iPhone 16' test -only-testing HealthDashboardViewModelTests

Environment-Specific Testing

Test different configurations using the scheme-based system:

# Test with Test environment (MockHealthDataProvider)
xcodebuild -project DemoApp.xcodeproj -scheme DemoApp-Test -destination 'platform=iOS Simulator,name=iPhone 16' build

# Test with Dev environment (MockDataWithInjectionProvider)
xcodebuild -project DemoApp.xcodeproj -scheme DemoApp-Dev -destination 'platform=iOS Simulator,name=iPhone 16' build

# Test with Production environment (HealthKitDataProvider)
xcodebuild -project DemoApp.xcodeproj -scheme DemoApp-Production -destination 'platform=iOS Simulator,name=iPhone 16' build

Console Output for Dev Environment:

๐Ÿ”„ MockDataWithInjectionProvider: Starting data injection...
โ„น๏ธ No existing HKQuantityTypeIdentifierStepCount data to clear (this is normal)
๐Ÿงน Cleared existing HealthKit samples
๐Ÿ“Š Day 1: Steps: 12000, VO2Max: 42.0, RHR: 65.0, HRV: 45.0, Sleep: 7.5h
๐Ÿ“Š Day 2: Steps: 11200, VO2Max: 42.3, RHR: 64.5, HRV: 46.5, Sleep: 8.0h
...
โœ… Injected 7 days of mock data to HealthKit
โœ… Health data permissions granted successfully

Test Coverage

  • โœ… HealthMetrics model initialization and extensions
  • โœ… MockHealthDataProvider deterministic behavior
  • โœ… HealthKitDataProvider permission handling and resilient data fetching
  • โœ… MockDataWithInjectionProvider HealthKit data injection and clearing
  • โœ… Use Cases business logic validation
  • โœ… Dependency injection system with three-environment support
  • โœ… ViewModel state management with async operations
  • โœ… Repository pattern implementation
  • โœ… NavigationCoordinator state management and routing
  • โœ… MetricType properties and visual consistency
  • โœ… Navigation destination handling and tab switching
  • โœ… Error cases and edge conditions with graceful degradation
  • โœ… Date selection and validation logic
  • โœ… Metrics completion percentage calculations
  • โœ… Health validation warnings and insights
  • โœ… Scheme-based configuration and environment detection
  • โœ… Automatic UI refresh after permission grant
  • โœ… Notification system integration

๐Ÿ”ง Configuration

Environment Setup

The app supports three distinct environments controlled by Xcode schemes:

Test Environment

  • Purpose: Rapid development with no HealthKit dependencies
  • Data Provider: MockHealthDataProvider
  • Usage: Day-to-day development, unit testing, and demos
  • Scheme: DemoApp-Test
  • Environment Variable: APP_CONFIGURATION=Test

Dev Environment

  • Purpose: Realistic HealthKit testing with controlled data
  • Data Provider: MockDataWithInjectionProvider
  • Usage: End-to-end testing, QA validation, and realistic demos
  • Scheme: DemoApp-Dev
  • Environment Variable: APP_CONFIGURATION=Dev
  • Special Features: Automatically injects 7 days of realistic mock data into HealthKit

Production Environment

  • Purpose: Live app with real user health data
  • Data Provider: HealthKitDataProvider
  • Usage: App Store releases and production deployment
  • Scheme: DemoApp-Production
  • Environment Variable: APP_CONFIGURATION=Production

HealthKit Permissions

To use the HealthKitDataProvider or MockDataWithInjectionProvider in your app, add the following to your Info.plist:

<key>NSHealthShareUsageDescription</key>
<string>This app needs access to your health data to display your daily metrics.</string>
<key>NSHealthUpdateUsageDescription</key>
<string>This app needs to write test data to HealthKit for realistic testing scenarios.</string>

Required HealthKit Capabilities

Ensure your app target has HealthKit capability enabled in Xcode project settings.

Automatic Configuration

The app automatically detects the current environment and configures dependencies accordingly:

// DIContainer automatically selects the appropriate provider
switch Configuration.current {
case .test:
    provider = MockHealthDataProvider()        // Pure mock data
case .dev:
    provider = MockDataWithInjectionProvider() // HealthKit injection
case .production:
    provider = HealthKitDataProvider()         // Real user data
}

๐ŸŽฏ Design Decisions

Why Protocol-Oriented Design?

  • Testability: Easy to mock dependencies for unit testing
  • Flexibility: Swap implementations without changing client code
  • Separation of Concerns: Clear boundaries between data access and business logic

Why Three Data Providers?

MockHealthDataProvider (Test)

  • Consistent Development: Same data across team members and CI/CD
  • Demo Ready: Perfect for app store screenshots and demos
  • Offline Testing: No need for real health data during development
  • Fast Iteration: No HealthKit dependencies or permission prompts

MockDataWithInjectionProvider (Dev)

  • Realistic Testing: Tests complete HealthKit integration flow with controlled data
  • End-to-End Validation: Validates permission flow, data writing, and reading
  • Predictable Results: Same test data every time for consistent testing
  • Production-Like: Uses real HealthKit APIs while maintaining data control

HealthKitDataProvider (Production)

  • Real User Data: Actual health metrics from user's HealthKit store
  • Live Integration: Full HealthKit feature set and real-world data patterns
  • User Privacy: Respects user permissions and data boundaries

Why MVVM + Use Cases + Repository Pattern?

  • Clean Architecture: Clear separation between UI, business logic, and data access
  • Testability: Each layer can be tested independently with full mock support
  • Maintainability: Changes in one layer don't affect others
  • Business Logic Isolation: Use Cases encapsulate domain rules independently
  • Dependency Injection: Centralized dependency management for better testing and flexibility
  • iOS Best Practices: Follows Apple's recommended patterns with modern Swift concurrency
  • Scalability: Architecture supports easy addition of new features and use cases

๐Ÿ“Š Health Metrics Details

Steps

  • Source: HealthKit step count data
  • Unit: Total daily steps
  • Mock Range: 8,000 - 12,950 steps

Heart Rate Variability (HRV)

  • Source: HealthKit SDNN measurements
  • Unit: Milliseconds (ms)
  • Mock Range: 30 - 70 ms

Resting Heart Rate

  • Source: HealthKit resting heart rate
  • Unit: Beats per minute (BPM)
  • Mock Range: 55 - 85 BPM

VOโ‚‚Max

  • Source: HealthKit cardio fitness
  • Unit: ml/kg/min
  • Mock Range: 35 - 65 ml/kg/min

Sleep Duration

  • Source: HealthKit sleep analysis
  • Unit: TimeInterval (seconds)
  • Mock Range: 6.5 - 9.5 hours

๐ŸŽฏ MockDataWithInjectionProvider Details

The Dev environment uses a revolutionary approach for realistic HealthKit testing:

Data Injection Process

  1. Permission Request: Requests both read and write HealthKit permissions
  2. Data Clearing: Gracefully clears existing test data (ignores errors if no data exists)
  3. 7-Day Injection: Writes realistic health metrics for the past 7 days
  4. Real Queries: Uses actual HealthKitDataProvider to fetch the injected data

Generated Mock Data Patterns

Metric Day 1 Day 2 Day 3 Day 7 Pattern
Steps 12,000 11,200 10,400 8,800 Decreasing with variation
VOโ‚‚Max 42.0 42.3 42.6 43.8 Gradual improvement
Resting HR 65.0 64.5 64.0 62.5 Slight improvement
HRV 45.0 46.5 48.0 54.0 Improving trend
Sleep 7.5h 8.0h 7.5h 8.5h Weekend variations

Benefits for Testing

  • Realistic Data Patterns: Natural variations and trends
  • End-to-End Validation: Tests complete HealthKit permission and data flow
  • Consistent Results: Same data set for every test run
  • Production Parity: Uses exact same HealthKit APIs as production
  • Error Handling: Tests real HealthKit error scenarios

๐Ÿšจ Error Handling

The package provides comprehensive error handling:

public enum HealthDataError: Error, LocalizedError {
    case permissionDenied
    case healthDataNotAvailable
    case dataFetchFailed(Error)
    case invalidData
}

Each error provides localized descriptions for user-friendly error messages.

๐Ÿ”ฎ Future Enhancements

Potential areas for expansion:

  • Additional Metrics: Blood pressure, blood glucose, weight trends
  • Historical Analysis: Weekly/monthly trends and averages
  • Export Functionality: CSV/JSON export of health data
  • Widgets: iOS widget support for quick health overview
  • WatchOS Companion: Apple Watch app for quick metrics
  • Advanced Health Insights: AI-powered health recommendations and trend analysis
  • Multi-User Support: Family health tracking with privacy controls
  • Integration APIs: Support for additional health data sources beyond HealthKit
  • Offline Sync: Local data persistence with sync capabilities

๐Ÿ“„ Requirements

  • iOS 16.0+
  • Swift 6.1+
  • Xcode 15.0+

๐Ÿ“œ License

This project is available under the MIT License.

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

๐Ÿ™‹โ€โ™‚๏ธ Support

For questions or issues, please open an issue on GitHub.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages