Skip to content
Support the creatorSupport

How iOS background tracking works

iOS has no equivalent of an Android foreground service. An app stays alive in the background for one of a few reasons, and for location tracking the reason is: location updates are running. So Long Ping keeps them running for as long as tracking is on, and controls cost by changing how precise they are, not by switching them off.

  • Standard location updates run the whole time, with allowsBackgroundLocationUpdates = true (only if UIBackgroundModes contains location), pausesLocationUpdatesAutomatically = false and no distance filter.
  • ios.activityType (default 'automotive') and ios.showsBackgroundLocationIndicator (default false) are passed to CoreLocation.
  • Significant-change monitoring is on as a safety net.
  • Fixes are recorded on your clock; everything between is ignored.

When the effective interval is 60 s or more, Long Ping asks CoreLocation for 3 km accuracy between fixes, which lets the GPS rest. 15 s before the next fix is due it switches to your configured accuracy (high → Best, balanced → HundredMeters, low → Kilometer), records the fix, and drops back.

Below 60 s the configured accuracy stays on the whole time: there isn’t enough time between fixes for the switch to pay off.

When the device parks, Long Ping also monitors a circular region around the parked position (radius max(100, stopRadiusM × 2), exit only). Leaving it switches to moving immediately and is one of the ways iOS can relaunch a terminated app. The region is removed when the device moves again or tracking stops.

With the default stopOnTerminate: false, Long Ping makes sure significant-change and region monitoring are on as the app terminates. If it was moving, it also puts a region around the last position, so the relaunch comes sooner than significant-change alone would bring it. When the device then moves far enough, iOS relaunches the app in the background. Long Ping registers for app launch in native code and resumes tracking before your JavaScript loads, if tracking was enabled and permission still allows it. No start() call needed.

What it means in practice: a swipe-away while parked loses the parked fixes until the van drives off; a swipe-away while driving loses fixes until iOS relaunches the app, typically within a few hundred meters.

Set stopOnTerminate: true if you’d rather a swipe-away stopped tracking for good.

After a reboot, an app that was tracking comes back the same way: on movement, iOS relaunches it and the engine resumes. If that happens before the phone’s first unlock, when the app’s saved state can’t be read yet, the engine logs it and resumes as soon as the phone is unlocked.

  • “While Using” instead of “Always”: the relaunch paths above (significant-change and region monitoring) need “Always”. For fleet use, ask for 'always'; see Permissions. If tracking is enabled but permission is missing at launch, the engine logs it and waits (and emits an error event with PERMISSION_DENIED if JavaScript is listening).
  • Precise Location off: fixes come with reduced accuracy (getProviderState().accuracyAuthorization === 'reduced'). With the default minAccuracyM: 100, many of them may be filtered out; the overdue rule still records the best available fix when one is late.
  • Low Power Mode: reported as powerSaveMode in getProviderState().
  • Uploads run on a serial queue with URLSession, wrapped in a background task so they finish when the app is suspended mid-request.
  • The queue is a SQLite file in Application Support, excluded from backups. Credentials are in the Keychain, wiped on the first launch after a (re)install.
  • getCurrentPosition() resolves early once a fix reaches 20 / 100 / 1000 m accuracy for high / balanced / low.