I want to track users current location only on demand. I need only initial location, not continuos updates. I thought best way to do this would be sending silent notification to user in order to get user's current location once. Receiving silent notification works just fine, but LocationManager doesn't get initial fix on the location. My Location Manager Delegate class instantiates normally but doesn't fire didUpdateLocations function at any point after location manager method startUpdatingLocation() is called. When App starts normally from AppDelegate:didFinishLaunchingWithOptions, LocationManager updates users location without problems.
I'm 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)
}
}
I first tried only with line:
LocManager.locationMngr.startUpdatingLocation()
but when it didn't work I added background task and dispatch_after to make sure my location Manager would get enough time to retrieve first location update before termination.
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 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 received remote push:
"aps" : {
"sound" : "",
"content-available" : 1,
"priority" : 5
}
I have all required plist.info keys and background modes for fetch, notifications and location enabled in project Capabilities: Background Modes. plist.info snippet:
<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 browsed SO furiously for similar problem and couldn't find any helping solution including this question:
IOS - Running background task for update user location using swift
Periodic iOS background location updates
Core Location delegate methods not getting called in iOS 8.3 Xcode 6.3.1
Swift: location not being updated when returned from background
I came across the same issue and went through the exact steps as OP to no avail. Eventually I figured out that I only had requested CLLocationManager.requestWhenInUseAuthorization()
which only provides location when app is in foreground. I had to request CLLocationManager.requestAlwaysAuthorization()
in order for app to request location in background. Also make sure you have NSLocationAlwaysUsageDescription
entry in Info.plist
file. With these changes, I was able to use CLLocationManager.startUpdatingLocation()
directly and was able to receive the location updates in background.
When the app is launched in the background, calling startMonitoringSignificantLocationChanges()
before startUpdatingLocation()
worked for me.
Remember to call stopMonitoringSignificantLocationChanges()
and stopUpdatingLocation()
when you are finished.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With