Skip to content

Setup

Installation

Swift Package Manager is the only supported installation method.

In Xcode: File → Add Package Dependencies, enter the repository URL:

https://github.com/transistorsoft/native-background-geolocation

Select Up to Next Major Version from the latest release, then add the BackgroundGeolocation library to your target.

Configure your license

Purchase a license

The SDK requires a license for release builds. Debug builds work without one. Purchase at transistorsoft.com.

Add your license key to Info.plist:

<key>TSLocationManagerLicense</key>
<string>YOUR_LICENSE_KEY_JWT</string>

Info.plist

Background Modes

<key>UIBackgroundModes</key>
<array>
    <string>location</string>
    <string>fetch</string>
    <string>processing</string>
    <string>audio</string>
</array>

Background Task Identifiers

<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
    <string>com.transistorsoft.fetch</string>
</array>

Location Usage Descriptions

iOS requires a human-readable explanation for each level of location access your app requests.

<!-- Location usage descriptions -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>App requires location access at all times for background tracking.</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>App requires location access while in use.</string>

<key>NSMotionUsageDescription</key>
<string>Motion detection helps determine when the device is stationary.</string>

Example

import SwiftUI
import BackgroundGeolocation

@main
struct MyApp: App {
    private var subscriptions = Set<BGGeo.EventSubscription>()

    init() {
        let bgGeo = BGGeo.shared

        // Register event listeners *before* calling ready()
        bgGeo.onLocation { event in
            print("[onLocation] \(event.coords)")
        }.store(in: &subscriptions)

        // ready() configures the SDK and restores persisted state.
        // It does NOT start tracking — call start()/stop() separately.
        bgGeo.ready { config in
            config.geolocation.desiredAccuracy = kCLLocationAccuracyBest
            config.geolocation.distanceFilter = 10
            config.app.stopOnTerminate = false
            config.app.startOnBoot = true
            config.logger.debug = true
            config.logger.logLevel = .verbose
        }
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

// Elsewhere — e.g. a toggle-button action in your UI
struct TrackingButton: View {
    @State private var isTracking = BGGeo.shared.state.enabled

    var body: some View {
        Button(isTracking ? "Stop" : "Start") {
            Task {
                let bgGeo = BGGeo.shared
                if isTracking {
                    bgGeo.stop()
                } else {
                    try await bgGeo.start()
                }
                isTracking = bgGeo.state.enabled
            }
        }
    }
}