A comprehensive Swift package for accessing HealthKit data with a clean architecture demo application.
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.
- ๐ฅ 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
Add HealthMetricsKit to your project:
dependencies: [
.package(url: "https://github.com/yourusername/HealthMetricsKit.git", from: "1.0.0")
]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)")
}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
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
}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 { ... }
}- HealthKitDataProvider: Live HealthKit integration with proper permission handling and resilient data fetching
- MockHealthDataProvider: Deterministic mock data based on date seeds with improved data generation
- MockDataWithInjectionProvider: HealthKit injection for realistic testing - writes controlled mock data to HealthKit and reads it back using real HealthKit queries
- 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
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
- 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
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
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:
NavigationDestinationenum 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
๐ฏ 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_CONFIGURATIONenvironment variables DemoApp-Test.xcscheme: Uses MockHealthDataProvider for rapid developmentDemoApp-Dev.xcscheme: Uses MockDataWithInjectionProvider for realistic HealthKit testingDemoApp-Production.xcscheme: Uses HealthKitDataProvider for production deployment- Centralized configuration in
DIContainerwith 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
๐๏ธ Advanced Dependency Injection
- Centralized
DIContainerfor all app dependencies ViewModelFactorywith environment-based injection- Support for both production and testing configurations
- MainActor-compliant dependency resolution
๐ Use Cases Implementation
FetchHealthMetricsUseCasewith business rule validationRequestPermissionsUseCasewith availability checksValidateHealthMetricsUseCasewith 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
NavigationCoordinatorwith centralized state management - TabView-based architecture with Dashboard, Metrics, and Settings tabs
- Type-safe navigation using
NavigationDestinationenum - 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
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
The dashboard displays:
- ๐ฃ Daily step count
- โค๏ธ Resting heart rate (BPM)
- ๐ Heart rate variability (ms)
- ๐ซ VOโMax (ml/kg/min)
- ๐ด Sleep duration (hours and minutes)
Run the complete test suite:
swift testThe 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 HealthDashboardViewModelTestsTest 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' buildConsole 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
- โ 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
The app supports three distinct environments controlled by Xcode schemes:
- 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
- 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
- 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
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>Ensure your app target has HealthKit capability enabled in Xcode project settings.
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
}- 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
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
- 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
- Source: HealthKit step count data
- Unit: Total daily steps
- Mock Range: 8,000 - 12,950 steps
- Source: HealthKit SDNN measurements
- Unit: Milliseconds (ms)
- Mock Range: 30 - 70 ms
- Source: HealthKit resting heart rate
- Unit: Beats per minute (BPM)
- Mock Range: 55 - 85 BPM
- Source: HealthKit cardio fitness
- Unit: ml/kg/min
- Mock Range: 35 - 65 ml/kg/min
- Source: HealthKit sleep analysis
- Unit: TimeInterval (seconds)
- Mock Range: 6.5 - 9.5 hours
The Dev environment uses a revolutionary approach for realistic HealthKit testing:
- Permission Request: Requests both read and write HealthKit permissions
- Data Clearing: Gracefully clears existing test data (ignores errors if no data exists)
- 7-Day Injection: Writes realistic health metrics for the past 7 days
- Real Queries: Uses actual HealthKitDataProvider to fetch the injected data
| 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 |
- 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
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.
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
- iOS 16.0+
- Swift 6.1+
- Xcode 15.0+
This project is available under the MIT License.
Contributions are welcome! Please feel free to submit a Pull Request.
For questions or issues, please open an issue on GitHub.