As per iOS CLLocationManager API startmonitoringsignificantlocationchanges will inform my app when there is significant change e.g. 500 mtrs or more.
But i want in my app like my app will get notified only when user/device enters into new city. App should automatically open if its in closed state.
NOTE: its not map/navigation application, so i don't want to my app keep monitoring user's location data and at the end drain device's battery.
Please suggest some solution.
It will execute your application. (sorry that it's not a comment - but it's too long for comment).
See details below (from Apple Documentation)
To start region monitoring, configure the appropriate region object and pass it to the startMonitoringForRegion: method of your location manager. In iOS, registered regions persist between launches of your app. If a region boundary crossing occurs while your iOS app is not running, the system automatically wakes it up (or relaunches it) in the background so that it can process the event. In this case, the options dictionary passed to the application:didFinishLaunchingWithOptions: method of your app delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your app was launched because of a location-related event. During the relaunch process, you must recreate your location manager object and assign a delegate capable of handling region-related events. After you do that, the system delivers the region notification for which your app was launched. All of the regions you configured previously are made available in the monitoredRegions property of any location manager objects you create.
I think you need method of CLLocationManager class:
- (void)startMonitoringForRegion:(CLRegion *)region
Parameters
region
The region object that defines the boundary to monitor. This parameter must not be nil.
Discussion
You must call this method once for each region you want to monitor. If an existing region with the same identifier is already being monitored by the app, the old region is replaced by the new one. The regions you add using this method are shared by all location manager objects in your app and stored in the monitoredRegions property.
Region events are delivered to the locationManager:didEnterRegion: and locationManager:didExitRegion: methods of your delegate. If there is an error, the location manager calls the locationManager:monitoringDidFailForRegion:withError: method of your delegate instead.
An app can register up to 20 regions at a time. In order to report region changes in a timely manner, the region monitoring service requires network connectivity.
Related
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 trying to listen for iBeacons when my app is not running (the user quit the app and it is not running in the background).
I have specified the Bluetooth LE Background Mode and can listen for and receive sightings when the app is active and in the background. However, I am having a difficult time figuring out how to implement the same functionality for when my app is not running.
I've been reading the Core Bluetooth guide and trying to implement CBCentralManagerDelegate - if that is the correct solution for this scenario. I don't understand where I implement the CBCentralManagerDelegate. Do I implement it in the AppDelegate or in the view controller that handles beacon sightings? Do I have to declare a CBCentralManager? What do I do in centralManagerDidUpdateState:?
I don't care about restoring or preserving state, I just want my application to receive beacon sightings when it is not running.
I have added the NSLocationAlwaysUsageDescription and am asking for permission for the location.
Let me know if I can provide more information.
Apple treats iBeacon support differently than other BLE services.
It considers iBeacons monitoring to be a Location Manager service.
You want to add the NSLocationAlwaysUsageDescription key to your app's info.plist.
At startup, you want to check the location manager's authorization status, and if it's not kCLAuthorizationStatusAuthorizedAlways then you want to request it. That code looks like this:
CLAuthorizationStatus status =[CLLocationManager authorizationStatus];
if (status != kCLAuthorizationStatusAuthorizedAlways
&& [self.theLocManager respondsToSelector:
#selector(requestAlwaysAuthorization)])
{
[self.theLocManager requestAlwaysAuthorization];
}
EDIT:
In your app delegate's application:didFinishLaunchingWithOptions: method, you need to check the options for the key UIApplicationLaunchOptionsLocationKey.
To quote the relevant part of the CLLocationManager Class Reference:
If a region boundary crossing occurs while your iOS app is not
running, the system automatically wakes it up (or relaunches it) in
the background so that it can process the event. In this case, the
options dictionary passed to the
application:didFinishLaunchingWithOptions: method of your app delegate
contains the key UIApplicationLaunchOptionsLocationKey to indicate
that your app was launched because of a location-related event. During
the relaunch process, you must recreate your location manager object
and assign a delegate capable of handling region-related events. After
you do that, the system delivers the region notification for which
your app was launched. All of the regions you configured previously
are made available in the monitoredRegions property of any location
manager objects you create.
I have gone through many tutorials but not able to find the right solution. I am working on location base application where I need to fetch user's current location, it doesn't matter even if the application is running in foreground or in background. So when i kill or terminate the application is it possible to fetch user's current location?
Yes it is possible. You will have to use method startMonitoringSignificantLocationChanges. According to CLLocationManager documentation
If you start this service and your application is subsequently
terminated, the system automatically relaunches the application into
the background if a new event arrives. In such a case, the options
dictionary passed to the application:didFinishLaunchingWithOptions:
method of your application delegate contains the key
UIApplicationLaunchOptionsLocationKey to indicate that your
application 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.
I am building an app, that has location updates enabled in the background, for this I am using an instance of CLLocationManager with the following code:
self.coreLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.coreLocationManager startMonitoringSignificantLocationChanges];
I implemented its delegate callback - (void)locationManager:(CLLocationManager *)locationManager didUpdateLocations:(NSArray *)locations, in which I trigger a network request to Google in order to reverse geocode the coordinates and retrieve the address of the location.
This does work very well if the app is in the foreground, but in the background it it doesn't seem to work. I have difficulties debugging it for testing as well, because I can't access the logs when the app is in the background (so I used Mixpanel, an analytics framework to capture the location updates as events, but apparently they don't work either).
In order to receive significant location change updates in the background you need to restart location services when your app is launched into the background - your delegate methods won't be called unless you do this.
From the Location And Maps Programming Guide -
If you are monitoring regions or using the significant-change location
service in your app, there are situations where you must start
location services at launch time. Apps using those services can be
terminated and subsequently relaunched when new location events
arrive. Although the app itself is relaunched, location services are
not started automatically. When an app is relaunched because of a
location update, the launch options dictionary passed to your
application:willFinishLaunchingWithOptions: or
application:didFinishLaunchingWithOptions: method contains the
UIApplicationLaunchOptionsLocationKey key. The presence of that key
signals that new location data is waiting to be delivered to your app.
To obtain that data, you must create a new CLLocationManager object
and restart the location services that you had running prior to your
app’s termination. When you restart those services, the location
manager delivers all pending location updates to its delegate.
Also, when you are launched into the background you should not perform network operations unless you request additional execution time. From the Location and Maps Programming Guide again -
Because your app is in the background, it must do minimal work and
avoid any tasks (such as querying the network) that might prevent it
from returning before the allocated time expires. If it does not, your
app will be terminated. If an iOS app needs more time to process the
location data, it can request more background execution time using the
beginBackgroundTaskWithName:expirationHandler: method of the
UIApplication class.
Foursquare always tracks geolocation (even when it's turned off).
On the image you can see that it tracks geolocation right now, but I turned it off, so when I double press home button I don't see Foursquare app.
Is it but of iOS7, is it bug of my iPhone?
Or may be Apple provided Foursquare with these abilities?
You can find out information on using location in the background in the Apple Location and Maps programming guide. Although your application doesn't appear in the app switcher it can still receive notifications - just as an app that isn't "running" can display notifications on the lock screen or update its icon badge.
From the Core allocation documentation on Signficant Region Change Notification -
If you start this service and your application is subsequently terminated, the system automatically relaunches the application into the background if a new event arrives. In such a case, the options dictionary passed to the locationManager:didUpdateLocations: method of your application delegate contains the key UIApplicationLaunchOptionsLocationKey to indicate that your application 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.
So, just because you have terminated the app and it doesn't appear in the app switcher doesn't mean that iOS can't relaunch it to process the notification and then shut it down again