Skip to content

Installation

Requirements

  • iOS 15.5+
  • Xcode 26.6 or newer — see the toolchain note below, it is not optional
  • Swift concurrency (async/await); the API is @MainActor-isolated

See Compatibility for the full matrix.

Add the package

In Xcode: File → Add Package Dependencies…, then

https://github.com/dc-bgeo/ios-background-geolocation

Or in a Package.swift:

dependencies: [
.package(url: "https://github.com/dc-bgeo/ios-background-geolocation", from: "0.1.0"),
],
targets: [
.target(name: "YourApp", dependencies: [
.product(name: "BackgroundGeolocation", package: "ios-background-geolocation"),
]),
]

The closed engine (BGeoCore.xcframework) is vendored in the package, so there is nothing else to download and no checksum to keep in step.

Info.plist — four keys, none optional

The engine cannot obtain Always authorization or run location updates in the background without all four:

KeyWhy
NSLocationWhenInUseUsageDescriptionThe foreground permission prompt.
NSLocationAlwaysAndWhenInUseUsageDescriptionThe Always prompt. Without it iOS shows no upgrade option at all.
NSMotionUsageDescriptionCore Motion activity, which drives the moving/stationary machine.
UIBackgroundModeslocationLets the app receive location while backgrounded. Missing it is the single most common “it works in the foreground and dies in the background” report.
<key>NSLocationWhenInUseUsageDescription</key>
<string>Shows your location on the map.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Keeps recording your route while the app is in the background.</string>
<key>NSMotionUsageDescription</key>
<string>Detects when you start and stop moving.</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>

Write the strings for a reviewer as much as for a user: App Review rejects background-location apps whose purpose strings do not explain a benefit the user gets while the app is not open.

If you call requestTemporaryFullAccuracy(purpose:), add NSLocationTemporaryUsageDescriptionDictionary as well, with your purpose as one of its keys. If the key is missing, iOS may never call the completion — the SDK bounds that with a 30-second watchdog rather than hanging forever, but a timed-out prompt is not a granted one.

License key

The key goes in Info.plist, not in Config:

<key>BGeoLicense</key>
<string>BGEO1....YOUR_KEY</string>

Debug builds and the Simulator run unlicensed, so a missing key first shows up in a TestFlight build. See License keys.

No registration call

There is no attach() or registerHeadlessTask() step here, unlike the Android SDK and the two cross-platform ones. The engine installs its own launch observer, so a process that iOS relaunches for a location event brings the engine up before your code runs; ready() attaches the event hub, and events that arrived before any subscriber existed are replayed to the first one.

Verify the install

Task {
let state = try await BackgroundGeolocation.ready(Config(distanceFilter: 10))
print("ready, enabled:", state.enabled)
}

A ready() that returns without throwing means the engine is up, the plist is readable and (in a release build) the license is accepted. Next: Permissionsstart() without authorization produces no fixes.