I need to detect when the device enters or exits a region and performs some action based on this.
Using the 'startRangingBeaconsInRegion' I can detect the closest iBeacon and change the background color based on this, and white if it can't detect an iBeacon.
I can't get it to fire on the 'didEnterRegion' or 'didExitRegion' though.
I am aware that if the device is already in the region, then the enterRegion won't fire. I make sure that the beacon isn't detected (white screen) and then that the beacon is detected (colour screen) - but nothing fires.
I have tried using the estimote SDK, but I get the same problem. Rebooting the device hasn't helped either.
My code is below, any suggestions?
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
let region = CLBeaconRegion(proximityUUID: NSUUID(UUIDString: "B9407F30-F5F8-466E-AFF9-25556B57FE6D"), identifier: "Estimotes")
let colors = [
3861: UIColor(red: 84/255, green: 77/255, blue: 160/255, alpha: 1),
19152: UIColor(red: 142/255, green: 212/255, blue: 220/255, alpha: 1),
40527: UIColor(red: 162/255, green: 213/255, blue: 181/255, alpha: 1)
]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.delegate = self
locationManager.pausesLocationUpdatesAutomatically = false
region.notifyEntryStateOnDisplay = true
region.notifyOnEntry = true
region.notifyOnExit = true
// Request authorisation to track location
if (CLLocationManager.authorizationStatus() != CLAuthorizationStatus.AuthorizedWhenInUse) {
locationManager.requestWhenInUseAuthorization()
}
if (CLLocationManager .isMonitoringAvailableForClass(CLBeaconRegion))
{
println("OK")
}
else {
println("Problem")
}
locationManager.startMonitoringForRegion(region)
locationManager.startRangingBeaconsInRegion(region)
locationManager.startUpdatingLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager!, didRangeBeacons beacons: [AnyObject]!, inRegion region: CLBeaconRegion!) {
let knownBeacons = beacons.filter { $0.proximity != CLProximity.Unknown }
if (knownBeacons.count > 0) {
let closestBeacon = knownBeacons[0] as CLBeacon
self.view.backgroundColor = self.colors[closestBeacon.minor.integerValue]
println(beacons)
}
else {
self.view.backgroundColor = UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1)
}
}
func locationManager(manager: CLLocationManager!, didEnterRegion region: CLRegion!) {
println("Region entered")
}
func locationManager(manager: CLLocationManager!, didExitRegion region: CLRegion!) {
println("Region exited")
}
func locationManager(manager: CLLocationManager!, monitoringDidFailForRegion region: CLRegion!, withError error: NSError!) {
println("FAIL!")
}
}
You are trying to change the UI in the location manager callback - that's a big no no since those callbacks are usually not on the main thread. Wrap each UI change in a dispatch block to the main thread and see if that changes anything.
Ah, I had the same issue a few days ago. You need to implement:
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
println("STATUS CHANGED: \(status.rawValue)")
if status == .AuthorizedAlways && !monitoring {
println("YAY! Authorized!")
locationManager.startMonitoringForRegion(beaconRegion)
monitoring = true
}
}
You can only start monitoring AFTER the system tells you you have permission to.
Also, if you want background notifications, you MUST have this string in your Info.plist: NSLocationAlwaysUsageDescription
, and you need the App registers for location updates
defined in Required background modes
.