Skip to main content

Overview

Radar requires location permissions to track the user’s location. iOS provides two levels of location authorization:
  • When In Use - Location access only while the app is in the foreground
  • Always - Location access in both foreground and background
For background tracking, you must request Always authorization.

Required Info.plist Keys

Before requesting location permissions, you must add usage description strings to your app’s Info.plist file. These strings explain to users why your app needs location access.

Required Keys

<key>NSLocationWhenInUseUsageDescription</key>
<string>Your foreground location usage description goes here.</string>

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Your background location usage description goes here.</string>
Replace the placeholder text with a clear explanation of why your app needs location access. Be specific about the features that require location.

Optional Keys

If you’re using motion detection features:
<key>NSMotionUsageDescription</key>
<string>Your motion usage description goes here.</string>

Background Modes

For background tracking, you must enable the location background mode in your app’s capabilities:
<key>UIBackgroundModes</key>
<array>
  <string>location</string>
</array>
In Xcode, you can also enable this in your target’s Signing & Capabilities tab under Background Modes.

Requesting Permissions

iOS 13.4 and Later

On iOS 13.4 and later, you should request foreground permission first, then request background permission if granted:
import CoreLocation

class YourViewController: UIViewController, CLLocationManagerDelegate {
    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.delegate = self
        requestLocationPermissions()
    }
    
    func requestLocationPermissions() {
        let status: CLAuthorizationStatus
        
        if #available(iOS 14.0, *) {
            status = locationManager.authorizationStatus
        } else {
            status = CLLocationManager.authorizationStatus()
        }
        
        if #available(iOS 13.4, *) {
            // On iOS 13.4+, request foreground first, then background
            if status == .notDetermined {
                locationManager.requestWhenInUseAuthorization()
            } else if status == .authorizedWhenInUse {
                locationManager.requestAlwaysAuthorization()
            }
        } else {
            // On earlier versions, request always authorization directly
            locationManager.requestAlwaysAuthorization()
        }
    }
    
    // Handle authorization changes
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        requestLocationPermissions()
    }
}
On iOS 13.4 and later, the OS will show the background permission prompt in-app after the user grants foreground permission.

Before iOS 13.4

On iOS 13.0-13.3, request Always authorization directly. The OS will show a foreground prompt in-app, then show a background prompt later at a time determined by the OS.
The background permission prompt on iOS 13.0-13.3 appears outside of your app after the user has been using the app for a while. Make sure to educate users about this behavior.

Permission States

The CLAuthorizationStatus enum defines the possible permission states:
The user has not yet been asked for location permission. Call requestWhenInUseAuthorization() or requestAlwaysAuthorization() to prompt the user.
The user has granted foreground (When In Use) location permission. You can request Always authorization by calling requestAlwaysAuthorization().
The user has granted background (Always) location permission. This is required for Radar background tracking.
The user has explicitly denied location permission. You should direct users to Settings to change the permission.
if status == .denied {
    // Show alert directing user to Settings
    let alert = UIAlertController(
        title: "Location Permission Required",
        message: "Please enable location access in Settings to use this feature.",
        preferredStyle: .alert
    )
    
    alert.addAction(UIAlertAction(title: "Open Settings", style: .default) { _ in
        if let settingsUrl = URL(string: UIApplication.openSettingsURLString) {
            UIApplication.shared.open(settingsUrl)
        }
    })
    
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
    present(alert, animated: true)
}
Location services are restricted, typically due to parental controls or enterprise device management. Your app cannot request permission.

Checking Current Authorization

You can check the current authorization status at any time:
import CoreLocation

let status: CLAuthorizationStatus

if #available(iOS 14.0, *) {
    // iOS 14+ - use instance property
    status = locationManager.authorizationStatus
} else {
    // iOS 13 and earlier - use class method
    status = CLLocationManager.authorizationStatus()
}

switch status {
case .notDetermined:
    print("Permission not requested yet")
case .authorizedWhenInUse:
    print("Foreground permission granted")
case .authorizedAlways:
    print("Background permission granted")
case .denied:
    print("Permission denied")
case .restricted:
    print("Permission restricted")
@unknown default:
    print("Unknown status")
}

Provisional “Allow Once” Permission

Starting with iOS 14, users can choose “Allow Once” which grants temporary permission that expires when the app is backgrounded. If the user selects this option, authorizationStatus will return .authorizedWhenInUse, but permission will need to be re-requested the next time the app is launched.

Best Practices

1

Explain before requesting

Show an explanation screen or alert before requesting permission. Explain what features require location access and how it benefits the user.
func showLocationPermissionExplanation() {
    let alert = UIAlertController(
        title: "Location Access",
        message: "We use your location to show nearby stores and provide accurate delivery estimates.",
        preferredStyle: .alert
    )
    
    alert.addAction(UIAlertAction(title: "Continue", style: .default) { _ in
        self.locationManager.requestWhenInUseAuthorization()
    })
    
    present(alert, animated: true)
}
2

Request at the right time

Don’t request permission on app launch. Wait until the user is about to use a location-dependent feature.
3

Use clear usage descriptions

Write clear, specific Info.plist usage descriptions that explain the value to users. Avoid generic text.Good: “We use your location to show nearby restaurants and provide delivery tracking.”Bad: “This app requires location access to function.”
4

Handle permission changes

Implement locationManagerDidChangeAuthorization to handle when users change permissions in Settings.
5

Gracefully handle denial

If permission is denied, degrade gracefully and provide an option to open Settings.
6

Request progressively

On iOS 13.4+, request When In Use first, then upgrade to Always only when needed.

Radar Status Codes

When calling Radar SDK methods, you may receive permission-related status codes:
Radar.trackOnce { status, location, events, user in
    switch status {
    case .errorPermissions:
        print("Location permissions not granted")
        // Show permission request UI
    case .success:
        print("Location tracked successfully")
    default:
        print("Other error: \(status)")
    }
}

Testing Permissions

When testing, you can reset permissions for your app:
  1. Open the Settings app
  2. Go to Privacy & Security > Location Services
  3. Find your app and change the permission
  4. Or use the Simulator: Features > Location > Custom Location
To completely reset permissions:
# Reset permissions for your app (on Simulator)
xcrun simctl privacy <device-id> reset location <bundle-id>

Common Issues

Make sure you have:
  1. Added NSLocationAlwaysAndWhenInUseUsageDescription to Info.plist
  2. Enabled the location background mode
  3. Called requestAlwaysAuthorization() after receiving When In Use permission
Check that:
  1. Usage description keys are present in Info.plist
  2. You’re calling the request method on the main thread
  3. You haven’t already been denied (check authorization status)
  4. Your CLLocationManager instance isn’t being deallocated
Users can change permissions in Settings at any time. Monitor authorization changes with the delegate callback and adjust your app’s behavior accordingly.