I'm developing an app with iBeacon support. Basically, I have a single view that updates its content according to the nearest beacon, and to scan beacons, I use no framework (just the CoreLocation from Apple), even though I use Estimote Beacons.
The problem is that my application doesn't detect the beacons instantaneously, I have to wait about 5 seconds in front of a beacon in order to get the content updated, while the Estimote app detects the beacons within 1-2 seconds. My Estimote beacons are configured to advertise every 960 ms.
How is that possible ? Can I set a time interval to scan for beacons ? How to improve my app to update the view faster ?
Here is the code I use to initialize the location manager and to update the view :
// ViewController.h =================
@property (strong, nonatomic) CLLocationManager *locationManager;
// ViewController.m =================
-(void)initBeaconMonitor {
NSUUID *estimoteUUID = [[NSUUID alloc] initWithUUIDString:estimoteBeaconUUID];
_region = [[CLBeaconRegion alloc] initWithProximityUUID:estimoteUUID major:estimoteBeaconMajor identifier:beaconRegionIdentifier];
self.locationManager = [[CLLocationManager alloc] init];
// For iOS 8
if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
self.locationManager.delegate = self;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager startMonitoringForRegion:_region];
[self.locationManager startRangingBeaconsInRegion:_region];
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:
(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
if(beacons.count > 0) {
CLBeacon *nearestBeacon = beacons.firstObject;
if(nearestBeacon == _lastBeacon) {
return;
}
_lastBeacon = [nearestBeacon copy];
switch(nearestBeacon.proximity) {
case CLProximityFar:
break;
case CLProximityNear:
[self updateViewWithBeacon:nearestBeacon];
break;
case CLProximityImmediate:
[self updateViewWithBeacon:nearestBeacon];
break;
case CLProximityUnknown:
return;
}
}
}
You cannot change the beacon scanning interval on iOS. When ranging in the foreground, iOS will constantly scan for beacons so this is not what is causing delays.
The problem is that the app logic will only update the UI once CoreLocation
determines the beacon is in Near/Immediate proximity and the beacon is closest according to the sorted position in the beacons array. Both the sorting and the value of the proximity
field are based on CoreLocation
's distance estimate to the beacon (the accuracy
field), and this is based on a 20 second running average of the signal strength between the mobile device and the beacon. It is this 20 second running average that is causing the delays you mention, because the distance estimate updates slowly and does not reach a steady state until the mobile device has been in the same place relative to all beacons for 20 seconds. Unfortunately, this 20 seconds is fixed and not configurable.
For faster responsiveness, you can stop using the accuracy
field and sorted order of the beacon within the array. A few alternatives:
Change your logic to not be based on distance at all, perhaps based on timing and what beacons have been seen before.
Switch to using the rssi
field as a proxy for distance. This field is averaged over only 1s, but be aware that it has as lot if variability due to radio noise. Less negative values for this field indicate closer beacons. Increasing the beacon transmission frequency as @heypiotr suggests in his answer will help give more stable RSSI numbers.
Manually calculate your own running average of RSSI over a shorter time interval (2-5 secs) for a better tradeoff between rapid updates in distance estimation and stability.
You can read more about how iBeacon ranging works here:
http://developer.radiusnetworks.com/2014/12/04/fundamentals-of-beacon-ranging.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With