Skip to content

Permissions & background location

iOS grants location in levels, and the jump from When In Use to Always is the one that decides whether this SDK can do its job. The rules are the platform’s, not the SDK’s, and they are unforgiving in a specific way: you usually get one chance at the Always prompt.

Requesting

let status = try await BackgroundGeolocation.requestPermission()

There is no requester object to construct (the Android SDK needs one; iOS does not). What the call does depends on where the user already is:

Current stateWhat happens
Not determinedThe standard prompt, offering When In Use.
When In Use, locationAuthorizationRequest = AlwaysiOS shows the Always upgrade prompt — once per install.
Denied, or Always already grantedNo prompt; the current status is returned.

The returned AuthorizationStatus is always, whenInUse, denied, restricted or notDetermined.

The Always prompt is a one-shot

iOS shows the When-In-Use → Always upgrade prompt once. Decline it, and calling requestPermission() again does nothing at all: no dialog, no error, the same status back. From then on the only path to Always is the user going to Settings themselves.

Two consequences worth designing around:

  • Ask when the value is obvious. Not at first launch — right after the user does the thing that needs background tracking.
  • Detect the dead end and explain it. If you asked and still have whenInUse, show your own screen pointing at Settings → your app → Location → Always. The SDK does not pop that alert for you; the RN and Flutter SDKs have a locationAuthorizationAlert config for it, and this facade deliberately does not port it — a native app can present a better one.

Precise location

Since iOS 14 a user can grant approximate location, a coarse grid that is useless for tracking: nearly every fix fails the accuracy gate. Read it from getProviderState():

let provider = await BackgroundGeolocation.getProviderState()
if provider.accuracyAuthorization == .reduced {
// Ask for a temporary upgrade, or explain why the map will be wrong.
let result = await BackgroundGeolocation.requestTemporaryFullAccuracy(purpose: "DeliverFullAccuracy")
}

purpose must be a key in your NSLocationTemporaryUsageDescriptionDictionary — if it is not, iOS may never call back at all, and the SDK’s 30-second watchdog resolves with the unchanged authorization rather than hanging.

Temporary full accuracy lasts until the app is next relaunched. It is a stopgap for a session, not a substitute for the user granting Precise.

What each level actually does

Always + Precise — everything in this documentation works: background fixes, force-quit relaunch, geofences.

When In Use — fixes arrive only while your app is in the foreground (plus a short grace period). The engine, the queue and the filter all keep working; the stream simply stops when the user leaves. Nothing announces it, which is why onProviderChange is worth subscribing to.

Approximate — fixes arrive but are coarse enough that the accuracy filter rejects most of them. A track that is mysteriously empty while permissions “look granted” is usually this.

Denied or Location Services off device-widestart() still succeeds and the engine still runs; it simply never receives a fix. Check getProviderState() rather than assuming the SDK is broken.

Core Motion

NSMotionUsageDescription covers activity recognition, which the motion state machine uses to notice you started moving. Denied, it falls back to speed and the wake region — departures are detected later, but tracking still works.

The blue indicator

While tracking with Always authorization, iOS may show the blue background-location pill. On the default session path this is not configurable: the session that keeps delivery alive in the background implies the indicator, and no API hides it. showsBackgroundLocationIndicator applies only to the legacy path (useSessionEngine: false), which trades reliability for a hidden indicator. When In Use always shows it, whatever the engine.