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
source to share
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.
source to share