Samuel Hayden
Samuel Hayden

Reputation: 142

Cannot keep GPS active with app in background, or read location with app in foreground or background

The app pertinent to this question is meant to track user location with a high degree of precision, including GPS coordinates and accelerometer readings, for a time period of 30 minutes, even if the user has pressed the sleep button.

To this ends, the plist file and app capabilities settings have been changed to reflect the reason for always on navigation access and to enable background processes for the provision of location based services.

The app does ask the user for GPS permissions when it is run, and if they are granted, the activation of this view controller (the view controller that contains the following code) does cause the GPS/Navigation icon to display on an iPhone.

The problem is, so far none of the four "print" commands seen below result in any printed messages, and so the "newLocation" and "myLocation" variables both do not yield any data. If this code is remotely close to being able to serve the purpose outlined in the first sentence, then the question is "How can it be fixed?". If this is a bad way to accomplish the goal, then a better answer would explain how this should be done.

import UIKit
import CoreMotion
import MapKit
import CoreLocation

class ActiveSession: UIViewController, CLLocationManagerDelegate {
        lazy var locationManager: CLLocationManager! = {
        let manager = CLLocationManager()
        manager.desiredAccuracy = kCLLocationAccuracyBest
        manager.delegate = self
        return manager
    }()

    func locationManager(_manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
        let myLocation:CLLocationCoordinate2D=CLLocationCoordinate2DMake(oldLocation.coordinate.latitude, oldLocation.coordinate.longitude)
        print(myLocation)

        if UIApplication.shared.applicationState == .active {
            print("at least it's active at all")
        } else {
            print(newLocation)
            print("it's active when the app isn't")
        }
    }

     func getPermission () {
        locationManager = CLLocationManager()

        switch CLLocationManager.authorizationStatus() {
        case .denied, .restricted:
            return
        case .notDetermined:
            locationManager!.requestAlwaysAuthorization()
            break
        case .authorizedAlways, .authorizedWhenInUse:
            break
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.getPermission()
        locationManager = CLLocationManager()
        locationManager!.desiredAccuracy = kCLLocationAccuracyBest
        locationManager?.startUpdatingLocation()
    }
}

Upvotes: 0

Views: 570

Answers (2)

Samuel Hayden
Samuel Hayden

Reputation: 142

As ohr pointed out, an additional permission was required. The following line was added to the lazy locationManager initializer to rectify this omission:

manager.allowsBackgroundLocationUpdates = true

In accordance with Noah and Paulw11's advice, the getPermission function was deleted, and the line:

locationManager = CLLocationManager()

was removed from viewDidLoad, as there was a great deal of redundancy present. This alone did not fix the problems, but adding logic to the locationManager func so that recent map data was stored to an array, like so:

let annotation = MKPointAnnotation()
annotation.coordinate = newLocation.coordinate    
locations.append(annotation)
while locations.count > 100 {
    let annotationToRemove = locations.first!
    locations.remove(at: 0)
}

resulted in working code. This solution was derived from code found here: https://www.raywenderlich.com/92428/background-modes-ios-swift-tutorial (Thanks, Ray)

Ultimately the code functioned in the foreground and background without removing anything from the class or implementing anything in appdelegate.

Upvotes: 0

Noah Witherspoon
Noah Witherspoon

Reputation: 57149

You’re creating new CLLocationManager instances in three places—the lazy locationManager initializer, getPermission, and viewDidLoad—and in the latter two of those, you’re neither setting the desired accuracy nor the delegate. Delete the locationManager = CLLocationManager() lines and you should have better results.

Upvotes: 1

Related Questions