iBeacons: Detect proximity change in background - ios

I'm trying to understand how you are supposed to detect proximity changes in the background.
The only window I get to range is when I enter a region, but this might be pretty far away.
I would like to present something when the user enters "near" or "immidiate", but if you get "didEnterRegion" at far, than stand around, then approach the beacon, you don't get any more ranging time, because you are still in the same region.
Is there a way to either extend the "ranging" time to let the user get near the beacon, or can you make "enterRegion" happen at a different proximity than "far"?

Background ranging time is limited to a few seconds as Charles says in his answer.
If you need to delay action until you are in the immediate region, then you must use iBeacons that allow you to reduce the transmit power so the transmission radius is smaller. The RadBeacon product from RadiusNetworks has this configurability for this exact purpose.
If you configure a RadBeacon for minimum transmit power, your phone will not detect it until it is a few feet away, sending you the entry event and starting your limited ranging window at that time.
Full disclosure: I am Chief Engineer for Radius Networks.

This walkthrough shows how to do what you're asking. I'm in the process of adapting and testing it for iOS 8, but the resulting app works well on iOS 7, pushing local notifications whenever the proximity changes.

In the best practices section in Apple's Getting Started with iBeacon guide it mentions that ranging API should not be used in the background.
• Ranging API are not expected to be used in the background. For best results, ranging should
be used when your app is frontmost and the user is interacting with your app.
Could be a shortcut to app rejection, so take caution.
Given this, you shouldn't really be expected to determine proximity when in the background. I'm also employing the low signal technique, but it becomes a little trickier to differentiate between beacons when you only use one monitored region for multiple beacons...

What's possible with iBeacons in background is pretty limited.
What you can do is monitor regions in the background (which gives you the didEnter / didExitRegion events).
You can also switch on ranging for the beacon and, for the 10 or so seconds after you get a beacon enter / exit event from region monitoring you will also get ranging info (i.e. the immediate / near / far data).
Perhaps you could trigger a local notification at that point to try to get the user to bring your app into foreground - then you'd be able to get the ranging data. If not then, based on my tests, you're only going to get the 10 seconds of ranging data.
To your question about adjusting the ranging time or adjusting the enterRegion proximity - no, these aren't possible in the current version of iOS.

Related

CLLocationManager False didExitRegion

