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-geolocationOr 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:
| Key | Why |
|---|---|
NSLocationWhenInUseUsageDescription | The foreground permission prompt. |
NSLocationAlwaysAndWhenInUseUsageDescription | The Always prompt. Without it iOS shows no upgrade option at all. |
NSMotionUsageDescription | Core Motion activity, which drives the moving/stationary machine. |
UIBackgroundModes → location | Lets 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:
Permissions — start() without
authorization produces no fixes.