Health Beat is an iOS app that continuously syncs Apple HealthKit data to a MySQL database. It connects directly to MySQL over TCP using a built-in wire protocol implementation — no backend server, no cloud service, no dependencies. Your health data goes straight from your phone to your database.
- 85 quantity types — steps, heart rate, blood pressure, blood glucose, body temperature, VO2 max, nutrition (all macros and micronutrients), audio exposure, and more
- 22 category types — sleep analysis, menstrual cycles, symptoms, mindfulness, heart events, stand hours
- Workouts — activity type, duration, energy burned, distance, swim strokes, flights climbed
- Blood pressure — systolic/diastolic correlation pairs
- ECG recordings — classification, heart rate, voltage measurements
- Audiograms — hearing sensitivity by frequency
- Workout routes — GPS coordinates recorded during workouts
- Activity summaries — daily ring data (active energy, exercise minutes, stand hours)
- Medications — name, dosage, start/end dates (iOS 26+)
- Full and incremental sync — initial backfill of all historical data, then ongoing incremental syncs for new records
- Real-time background sync — registers HealthKit observer queries for immediate delivery when new data is recorded
- Background processing — periodic sync via BGProcessingTask when the app isn't active
- Live Activity — sync progress on the lock screen and Dynamic Island
- Data browser — browse all synced data by category with search and filtering
- Location tracking — continuous GPS logging and geofence-based check-ins with customizable place categories
- Data validation — quick scan (count comparison) or deep scan (record-level comparison) with auto-repair
- Backup and restore — manual or automatic backups to iCloud Drive, with selective per-category restore
- Multi-device iCloud sync — settings, geofences, and place categories sync across devices; one device claims auto-sync rights to prevent conflicts
- No dependencies — pure Swift using only Apple frameworks (HealthKit, Network, BackgroundTasks, CoreLocation, ActivityKit, CloudKit)
- iOS 16.2+
- Physical device (HealthKit is not available in the Simulator)
- MySQL 5.7+ or 8.0+ server accessible from the device's network
- Apple Developer account (for HealthKit entitlement and code signing)
-
Clone the repository:
git clone https://github.com/your-username/HealthBeat.git -
Open the Xcode project:
open "Health Beat.xcodeproj" -
In Signing & Capabilities, select your development team and set a unique bundle identifier.
-
Verify the following capabilities are present (they should already be configured):
- HealthKit (with Background Delivery)
- Background Modes: Background processing, Background fetch
- iCloud (Key-value storage)
-
Verify build settings point to the right files:
INFOPLIST_FILE=Sources/HealthBeat/Resources/Info.plistCODE_SIGN_ENTITLEMENTS=Sources/HealthBeat/Resources/HealthBeat.entitlements
-
Build and run on a physical device.
Sources/HealthBeat/
HealthBeatApp.swift App entry point and background task registration
ContentView.swift Root TabView (Sync, Browse, Settings)
Models/
MySQLConfig.swift Connection config (saved to UserDefaults)
SyncState.swift Observable sync state
HealthDataType.swift All HealthKit type descriptors
HealthRecord.swift Record models for the data browser
...
Services/
MySQLService.swift TCP MySQL wire protocol (async/await actor)
SchemaService.swift CREATE TABLE DDL and schema initialization
HealthKitService.swift HealthKit queries and permissions
SyncService.swift Full/incremental sync orchestration
BackgroundSyncManager.swift HKObserverQuery registration and background delivery
LocationService.swift GPS tracking and geofence monitoring
BackupManager.swift Backup creation, listing, and restore
iCloudSyncService.swift iCloud KV store sync and device management
ViewModels/ View models for each tab
Views/
Sync/ Sync dashboard and category status cards
DataBrowser/ Data browsing views per type
Settings/ All settings and configuration views
Resources/
Info.plist HealthKit usage description, BG task identifiers
HealthBeat.entitlements HealthKit, iCloud, and location entitlements
Sources/HealthBeatWidgets/ Live Activity widget for sync progress
The app implements the MySQL client wire protocol directly using Network.framework. This means no MySQL client library or SPM dependency is needed. It supports:
- Protocol v4.1 handshake
mysql_native_password(SHA1) andcaching_sha2_password(SHA256 + RSA full auth)- Batch
INSERT IGNOREin chunks of 500 for UUID-based deduplication - Async/await with continuation-based receive buffering
- Install the app on your iPhone.
- Go to Settings > MySQL Connection and enter your MySQL server's host, port, database name, username, and password.
- Tap Test Connection to verify connectivity.
- Go to Settings > HealthKit Permissions and grant access to the health data types you want to sync.
- Return to the Sync tab and tap Full Sync to backfill your historical data. Keep the screen on until the full sync completes — Apple HealthKit is not accessible when the device is locked, and the sync will stall. The app enables "Keep Screen On" by default during full sync (configurable in Settings).
Create a database on your MySQL server. The app will automatically create all required tables on first sync.
CREATE DATABASE healthbeat CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'healthbeat'@'%' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON healthbeat.* TO 'healthbeat'@'%';
FLUSH PRIVILEGES;If you're using MySQL 8.0+ and get authentication errors, switch to the legacy auth plugin:
ALTER USER 'healthbeat'@'%' IDENTIFIED WITH mysql_native_password BY 'your_password';After the initial full sync, the app automatically syncs new data in the background:
- Observer-based: HealthKit notifies the app immediately when new data is recorded (requires the app to have run recently)
- Scheduled: A background processing task runs periodically (approximately every 15 minutes, subject to iOS scheduling)
- Manual: Pull down on the Sync tab to trigger an incremental sync
Enable location tracking in Settings > Location & Places to log GPS coordinates to the location_tracks table. You can also set up geofences around places (home, office, gym, etc.) to log check-in and check-out events.
Go to Settings > Backup & Recovery to create manual backups or enable automatic backups. Backups are stored in iCloud Drive and include all app configuration (MySQL settings, geofences, place categories, sync state). They do not include health data itself — that lives in HealthKit and your database.
If you use the app on multiple devices, only one device performs automatic background syncs to avoid duplicate writes. Go to Settings > iCloud Sync to see registered devices and change which device is active.
HealthKit restricts data access when the device is locked. This affects background sync in important ways:
- Screen on / app in foreground: Full HealthKit access. All syncs work normally.
- Screen off but recently unlocked: HealthKit data remains accessible for a short window. Observer-based background syncs triggered by new health data (e.g., a workout ending) typically succeed because iOS delivers the notification while the device is still in this window.
- Screen off for a long time / device locked: HealthKit queries return authorization errors. The
BGProcessingTaskscheduled sync may wake the app, but if the device has been locked too long, HealthKit will deny access. The app handles this gracefully — it skips the sync and tries again next time. - Full sync requires screen on: A full historical backfill takes a long time and needs continuous HealthKit access. The app has a "Keep Screen On" toggle in settings for this reason. If the screen locks mid-sync, the sync pauses and resumes when access is restored.
In practice, incremental syncs work well because they're triggered by HealthKit observer queries right when new data is recorded (device typically just used), and the data volume per sync is small.
If your MySQL server is only reachable via VPN or Tailscale, be aware that iOS aggressively manages VPN connections:
- iOS may disconnect VPN tunnels in the background to save battery, especially on cellular.
- The "Connect On Demand" VPN setting helps but is not guaranteed — iOS can still tear down the tunnel when it decides the app doesn't need network access.
- Tailscale's iOS app uses the NEPacketTunnelProvider API, which is subject to the same iOS restrictions. The tunnel may go down during background sync windows.
- When the VPN is down, MySQL connections will fail with a timeout. The app will retry on the next sync cycle.
Workaround: If reliable background sync is important, expose your MySQL server on a network the phone can always reach (e.g., port-forwarded with TLS, or a cloud-hosted database). Alternatively, accept that some background syncs will be missed and rely on the next foreground sync to catch up.
BGProcessingTaskruns at iOS's discretion — typically when the device is charging and on Wi-Fi. The 15-minute interval is a request, not a guarantee.- iOS may defer background tasks indefinitely if the device is low on battery or the app hasn't been used recently.
- After a force-quit by the user (swipe up in app switcher), background tasks and observer queries stop until the app is launched again.
The app creates these tables automatically:
| Table | Contents |
|---|---|
health_quantity_samples |
All quantity type measurements (steps, heart rate, etc.) |
health_category_samples |
Category type events (sleep, symptoms, etc.) |
health_workouts |
Workout sessions |
health_blood_pressure |
Blood pressure correlation pairs |
health_ecg |
ECG recordings with voltage data |
health_audiograms |
Hearing sensitivity measurements |
health_activity_summaries |
Daily activity ring data |
health_workout_routes |
GPS coordinates from workout routes |
health_medications |
Medication records |
location_tracks |
GPS location history |
location_geofence_events |
Geofence entry/exit events |
All tables use UUID-based primary keys for deduplication and DATETIME(3) for millisecond precision timestamps in UTC.
This project is released under the MIT License. See LICENSE for details.