With CLLocationManager
I am defining regions and responding to didEnterRegion and didExitRegion. This works fine in that I get the callbacks for the Enter and Exit as the device moves between regions.
The problem is that I have run the app overnight a few times with the phone device sitting on a table and not moving. The phone device is in the center of an entered region.
During the night, about once an hour, I get a didExitRegion and then within less than 15 seconds I get a didEnterReqion.
My solution to filter these phantom exit/enter pairs was to set up a timer when I get an exit to wait 15 seconds and then if I do not receive an Enter for the same region within that timer window then I process the Exit.
This works if the app is in foreground, BUT in background it fails. In background mode I still get the didExitEvent but I think the App is going back in to background mode before the 15 second window has elapsed do I don't fire that timer until the phone goes back in to foreground mode.
The Radius of my Region is 250M and the accuracy mode is nearest 10 meters. My device, while sitting still, is centered in the Region and yet I still get these phantom Exit/Enter pairs once an hour.
Either I need to find a way to stop the phantom exit/enter pairs, or need a way to keep the timer running the full 15 seconds before the app moves back to background mode.
Does anyone have a good solution for dealing with random exit/enter or enter/exit pairs for stationary devices?
Also what is the max time that a timer can run upon an app waking event in background mode?
Geofencing does not use triangulation (that's why "accuracy mode" you mentioned is totally irrelevant). Geofencing relies on a "digital signature" - set of wifi access points and cell towers your iPhone detected along with strength of signal coming from these sources. Whenever this digital signature changes, the phone might be fooled into triggering a geofence event.
However, before reporting the event, iOS runs triangulation (in most cases without GPS) - and the resulting location is available to you to check if you are really outside the geofence. If location accuracy is too low relative to size of your geofence, you may obtain a better reading - requestLocation() will do the trick, as it will not run for more than 10 seconds.
By the way, that triangulation sequence the iOS runs after detecting a geofence event most likely is why your phone registers didEnter event shortly after didExit.
Arming a timer in background mode makes no sense, as iOS silently suspends background tasks after first 15 to 20 seconds of background execution. This behavior was introduced with iOS 7 and enforced for timers during iOS 10 lifetime.

ios background service to calculate distance and notify user

I'm using ios mapkit for my project. Basically, I'm trying to notify the user when he arrives at a given location. What I do here is I get the distance to the destination and if it's somewhere around 20 meters I'm calling a REST API which will send a push notification to another user. This works fine if the app in the foreground. But how can I do this while the app is in the background? I know there are background modes in the ios. But I can't figure out which mode going to fit here
Thanks
Having tested and deployed region monitoring in production code, I can tell you its bad for walking. It relies on cell towers and the alerts are very flakey at fence sizes of less that 150-200 meters, which is a long way to walk. We initially tried 30 meters and the results were disastrous with tons of false negatives and a few false positives. If you really want to detect 20 meters then you need to use GPS mode, which is drains the battery but its the only thing that has that kind of granularity.

iOS Geofencing; will this be more accurate than what I have now?

I am by no means an iOS developer, and am just hacking something basic together for myself. Sorry if this is too beginner of a question.
I'm trying to collect my own location data from my phone to my own back-end service. Looking around, I found a sample project to collect location info: https://github.com/chriseidhof/PostGPS/
From the looks of things, this project uses significant location update, so even though I changed my desired accuracy to 100 meters, the app will still only provide update when enough cell towers have changed.
Instead, I'm thinking of using geofencing (CLCircularRegion) by creating grids of 3x3 geofences with 500 meter radius (with maybe a 50 meter overlap between each region), and each time I exit the central region, a new set of 3x3 geofences gets generated.
My questions are as follows:
Is this (the deleting and re-fencing part) a correct use of geofencing on iOS?
Is this going to be more accurate than what I currently have?
Will this significantly negatively affect my battery life?
The problem with using geofencing is that you can't monitor more than 20 regions at a time(OS limitation). It's better to use significant location changes. It is triggered while you're in foreground or background and the location is updated if the cell tower has changed or you have opened the app while the app was not in memory. But this method will be triggered only in the intervals of 15 mins. So even if the cell tower changes rapidly, this method will be invoked only once in 15 mins.
So if you want to update the location in background keeping in mind the battery usage as well, use significant location api.

didDetermineStateForRegion and didExitRegion returning false responses

I am showing the user a local notification when they enter a beacon region, and when they exit a beacon region. The exit is the most important because I tell the user how long they dwelled in that location. I am using region monitoring because it allows me to keep track of the beacons even when the app is in the background or suspended. I am experiencing a bug where I am monitoring 3 beacons (this happens with 2 and 1, but less frequently). My phone will sleep, and I will continue to monitor for the beacons. Then, my app will wake due to didExitRegion for one of the beacons, even though all 3 beacons are sitting face up on the same desk as my phone. It is a different beacon each time, so I have ruled our signal strength. Then, once the app is awake, it rediscovers the beacon and immediately re enters (because it never left the signal in the first place). I am detecting the signals with an android device at the same time, and the beacons are broadcasting the whole time, so the iPhone should not be losing these signals, especially not for a long enough time to consider it an exit.
I tried to remedy this by using
[self.locationManager requestStateForRegion:region];
However, in these situations this will return state 2, which is CLRegionStateOutside.
How should I get around this? Has anyone had a similar experience. I should be able to dwell in a beacon region for 1 minute or 1 hour and only get an exit when the beacon is undetected for 30 seconds.
A few things to check:
Verify this happens with multiple iOS devices. It is possible that the iOS device has a hardware problem such that it has weaker Bluetooth LE reception, or picks up more radio noise. I have never seen this myself, but I have heard reports of others who insist they have seen it on some iOS devices.
Check the signal level received by the iOS device and the Android device by ranging the beacon using an app like Locate for iOS and Android. The signal levels should be similar on both devices. A strong signal will have an RSSI of about -60 or less negative. A weak signal will have an RSSI of about -100 or more negative. If you have a weak signal, it may cause intermittent detection losses because radio noise will sometimes prevent packets from being received properly. If you can configure your beacons to increase their transmitter power level, do so.
With the Locate app in the foreground, range the beacon to check the signal level and rotate it at different angles. Some beacons have antenna patterns that are much weaker on one side. You may find that the orientation gives a much weaker signal, and again, a weak signal can cause dropouts.
Check the specs or configuration settings of your beacon to see how often your beacons are transmitting. Beacons that are configured to transmit rarely to conserve battery (e.g. once every 5 seconds) are more likely to cause this situation because it only takes 6 missed packets in a row (rare but possible) to cause a region exit.
One other possibility is that there is an unusual amount of radio noise periodically in your vicinity in the Bluetooth frequency range. This is unlikely, but I have seen it before. I live across the street from a U.S. Marine installation with powerful antennas, and at home I often get much higher packet CRC error rates than I do in the office.

ibeacon powered on as opposed to enter or leaving region

I have been playing around with various test apps that detect when the device enters or leaves the iBeacon's region but my question is are there any apps that will detect when a beacon is turned on?
The reason I ask is that if I sit in the same room as my iPhone and remove the battery from the beacon then re-insert it the none of the apps that I have tried so far trigger a region entered response.
Please excuse my non tech question as until I can find out if this type of detection is possible I haven't yet fully immersed myself in the coding as it may not be suitable for my application.
Think about it from your phone's perspective: Powering down an iBeacon looks exactly the same as moving out of its transmitter range. Likewise powering up an iBeacon looks exactly the same as entering its transmitter range.
The way that the iOS CoreLocation monitoring callbacks work (didEnterRegion / didExitRegion) is exactly the same for the two cases above.
I suspect the reason you aren't seeing a didEnterRegion callback when you power on your iBeacon is because you didn't leave it unpowered long enough. It takes time for iOS CoreLocation to decide the phone exited a region, and it generally won't tell you that you entered a region if it thinks it never left it.
Two suggestions to make this easier for you.
When doing testing like this, always verify you get a didExitRegion indication before expecting a didEnterRegion event. (Add NSLog lines to your appDelegate to help you see this.)
Turn on ranging for iBeacons whenever you set up monitoring for iBeacons. This makes the time needed to detect region transitions much faster when you are in the foreground.
More information on the time it takes to detect region transitions can be found in this blog post.
I had similar experiences and assume the phone checks for new beacon only when you move around. That makes sense from an energy saving perspective and the main use case of beacons.
To detect a beacon when it's powered on is possible, if the CLLocationManager object is currently ranging for the beacon, and it's already in range.
The thing to understand here is the difference between region monitoring and beacon ranging.
Some apps only start with region monitoring, ranging only when a region is entered, and stop ranging when the region is exited.(taking the batteries out will cause the region to be exited) When you put the batteries back in, the beacon in this case is not detected because ranging has been stopped.
When your app launches start ranging with startRangingBeaconsInRegion: method and don't stop this anywhere in your code.

Resources