How to update user location on demand with silent push notifications? IOS

I want to track the current location of users on demand only. I only need the original location, not continuous updates. I thought the best way to do this would be to send a silent notification to the user to get the user's current location once. Getting the silent notification works pretty well, but the LocationManager doesn't get the initial fix at the location. My location manager. The delegate class is usually instantiated, but does not run the didUpdateLocations function anytime after the location manager's startUpdatingLocation () method is called. When the app launches normally from AppDelegate: didFinishLaunchingWithOptions, the LocationManager updates the users' location without issue.

I am developing on Xcode 6.3.2 to iOS 8.3

My AppDelegate: DidReceiveRemoteNotification looks like this:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {

    var bgTask = bgManager()
    bgTask.registerBackgroundTask()
    LocManager.locationMngr.startUpdatingLocation() // LocManager is global variable

    let delayInSeconds = 8.0
    let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delayInSeconds * Double(NSEC_PER_SEC)))
    dispatch_after(popTime, dispatch_get_main_queue()) {
            println(LocManager.updated)
            bgTask.endBackgroundTask()
            handler(UIBackgroundFetchResult.NewData)
    }
}

      

At first I tried only the line:

LocManager.locationMngr.startUpdatingLocation()

      

but when that didn't work, I added a background task and a dispatch_after to make sure my location manager gets enough time to restore the first location update to completion.

Here is the LocationManager class:

class LocationManager: NSObject, CLLocationManagerDelegate {
let locationMngr:CLLocationManager
var coord:CLLocationCoordinate2D
var updated:Bool
    override init() {
        locationMngr = CLLocationManager()
        coord = CLLocationCoordinate2D()
        updated = false
        super.init()
        locationMngr.delegate = self
        locationMngr.desiredAccuracy = kCLLocationAccuracyHundredMeters

        locationMngr.startUpdatingLocation() //Should call didUpdateLocations after some time
    }

    //Doesn't get called in AppDelegate remoteNotifications method
    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
    {
        var loc:CLLocation = locations.first as! CLLocation
        self.coord = loc.coordinate
        locationMngr.stopUpdatingLocation()
        updated = true
    }

      

and the background manager class:

class bgManager:NSObject{
    var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
    override init(){
        super.init()
    }
    func registerBackgroundTask() {
        backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler {
        [unowned self] in
        self.endBackgroundTask()
        }
    }

    func endBackgroundTask() {
        UIApplication.sharedApplication().endBackgroundTask(backgroundTask)
        backgroundTask = UIBackgroundTaskInvalid
    }
}

      

JSON of the received remote click:

"aps" : {
        "sound" : "",
        "content-available" : 1,
        "priority" : 5
    }

      

I have all the required plist.info keys and background modes for selection, notifications and location included in the project. Features: Background modes. plist.info:

<dict>
    <key>UIRequiredDeviceCapabilities</key>
    <array>
        <string>location-services</string>
        <string></string>
        <string></string>
    </array>
    <key>UIBackgroundModes</key>
    <array>
        <string>remote-notification</string>
        <string>fetch</string>
        <string>location</string>
    </array>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Your location is needed for this app.</string>
    ...

      

I've searched so much for a similar issue and haven't found any helpful solution including this question:

IOS - Run background task to update user location with quick

IOS background location updates periodically

Main location delegation methods not called in iOS 8.3 Xcode 6.3.1

Swift: location not updating when returning from background

+3


source to share


2 answers


I ran into the same problem and went through the exact steps like the OP to no avail. I eventually figured out that I only requested CLLocationManager.requestWhenInUseAuthorization()

that only provides the location when the app is in the foreground. I had to request CLLocationManager.requestAlwaysAuthorization()

that the app ask for a location in the background. Also make sure you have an entry NSLocationAlwaysUsageDescription

in the file Info.plist

. With these changes I was able to use directly CLLocationManager.startUpdatingLocation()

and was able to get location updates in the background.



+1


source


When the app is running in the background, the call startMonitoringSignificantLocationChanges()

to before startUpdatingLocation()

worked for me.



Don't forget to call stopMonitoringSignificantLocationChanges()

and stopUpdatingLocation()

when you're done.

0


source







All Articles