backgroundIOS.ts
Purpose
This module implements the two iOS background execution paths used during monitoring: a BGTaskScheduler-driven periodic fetch (fired every ~15–30 minutes by the OS) and a HealthKit event-driven path (fired each time the Apple Watch pushes a new heart rate sample). Together they provide periodic full prediction runs and more frequent model updates triggered by fresh HR data.
Its responsibilities include:
- Registering the background fetch task at module scope so it is available in headless app starts
- Running a 7-step prediction pipeline on each background wake
- Starting a 60-minute coprocessor accelerometer recording on each wake
- Reading 40-minute per-chunk CPM data, writing it to the CPM database, and using it as the CPM input
- Sending a local notification alert when core temperature exceeds the risk threshold
- Registering the task with the OS at a 15-minute minimum interval
- Providing a test trigger that re-registers and immediately fires the task in debug builds
- Requesting HealthKit authorization and enabling background delivery for heart rate samples
Invariants
Module-Scope Task Registration
TaskManager.defineTask is called at module load time, not inside a component or hook.
This is required because iOS can wake the app in a headless state before any React component mounts. The module must be imported at the top of App.tsx to guarantee registration happens before the first background wake.
Native Module Lazy Load
expo-background-task and expo-task-manager are loaded via lazy require() at module load time (iOS only).
If the native modules are unavailable (stale dev client), the load failure is caught, a warning is logged, and nativeBackgroundModules is set to null. All dependent functions degrade gracefully.
Coprocessor Minimum Data Guard
If getCPMFromRecordedAccelerometer returns null (fewer than 3 minutes of data available), the background task returns Success immediately without running prediction.
This prevents failed or low-confidence predictions from being persisted.
CPM Chunk Backfill
Each per-minute CPM chunk from the coprocessor is inserted into the CPM database with a reconstructed timestamp:
timestamp = now - (chunks.length - i) × 60,000 ms
This ensures the foreground pipeline has real CPM history available when the app comes to the foreground.
Risk Threshold Alert
A local notification is sent when coreTemp >= RISK_THRESHOLD.
The current RISK_THRESHOLD is 36°C (a temporary test value; the comment notes it should be changed to 38.5 for production).
HealthKit Background Delivery Mode
HealthKit background delivery uses immediate mode (1), meaning the app is woken as soon as each new heart rate sample arrives from Apple Watch.
Each wake runs a full makeHeatRiskPrediction(null) call (no CPM override) and persists and alerts on the result.
Variants
Seven-Step Pipeline
runBgFetchTask executes steps in a fixed numbered sequence logged at INFO level for traceability:
| Step | Action |
|---|---|
| 1 | iOS woke the app |
| 2 | Start coprocessor recording; query 40-min CPM |
| 3 | Write CPM chunks to DB; log latest-minute CPM |
| 4 | Run heat risk prediction with CPM override |
| 5 | Persist core temperature to DB |
| 6 | Check risk threshold and send alert if exceeded |
| 7 | Return Success to iOS |
Exports
IOS_BG_FETCH_TASK
const IOS_BG_FETCH_TASK = 'com.heatsafe.app.bg-fetch'
The task identifier string used for all TaskManager and BackgroundTask API calls.
isIOSBackgroundFetchAvailable()
function isIOSBackgroundFetchAvailable(): boolean
Returns true if running on iOS with the native background modules available.
runBgFetchTask()
async function runBgFetchTask(): Promise<IOSBackgroundTaskResult>
Executes the full 7-step background prediction pipeline. Also exported for the Debug screen’s “Simulate BG” button.
registerIOSBackgroundFetch()
async function registerIOSBackgroundFetch(): Promise<void>
Registers the background fetch task with a 15-minute minimum interval. No-ops on Android or when native modules are unavailable.
triggerIOSBackgroundFetchForTesting()
async function triggerIOSBackgroundFetchForTesting(): Promise<boolean>
Re-registers the task and calls triggerTaskWorkerForTestingAsync. For debug builds only. Returns true if the trigger succeeded.
setupHealthKitBackgroundDelivery()
async function setupHealthKitBackgroundDelivery(): Promise<void>
Requests HealthKit authorization for heart rate, enables immediate background delivery, and subscribes to HR change events. iOS only.