Being notified when user turns on location services iOS 7 and up - ios

I am faced with a situation where we would like to kick off a particular process based on whether or not a user has locations services enabled or not. This part is trivial. However, we want to extend this functionality by changing our process if the user turns the locations services off or on. We currently are able to monitor, and change or process, when the user turns off location services. My question is, how can our app be notified when the user turns locations services back on?
Here is what we are currently working with
iOS 7
Background Location Mode is enabled
We are using request always for location services
Here is what we tried
We have tried setting a timer after a user turns off the location service to periodically check if the user turns back on the location service. This is less than desirable for many reasons. Besides that the timer is killed once location services is turned off because background services is no longer needed and the OS kills our process. This is understandable.
We also went the approach of notifying the user that they just stopped a process and they need to turn location services back on. There are two problems with this approach.
If the user does not have notifications enabled then this approach is no good at all.
If they do have notifications enable then we first need the user to turn the location services back on and then they would need to open the app back up to get our app to "wake" back up.
Thank you in advance!

After hours of research and implement trying to a solution we have discovered that this is not possible as of iOS 8. For reference here is what we found:
We were able to be notified when the user had shut off the location services, ONLY if they shut off location services to our app. We did not receive a notification if the user shut off the main location services.
We did not receive a message if the locations services was turned back on, regardless, if it was our location service or the main location service.
You cannot use a timer approach because the timer is killed if the app is sent to background. So we could not have periodically checked. This would not have been acceptable for our use case but it was worth entertaining
You can still call CLLocationManager as if you had permission to use location service, even if you don't have permissions.
If you do call the CLLocationManager you will start receiving location messages, after permissions have been granted to your app, without having to re-register to receive location messages.
Our solution:
The combination of 4 and 5 was our saving grace. We were faced with an edge case where a user could have been eligible for a location event trigger but previously had denied use the location services and then after becoming eligible the user grants us permission to use location services. After doing a little refactoring we moved our location manager so we would register for location event updates, specifically geofencing, even if we did not have permissions. After testing we found that in the edge case event we started receiving location updates even without having to reinitialize the location manager. The same applies to beacon region monitoring for anyone interested.

Just check your location services after app has entered foreground.
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterForeground), name: UIApplication.didEnterForegroundNotification, object: nil)
func applicationDidEnterForeground() {
print("Location services enabled? \(CLLocationManager.locationServicesEnabled())")
}

Related

iOS: Location Update in Application Suspended State

Is it possible to update location when application is in suspended/terminate state.
i want to update location every 500 meters when app is in suspended/terminate state.
thanks in advance.
When terminated the only real way to get updates is to use Region Monitoring but you will only get major updates so I doubt it will work for 500 meters.
From the documentation:
If your app is terminated either by a user or by the system, the
system doesn't automatically restart your app when new location
updates arrive. A user must explicitly relaunch your app before the
delivery of location updates resumes. The only way to have your app
relaunched automatically is to use region monitoring or
significant-change location service. However, when a user disables the
Background App Refresh setting either globally or specifically for
your app, the system doesn't relaunch your app for any location
events, including significant change or region monitoring events.
Further, while Background App Refresh is off your app won't receive
significant change or region monitoring events even when it's in the
foreground.
There are good reasons for this. Firstly people don't want apps that 'snoop' on them all the time and even if there is a good reason imagine having 10 apps doing this constantly. It's going to start causing you performance and battery life issues.
EDIT
There appears to be some confusion by a lot of people over this issue so I will attempt to clear things up a bit.
Your app is NOT supposed to be continually tracking location while terminated (or suspended really). You are just not allowed to do this both for privacy reasons and so that you don't drain the battery excessively.
While your app is in the foreground you can use location services via startUpdatingLocation to monitor the device location. Assuming the app has been granted permission this will use all available hardware (GPS, WiFi, Cellular).
Now from the documentation itself:
If you start this service and your app is suspended, the system stops
the delivery of events until your app starts running again (either in
the foreground or background). If your app is terminated, the delivery
of new location events stops altogether. Therefore, if your app needs
to receive location events while in the background, it must include
the UIBackgroundModes key (with the location value) in its Info.plist
file.
So once suspended and terminated your options are really to monitor regions and to monitor for significant location changes. Neither of these are particularly accurate or frequent. One reason for this is that they only use low power methods to get the position (WiFi and Cellular) they don't use the GPS.
So no accurate and/or frequent location tracking while an app is suspended or terminated. This just has to be accepted and you need to design your apps accordingly.
let locationManager = CLLocationManager()
locationManager.startMonitoringSignificantLocationChanges()
After returning a current location fix, the receiver generates update events only when a significant change in the user’s location is detected. It does not rely on the value in the distanceFilter property to generate events
If you start this service and your app is subsequently terminated, the system automatically relaunches the app into the background if a new event arrives. In such a case, the options dictionary passed to the application(:willFinishLaunchingWithOptions:) and application(:didFinishLaunchingWithOptions:) methods of your app delegate contains the key location to indicate that your app was launched because of a location event. Upon relaunch, you must still configure a location manager object and call this method to continue receiving location events. When you restart location services, the current event is delivered to your delegate immediately. In addition, the location property of your location manager object is populated with the most recent location object even before you start location services.
Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.
Hope It helps

I am not getting user current running location after Terminate the Application

