A complete React Native + Expo application demonstrating iOS HealthKit integration through a custom native module.
This is a fully functional iOS fitness tracking app that demonstrates how to integrate native iOS HealthKit features into a React Native/Expo application. The app allows users to:
- π± Track and save workout sessions to Apple Health
- π View workout history from the last 30 days
- π See aggregate statistics (total distance, calories)
- ποΈ Delete workouts from HealthKit
- β Request and manage HealthKit permissions
The app is built using Expo Router for navigation and includes a custom expo-healthkit module that bridges Swift/HealthKit to JavaScript.
Main Demo Screen (healthkit-demo.tsx)
- Authorization Flow: Request read/write access to HealthKit workout data
- Save Workouts: Create sample workouts (running, walking, cycling, etc.) with distance, duration, and calories
- View Statistics: Display total distance and calories burned over the last 30 days
- Workout History: Browse recent workouts with detailed information
- Delete Workouts: Remove individual workouts from HealthKit
The expo-healthkit module provides:
- β Full HealthKit workout management
- β Multiple activity types (running, cycling, swimming, yoga, etc.)
- β Aggregate statistics queries
- β Type-safe TypeScript API
- β Automatic permission configuration via Expo config plugin
health-kit-rn/
βββ app/ # Expo Router app directory
β βββ (tabs)/ # Tab navigation
β β βββ index.tsx # Home screen
β β βββ explore.tsx # Explore screen
β βββ healthkit-demo.tsx # HealthKit demo & test screen
β βββ _layout.tsx # Root layout
β βββ +not-found.tsx # 404 screen
β
βββ modules/expo-healthkit/ # Custom HealthKit Expo module
β βββ ios/ # Native iOS implementation
β β βββ ExpoHealthKitModule.swift # Module interface definition
β β βββ ExpoHealthKitManager.swift # HealthKit operations logic
β βββ src/ # TypeScript API
β β βββ ExpoHealthKit.ts # Main API wrapper
β β βββ types.ts # TypeScript type definitions
β β βββ index.ts # Module exports
β βββ app.plugin.js # Expo config plugin (auto-adds permissions)
β βββ expo-module.config.json # Module configuration for autolinking
β βββ package.json # Module package definition
β βββ README.md # Module documentation
β
βββ components/ # React components
β βββ navigation/ # Navigation components
β βββ ui/ # UI components
β βββ ...
β
βββ ios/ # Generated iOS native project (git-ignored)
β βββ healthkitrn.xcworkspace # Xcode workspace
β βββ healthkitrn/
β βββ Info.plist # Contains HealthKit usage descriptions
β βββ healthkitrn.entitlements # HealthKit entitlements
β
βββ app.json # Expo configuration
βββ package.json # Project dependencies
βββ tsconfig.json # TypeScript configuration
- app/healthkit-demo.tsx: Main demo screen with HealthKit integration UI
- modules/expo-healthkit/ios/ExpoHealthKitModule.swift: Native module interface
- modules/expo-healthkit/ios/ExpoHealthKitManager.swift: HealthKit business logic
- modules/expo-healthkit/src/ExpoHealthKit.ts: JavaScript API wrapper
- modules/expo-healthkit/app.plugin.js: Expo config plugin for permissions
yarn installyarn ios --device. You CANNOT use yarn start alone because:
- The native Swift module needs to be compiled
- HealthKit requires a physical iOS device (not simulator)
- Metro bundler only handles JavaScript, not native code
Option A: Build with Xcode (Recommended for first build)
-
Open the workspace:
cd ios && open healthkitrn.xcworkspace
-
In Xcode:
- Select the healthkitrn project β healthkitrn target
- Go to Signing & Capabilities tab
- β Check "Automatically manage signing"
- Select your Apple Developer Team from the dropdown
-
Connect your iPhone and select it as the destination
-
Press Run
βΆοΈ (or βR)
Option B: Build with CLI
Connect your iPhone and run:
yarn ios --deviceCommon Error: If you see Error: Cannot find native module 'ExpoHealthKit', it means you tried to run with yarn start instead of building the app. You must build with Xcode or yarn ios --device first.
Once the app launches on your device:
- Navigate to the healthkit-demo screen (you can add it to your navigation or access it directly)
- Tap "Request HealthKit Access" to authorize the app
- Use the buttons to:
- Save Sample Workout: Creates a 1-hour running workout with 5km distance
- Load Workouts: Fetches your last 10 workouts from the past 30 days
- Load Stats: Shows total distance and calories for the last 30 days
- View your workout history and tap Delete to remove individual workouts
import * as ExpoHealthKit from 'expo-healthkit';
// Request permission
await ExpoHealthKit.requestAuthorization([], ['Workout']);
// Save a workout
await ExpoHealthKit.saveWorkout({
startDate: Date.now() / 1000 - 3600,
endDate: Date.now() / 1000,
duration: 3600,
distance: 5000,
calories: 350,
activityType: 'running',
});
// Query workouts
const workouts = await ExpoHealthKit.queryWorkouts({
startDate: new Date('2024-01-01'),
endDate: new Date(),
});This project shows how to bridge Swift/HealthKit to React Native:
JavaScript (TypeScript)
β
requireNativeModule
β
Expo Bridge
β
Swift Module
β
iOS HealthKit
Key Components:
- Swift Module (ExpoHealthKitModule.swift) - Defines the native interface
- Swift Manager (ExpoHealthKitManager.swift) - Implements HealthKit operations
- TypeScript API (src/ExpoHealthKit.ts) - Type-safe JavaScript wrapper
- Config Plugin (app.plugin.js) - Auto-adds permissions
See modules/expo-healthkit/README.md for:
- Complete API reference
- All supported functions
- TypeScript types
- Advanced usage
Cause: You're running the Metro bundler (yarn start) without building the native code.
Why this happens:
- Metro bundler only handles JavaScript files
- Native Swift modules must be compiled with Xcode or
yarn ios - The module exists in code but hasn't been built into a binary
Solution:
- Stop Metro bundler (Ctrl+C)
- Build the app with Xcode or run
yarn ios --device - The module will be compiled and available
Solution: Open Xcode and configure code signing:
open ios/healthkitrn.xcworkspace- Select healthkitrn target β Signing & Capabilities
- Check "Automatically manage signing"
- Select your Apple Developer Team
Cause: HealthKit requires special App ID configuration in your Apple Developer account.
Solution:
-
Register App ID with HealthKit:
- Go to https://developer.apple.com/account
- Navigate to Certificates, Identifiers & Profiles β Identifiers
- Find or create App ID:
com.kayzmann.healthkitrn - β Enable HealthKit capability
- Click Save
-
Regenerate Provisioning Profile in Xcode:
- Open Xcode β Signing & Capabilities
- Uncheck "Automatically manage signing"
- Check it again (forces Xcode to regenerate)
- Wait for Xcode to download new profile
-
Build again - the profile will now include HealthKit entitlements
rm -rf node_modules/expo-healthkit
yarn install
cd ios && pod install
yarn ios --deviceThis project teaches:
- How to create local Expo modules
- Swift β JavaScript bridging
- HealthKit integration
- Expo config plugins
- Native module architecture