Search code examples
iosswiftibeaconestimote

iBeacon - can detect using startRangingBeacons but not for didEnterRegion


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!")
    }

}

Solution

  • 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.