I require the user running location and route map path, When an application is Terminate or Background mode.
Currently I am using significant location for application kill mode, but we are not getting proper distance and route.
Because didUpdateLocations is called after some specific interval so that I am not getting proper distance.
Please guide.
According to Apple docs :
Apps can expect a notification as soon as the device moves 500 meters
or more from its previous notification. It should not expect
notifications more frequently than once every five minutes. If the
device is able to retrieve data from the network, the location manager
is much more likely to deliver notifications in a timely manner.
This is why startMonitoringSignificantLocationChanges() would not work reliably for tracking user location change other than driving/public-transport.
Now, coming back to your problem of having to track user location when app is terminated, unfortunately you cannot track location when the app is terminated
If your app is terminated either by a user or by the system, the system doesn’t automatically restart your app when new location updates arrive. A user must explicitly relaunch your app before the delivery of location updates resumes. The only way to have your app relaunched automatically is to use region monitoring or the significant-change location service.

Does location update remain running after force close app

I am sending user location at n time on server for tracking. Working fine in foreground and background mode. But my question is bit more theoretical.. Does my location update service remain running after i force close the app on the device?
I know i can check it on server, But sorry i don't have server access permission. So i have to be sure in which scenario my location service will stop running.
Yep it will continue to be updated when the application is sent into the background. For some official docs check here under the "Getting Location Events in the Background (iOS Only)" section.
Also, under special circumstances you can register your application to have a true background process running like Android allows. So when the user kills the background application, your app doesn't really die. The background process continues to work. Apple will only allow apps that have a necessary reason for this though. Such as a turn by turn navigation app (example from the docs).
Yes, if the application is removed from background then location update will be stopped.
iOS will only restart an app after a force close if its uses region monitoring or the significant-change location service. From the iOS Location and Maps Programming Guide section on Getting the User’s Location:
If your app is terminated either by a user or by the system, the system doesn’t automatically restart your app when new location updates arrive. A user must explicitly relaunch your app before the delivery of location updates resumes. The only way to have your app relaunched automatically is to use region monitoring or the significant-change location service.
iOS only restarts the app if it has Background App Refresh enabled:
when a user disables the Background App Refresh setting either globally or specifically for your app, the system doesn’t relaunch your app for any location events, including significant-change or region monitoring events.

iOS: Notify a WebService of location change (using Significant-Change Location Service)

I'm developing an app that allows me to track the device's location, the idea is that the app notifies every few hours our servers of the current location so I can send relevant push notifications to the user.
This should work even if the app is not running (the app should be awakened by the OS).
I was reading the Location Awareness Programming Guide (http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html) and I think the Significant-Change Location Service would help me accomplish this, however the guide mentions this:
it should do minimal work and avoid any tasks (such as querying the
network) that might prevent it from returning before the allocated
time expires.
If this is the case, I don't think I will be able to notify our servers of the location change.
I'm assuming this is possible because there are apps like "Find My Phone" that have to get the updated location of the devices every once in a while.
If this is not the right approach I would appreciate any pointers to info on what should I do to get this working.
Thanks

Getting user's location while making a phone call

I need to get exact location (as much accurate as possible) in background while making a call to a phone number (The call will be made from app). As far as I understand from documentation, I can listen to significant changes of location in background. I am wondering how accurate is a significant update and when will it trigger.
I need the location where the call is made because it will be an emergency call. And it's not a good idea to listen to location in foreground and then make a call because it will be an emergency situation - call will be made immediately.
Is there a solution to get accurate location of user in background? What do you recommend?
Edit: Location will be sent to server immediately.
As for the accuracy, you can get accurate location in the background, under those conditions:
Getting Location Events in the Background
If your application needs location updates delivered whether the application is in the foreground or background, there are multiple options for doing so. The preferred option is to use the significant location change service to wake your application at appropriate times to handle new events. However, if your application needs to use the standard location service, you can declare your application as needing background location services.
An application should request background location services only if the absence of those services would impair its ability to operate. In addition, any application that requests background location services should use those services to provide a tangible benefit to the user. For example, a turn-by-turn navigation application would be a likely candidate for background location services because of its need to track the user’s position and report when it is time to make the next turn.
As for getting location during phone call, I didn't use it myself, but navigation apps like 'waze' do inform turns and navigation events during a phone call so I guess what you ask is possible.
If I understand your needs, you have 2 options:
If you think that the user will be static then simply get the user location right before the call is made. Or better when your app is lunched to make the emergency call.
If the user is moving then you can 'ask' to get background location events. Even then you should consider using 'significant-change location service' as you don't need more then the user location. The standard 'location services' are used for navigation 'Turn by turn' services.
*LAST COMMENT *
If your app is an emergency app you shold read the "Tips for Conserving Battery Power" in the previous link. you don't want your user battery to empty while tracking his location.
Can't you like add that flag in your app plist file to request Location Service to be running in the background mode.
Then in your app, when the user presses the "call" button, you can do your normal CLLocationManager didUpdateToLocation, right before you perform the call.
In your didUpdateToLocation method, you can record the user's location either in a TXT file written to the application sandbox Library/Cache folder or you can use NSUserDefaults.
Note: I've written an app that records the user's GPS location as they drive even when the user presses the lock screen, so I am confident your app can write the GPS coordinate to a TXT file even when the app is minimized, as long as you start your location manager.

Resources