ios - Cllocation in background - ios

I am working on project in which I need to fire notification when user reaches particular place, even application in background. What is the best way to do this?
What I found is following.
locationManager = [CLLocationManager new];
[locationManager startUpdatingLocation];
or
[sharedService.locationManager stopMonitoringSignificantLocationChanges];
or
[locationManager startMonitoringForRegion:region];
About startUpdatingLocation I am getting continuous notification on simulator and on ipod after 3-4 mins.
Documents says it will drain battery and appstore may not accept because this methods must be used by application like navigation types.
About stopMonitoringSignificantLocationChanges documents says it uses cellular network. I am not sure whether it wil work on ipod. On my ipod not working. Does this method needs sim card?
And how does this method works? Means should I walk some distance to get this method respond? I traveled 1-2 km but it did not work.
About startMonitoringForRegion I used
if([CLLocationManager regionMonitoringEnabled])
NSLog(#"monitering enable");
else
NSLog(#"monitering not avail");
For Ipod I got monitering not avail. Also client checked on his iphone. He also did not got notification.
Please can some one explain me this method? If any other way of finding location in background then please tell.
Edit:
I am using startUpdatingLocation. On device it calls didUpdateToLocation method every after 5 mins. Will it use lot of battery? and appstore will accept this?
If I use startUpdatingLocation will appstore accept app? Since my need is just to give notification when user reach a particular place.

According to the application requirement you describe I think that
- startMonitoringForRegion:
is the best approach, look at Apple Doc snippet below...
You can use the region-monitoring service to be notified when the user crosses a region-based boundary. Region monitoring applies both to geographical regions (represented by the CLCircularRegion class) and to beacon regions (represented by the CLBeaconRegion class). You region monitoring to detect boundary crossings of the specified region and you use those boundary crossings to perform related tasks. For example, upon approaching a dry cleaners, an app could notify the user to pick up any clothes that had been dropped off and are now ready.
You app is not tracking or routing related application so using [locationManager startUpdateLocation] will be overly done I think.

Related

What strategy to adopt to monitor the user location in background?

I want to track the user location in background, in the purpose to show him an alert when he is close to one of his friend.
So i start with CLLocationManager. As far as i know their is only one reliable way to let the app know about the location update even if the user reboot the Iphone or kill the app: startMonitoringSignificantLocationChanges. But the problem is that even inside a city with many wifi, startMonitoringSignificantLocationChanges fire the DidUpdateLocations when the user move around 1km and that is really too much for my need
on the other way startUpdatingLocation is firing DidUpdateLocations at good interval (even too much because even when the user do not move it's fire quite often DidUpdateLocations). But startUpdatingLocation not survive to iphone reboot or app being killed by the user. Also I suspect that even with an accuracy of 100m, startUpdatingLocation use lot of battery consumption.
So the question: What strategy i can use in my app to track efficiently without draining too much the battery the user location at full time? I need an accuracy of around 100m and if possible an interval between 2.5 - 5 min for each track (i didn't find any option to specify a delay to wait before to catch a new location)
Actually i think to do something like this :
2 locationManager, 1 GPS and 1 Significant Changes
when app start I do with significantChangesLocationManager: startMonitoringSignificantLocationChanges and startMonitoringVisits
I also call GPSLocationManager startUpdatingLocation to retrieve the accurate user position. I set up PausesLocationUpdatesAutomatically(true) so that the GPSLocationManager will stop by himself soon or late
on DidUpdateLocations raise by the GPSLocationManager I start monitoring region enter/exit (100m radius around the obtained latitude/longiture) with significantChangesLocationManager
What do you think of such strategy ?
Even though you will receive more triggers than you need, as you already said, you can use startMonitoringSignificantLocationChanges. It is implemented in a very energy efficient way. It allows the app to be terminated and only be woken up again when iOS thinks the device has moved significantly. Another advantage would be that your app doesn't need the location background mode, which could raise questions during an app review.
The startUpdatingLocation let's the app continuously update the location of the device, even though you only receive a couple didUpdateLocations: events. Also, iOS cannot shutdown the app while updating is active, so it consumes a lot of battery.
You can also consider geofencing, with an exit geofence around the current location. However, significant location updates will be more reliable. Exit geofences won't trigger anymore once you're already out of a geofence, which could happen when the phone is turned off inside a geofence and turned back on outside. This solution has the same advantage of not needing a background mode.
As far as I understand your use case, startMonitoringSignificantLocationChanges sounds as the best option. You won't have control over the exact time interval and distance it triggers, but it is very energy efficient and easy to use.
As mentioned in comments, here are some approach I had to do in order to get the expected result in our app.
Significant Location Updates - is good to wake your app up once it gets finished by some reason that you can't control, so even if you lose some points, it will get back in some seconds/minutes.
This is not good if you need a good accuracy, as you cannot control the distance / time or whatever, iOS will update locations when mobile antenna is changed, wifi connection, turn air plane mode off and on but will not give a sequence of gps points.
Start Location Updates - Best accuracy but battery drainer. So you can't just turn it on let it go. You must implement some controls over it.
Background tasks - The only way I've found to keep my app alive.
The way you can combine is:
Have 2 location managers isolated, one for significant location change and one for start updating location;
Start your app with both turned on;
Inside your didUpdateLocations you can create your logic to start and stop your background tasks;
Create methods to start and pause your location manager and create your timers to control that;
inside your bg task you will start or pause your update locations, but never stop it, just if for example, your user logs out and you want to stop location;
keep significant location update location manager alive forever, if for some reason iOS decide to kill your app when in bg, it will ensure that in a given moment your app will come back to life;
For battery live, try do not use kCLLocationAccuracyBestForNavigation for accuracy as when it starts it eat a LOT of resources, most of time, kCLLocationAccuracyBest is more then enough and if you can use kCLLocationAccuracyNearestTenMeters;
Your didUpdateLocations will give you mostly a bunch of points, try to get only those with good horizontalAccuracy, around 20 meters for us was good enough, so let it work and once you have a point with good accuracy, you can pause it again.
Below you have some links that helped me a lot to implement our solution, none of those have a "as is" solution, as I said, I had to mix all of them and test a lot to understand its behaviour and make the necessary adjustments.
https://github.com/voyage11/Location
http://mobileoop.com/background-location-update-programming-for-ios-7
http://zaachi.com/2013/09/30/ios-locationmanager-location-update-in-my-own-interval-with-application-in-the-background.html
In addition to Mark's answer I would like you to explore pausesLocationUpdatesAutomatically which can help you save battery from draining when user has stopped Apple Documentation
Allowing the location manager to pause updates can improve battery life on the target device without sacrificing location data. When this property is set to true, the location manager pauses updates (and powers down the appropriate hardware) at times when the location data is unlikely to change. For example, if the user stops for food while using a navigation app, the location manager might pause updates for a period of time. You can help the determination of when to pause location updates by assigning a value to the activityType property.

Beacon monitoring in background iOS

I am developing an iOS app in Swift that monitors for beacon events. This is my first real beacon endeavor.
I am using Estimote beacons, but am not using the Estimote SDK. I am using core location and a CLLocationManager with didExit and didEnter events.
I am only listening for beacons that are registered with the current user that is signed in to my app. For example, John Doe could be registered with beacons A and B, while Mary Sue is only registered to beacon C. I am experiencing a lot of false leaves, and wonder if it is because of where I am implementing my code.
I understand that there is a default 30 second latency when validating a leave event, but I am experiencing periods of longer than 30 seconds without a bluetooth signal from point blank range. Perhaps implement a 30 minute window rather than 30 seconds for a leave validation?
Since a user has to sign-in in order to know what beacons to monitor, the location manager resides within the user's default profile view controller. I successfully get beacon interaction even when the phone is locked, but it is not consistent. I am concerned because I know that the view controller itself is suspended/activated at the iPhone's discretion and may be revealing flaws in my logic.
Should all location oriented code be placed within the app delegate file? If I implement a protocol from my profile view to the app delegate, I can instantiate it there within the app delegate first and then retrieve the beacon data later, once the user is signed in.
I have struggled to find an "iOS beacon convention" in my research, just examples that provide some results. Not too sure whats actually considered proper practice.
Thanks!
It is common to use a software filter to ignore spurious region exit events if an entry event happens soon afterward.
To make this independent of any one ViewController, it is important to have the logic triggered by the AppDelegate. Two choices here:
Put region monitoring callbacks and filter logic directly in the AppDelegate. This is appropriate for small and simple apps.
Put callbacks and filter logic in a custom class, and initialize it from the AppDelegate's didFinishLaunching method. This is the best approach for larger and more complex apps to keep the AppDelegate simple and clean.
Either way, it is critical to trigger starting of monitoring from the didFinishLaunching method. This ensures proper background CoreLocation setup should your app be auto launched by region transitions.

iBeacon: Unable to detect broadcaster - Intermittent

I came across this tutorial (http://www.appcoda.com/ios7-programming-ibeacons-tutorial/) about iBeacon which I found interesting. I've downloaded their source code and able to run well.
Anyway, I noticed one strange thing. There are times, when I run the broadcaster first instead of the receiver, the receiver seems to not be able to detect any beacon but if I run the receiver first, only then the beacon can be detected.
I've tried looking into other tuts but iBeacon seems like a new technology and not much reference can be found yet. Can any of you guys who had get their hands dirty into this iBeacon thing shed some light on this intermittent issue?
Your help are much appreciated.
The issue you're seeing is because the receiver app only starts 'ranging' for beacons if it detects that you have entered a region. If you start the broadcaster first, you're already inside the beacon's region, so your app might not start ranging. This sentence in the article is the clue:
Launch the receiver app and carry it far away from the broadcasting beacon and then walk towards it to simulate entering the region.
Monitoring for a beacon means that your app will only be notified when you enter or exit a region you've defined. The radius of this region could be up to ~50m, so if you're just sat next to the receiver, you shouldn't trigger one of these events unless you turn the receiver off and on again. Monitoring can be done whilst the app is running in the background or the foreground.
Ranging for beacons in a region means that the app will be notified once per second with a list of all beacons that the device can see in the specified region (ordered by distance). Ranging will call the locationManager:didRangeBeacons:inRegion: method of your CLLocationManager's delegate. The list of beacons will be constantly updated as you move around inside / outside the region and your distance to the beacons changes. Ranging is intended to happen whilst your app is in the foreground.
If you would like the app to continuously listen for beacons, try calling
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
in your viewDidLoad:, instead of in your didEnterRegion: method.
Its due to current location delegate available methods. Add this method also -
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
This will fix the issue.

iOS: How to to notify a user on reaching near to a store

I am writing an application that should alert the user on reaching near (with in 300 meters) to a specified retail store.
I am using the API
[locationManager startMonitoringForRegion:grRegion desiredAccuracy:acc];
but not able to get the events for enter and exit region.
My Questions are
How accurate is this API. Will it me accurate to fire the event if we specify the 300 meter range. Or this event will be fired only when the user changed from one cellular tower to another?
If it is not able to get events with in 300 meters, How can I implement my requirement.
PS:- I don't want to use the API [locationManager startUpdatingLocation]; as it would drain the battery quite quickly.
Thanks in advance.
You will need to implement CLLocationManagerDelegate to intercept the location callbacks for -didEnterRegion, and -didExitRegion.
I've been using this exact API in my app for almost a year now and I find it to be very accurate with minimal battery drain. I would say this should be your best avenue and wouldn't consider using -startUpdatingLocation as it will require a lot more code to implement what you need, not to mention the battery hit.
Implement the delegate and methods, you should be good to go. You can test it out using the location changes in the simulator too. Get things working good before you test them out in real world use.

Battery drain when using CoreLocation Significant Location Monitoring & CoreBluetooth

We've released an application which runs in the background and uses CoreBluetooth & CoreLocation to automatically save your parking location.
At a high level our app just looks for a CoreBluetooth disconnect event and turns on GPS until we get an location fix (accuracy <=10m) or 3 minutes max time (this could occur when you park in an underground parking lot with no GPS coverage). We then use Significant Location Monitoring to automatically re-launch our application in event of the system terminating our app.
During our development we never saw a battery drain issue ourselves, however 75% of our users say that they see a significant battery drain. 10% of our backers responded to the poll so it's a difficult to determine how representative the breakdown is, but it's a large percentage of our users. http://www.findmycarsmarter.com/forum/viewtopic.php?f=4&t=30
We then released an update that allowed users to disable Significant Location Monitoring and 60% say that by disabling Significant Location Monitoring the drain goes away. http://www.findmycarsmarter.com/forum/viewtopic.php?f=4&t=42
Initially we could not duplicate the drain issue ourselves, but we found that when we installed a simple app that just turned on Significant Location Monitoring in conjunction with Find My Car Smarter, we intermittently saw the drain reproduce. In the drain state the phone does not enter hibernate. This is indicated by the usage time in (Settings->Usage->Time since last full charge) continuing to increment even though the phone had been put to sleep and the display is off. Something prevents the system from entering hibernate. The battery drains about 15% per hour in this stage. This drain shows up intermittently and seems to clear itself out after an hour or two and come again randomly. We have not found a way to reliability reproduce the drain.
We believe the issue is caused by multiple clients calling into CoreLocation. We asked a few users who experienced the issue to wipe their phone and only install our Find My Car Smarter app. Alone with just this app installed, the drain did not exhibit. We have had other reports that when our app is used with Google Latitude or Facebook, etc is when they see the drain occur. Or if they go and kill other applications the drain goes away. We've seen the drain persist through a power cycle, with no apps launched. This implies that it has to be a system level service that prevents the OS from sleeping.
Even though we think the issue is caused by some race condition of multiple clients calling into CoreLocation, we never saw the issue reproduce with apps that only used CoreLocation. We even created 4 or 5 different apps that would simultaneously access CoreLocation and we didn't see the drain occur. We did however see the issue when we had an app with CoreLocation and a second app with CoreLocation + CoreBluetooth. There are probably very few apps that use the CoreLocation + CoreBluetooth combination, so potentially that's why more developers haven't hit this issue. Although we're at a loss to explain how CoreLocation & CoreBluetooth interact to cause this drain and how the second app with CoreLocation comes into the equation. Since the drain was intermittent it's possible that it's just a fluke that the issue only happened when we were testing with CoreLocation + CoreBluetooth.
On a wiped 5.0.1 iPhone 4S with only these two apps CTM1 & FMC installed we were able to intermittently get into the drain state. Interestingly, the drain issue seemed to occur much less frequently on a wiped device then our normal device. Unfortunately we only saw the drain state a few times and without being able to reliably reproduce the drain we don't have a good control state to work from.
We've filed a bug report with Apple and opened up a Technical Support Incident, but maybe the Stackover community can also provide some insight. We've seen this issue both in 5.0.1 & in 5.1 Beta 3.
CTM1
http://www.findmycarsmarter.com/files/CTM1.zip
On Going into the Background
[locationManager stopUpdatingLocation];
[locationManager stopUpdatingHeading];
[locationManager startMonitoringSignificantLocationChanges];
On Re-entering Foreground
[locationManager stopMonitoringSignificantLocationChanges];
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
On didUpdateToLocation
//do nothing
On didUpdateHeading
//do nothing
FMC
http://www.findmycarsmarter.com/files/FMC.zip
On Going into the Background
[btleManager stopScan];
[locationManager stopUpdatingLocation];
[locationManager stopUpdatingHeading];
[locationManager startMonitoringSignificantLocationChanges];
On Re-entering Foreground
[locationManager stopMonitoringSignificantLocationChanges];
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
[btleManager scanForPeripheralsWithServices:nil options:nil];
On didUpdateToLocation
//do nothing
On didUpdateHeading
//do nothing
On centralManagerDidUpdateState
[btleManager scanForPeripheralsWithServices:nil options:nil];
On didDiscoverPeripheral
[btleManager connectPeripheral:device options:nil];
On didConnectPeripheral
//update log
On didDisconnectPeripheral
//initiate reconnect
[btleManager connectPeripheral:device options:nil];
If you see any coding mistakes that might account for the drain please let us know.
One other question we did have, if we're using both GPS & Significant Location Monitoring, is there a reason to call stopMonitoringSignificantLocationChanges? Looking at the Regions sample code they call stopMonitoringSignificantLocationChanges & startLocationUpdate on entering foreground and stopLocationUpdate & startMonitoringSignificantLocationChanges on entering background, but I'm wondering if this is necessary/recommended/required?
Update:
We've confirmed with Apple Developer Technical Support that for applications using both GPS & Significant Location Monitoring that our sequence of turning off Significant Location Monitoring before enabling GPS update is correct.
We've also confirmed that the drain issue can still be seen in the GM 5.1 & with a re-compiled Find My Car Smarter application against the 5.1 Frameworks.
Update:
It looks like the issue is triggered when our app is launched from the background in response to a Significant Location Monitoring event. We actually don't handle this scenario properly in our sample code but we do in our actual app.
In the sample code, on a background re-launch we'll turn on location update and since there is not a applicationDidEnterBackground call, the GPS will be left on.
In our app we check to see if we were launched from the background by looking for the UIApplicationLaunchOptionsLocationKey flag, if so we start Significant Location Monitoring, otherwise we were launched in the foreground and we start Updating Location.
Apple got back to us and stated that usage of Significant Location Monitoring does not require the location set in UIBackgroundModes array in the Info.plist. We removed this entry and it appears that the battery drain state is no longer hit. We still have bluetooth-central in the UIBackgroundModes list. At the moment we're unclear as to why this helps. We're going to be running some more experiments to help us understand this better. If anyone has any suggestions please let us know.
At the end of the day, Apple's suggestion of removing location from UIBackgroundModes fixed our battery drain issue.
In order to still get locations in the background we had to wrap the [locationManager startLocationUpdates] & [locationManager stopLocationUpdates] calls with:
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler];
[[UIApplication sharedApplication] endBackgroundTask:];
You could debug status of the app using any repetitive signal sound. Just make sure you didn't put 'plays audio' in the background modes requirements for this test.
If your app running - you will hear this sounds even application is in the background. If app is suspended - you will hear nothing. This is probably simplest method to detect that the app is not properly suspended.
Using Profiler for debug of this issue is problematic because many things works different in debug mode when device connected to computer. Especially power saving things.
Also, please make sure you do everything right in response to significant location changes. If you start location updates - make sure you've set some timer (for 3 minutes, for example) that shuts down location updates.
Anyway, the iOS will kill you app even it started location updates from response to significant location changes. Does not matter what you did started in response - the app will be killed in 10 minutes if still running - pay attention to crash logs - such event will be logged there.
Also, check all your 3rd party code and libs - perhaps some of them turns GPS and use it for somethings. Mostly paranoid, but may happen for analytic and advertising targeting purposes.
CoreLocation enabled applications generally made for background mode , so it can run in background, definitely it usage more battery , for my suggestion is always try to stop the location service when it is no need .
[locationManager stopUpdatingLocation];
then after according to your requirement then start accordingly,
Thanks

Resources