Store location data when app is not running using Xcode 15.1 and SwiftUI

I'm close but can't seem to get my app to store location data when not running. I'm trying to collect driver data. When I start the App it asks for location permission while using the App. At no time does the app ask me to give permission for allowing the app to collect information when I am not using the app. I think the problem revolves around this. I've also tried going into iOS settings for the app and set to Always but that didn't help. I'm likely missing something here within the app to get it to collect the data when the app is not running. Any help is appreciated.

Here is what I've got.

For Signing I have Background Modes enabled with "Location updates". For plist.info I have the following set with descriptions.

  • Privacy - Location Location Always Usage Description
  • Privacy - Location When in Use Usage Description
  • Privacy - LocationAways and When in Use Usage Description

I also have in the Info file: Required background modes with Item 0 set with "App registers for location updates"

for code I have the the following in the AppDelegate:

import UIKit
import CoreLocation

class AppDelegate: NSObject, UIApplicationDelegate {
    
    static let shared = AppDelegate()
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        // Add any custom setup code here
        return true
    }
}

extension AppDelegate {
    func requestLocationAuthorization() {
        let locationManager = CLLocationManager()
        locationManager.requestAlwaysAuthorization()
    }
}

For my app here is how I trigger the app delegate and starupt the location manager

import SwiftUI
import SwiftData

@main
struct ZenTracApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate    
    @Environment(\.scenePhase) var scenePhase
    @StateObject var locationManager = LocationManager()
    ...

for code I have the following LocationManager:

import CoreLocation
import SwiftData

@MainActor
class LocationManager: NSObject, ObservableObject {
    
    @Published var location: CLLocation?
    //@Published var region = MKCoordinateRegion()
    
    private let locationManager = CLLocationManager()
    
    /// Override exiting init
    override init() {
        /// Bring in the normal init
        super.init()
        
        AppDelegate.shared.requestLocationAuthorization()
        
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.distanceFilter = kCLDistanceFilterNone
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()
        locationManager.delegate = self
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.showsBackgroundLocationIndicator = true
        locationManager.startUpdatingLocation()
        
    }
}

extension LocationManager: CLLocationManagerDelegate {
    
    /// iOS triggers whenever the location changes
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        
        guard let newLocation = locations.last else {return}
        
        /// Check if the location has changed significantly before updating in this case more than 10 meters
        if self.location == nil || location!.distance(from: newLocation) > 10 {
            self.location = newLocation
            // save the location info in this function
            saveEntry(location: self.location!)
        }

    }
}

Some progress on permissions. By asking in the proper order I can now get the app to ask for both the permissions. For the AppDelegate I added the following:

extension AppDelegate {
    func requestLocationAuthorization() {
        let locationManager = CLLocationManager()
        locationManager.requestWhenInUseAuthorization()
        locationManager.requestAlwaysAuthorization()
    }
}

and in my LocationManager added the following to then immediate ask for Always:

    func locationManager(
        _ manager: CLLocationManager,
        didChangeAuthorization status: CLAuthorizationStatus
    ) {
        /// Handle location permission changes...
        
        /// This asks for Always Allow right after asking for When in Use
        if locationManager.authorizationStatus == .authorizedWhenInUse {
            AppDelegate.shared.requestLocationAuthorization()
        }
    }

Now the issue remains of how to collect location information when the app is not "active" or in the "background". I can't find any info on how to do this yet I know other apps out there do collect location information when the user is not "using" the app.

Store location data when app is not running using Xcode 15.1 and SwiftUI
 
 
Q