BoreBoar
BoreBoar

Reputation: 2749

Cant detect iBeacon in iOS 10 after setting up monitoring

I've been working on detecting iBeacons on iOS 10 with swift 3 and Xcode 8.2.1.

I've been following this tutorial and so far i've been able to get the beacons detected in the foreground. However, what i need is for the beacons to be detected in the background as well as when the app is closed.

I've set the key NSLocationAlwaysUsageDescription in info.plist and also added Location updates in the apps Background Modes.

I'm also requesting requestAlwaysAuthorization from the user.

Everything works fine till i add the following statement to the code: locationManager.startMonitoring(for: beaconRegion)

After i add the above statement and run the code, my app detects the beacon in the foreground and prints me a message. But as soon as i minimise the app and reopen it, the app cant seem to find the beacon. If i comment the line out and then rerun my program, the app detects the beacon in foreground as well as when i minimise and reopen the app again. I don't understand what i'm doing wrong.

Here is my ViewController code:

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {
    var locationManager: CLLocationManager!

    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.pausesLocationUpdatesAutomatically = false
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.requestAlwaysAuthorization()
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedAlways {
            if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
                if CLLocationManager.isRangingAvailable() {
                    startScanning()
                }
            }
        }
    }

    func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
        if beacons.count > 0 {
            NSLog("Found beacon")
        } else {
            NSLog("Beacon not found")
        }
    }

    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
        let beaconRegion = region as! CLBeaconRegion
        print("Did enter region: " + (beaconRegion.major?.stringValue)!)
    }

    func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
        let beaconRegion = region as! CLBeaconRegion
        print("Did exit region: " + (beaconRegion.major?.stringValue)!)
    }

    func startScanning() {
        let uuid = UUID(uuidString: "2f234454-cf6d-4a0f-adf2-f4911ba9ffa6")!
        let beaconRegion = CLBeaconRegion(proximityUUID: uuid, major: CLBeaconMajorValue(0), minor: CLBeaconMinorValue(1), identifier: "MyBeacon")

        beaconRegion.notifyEntryStateOnDisplay = true
        beaconRegion.notifyOnEntry = true
        beaconRegion.notifyOnExit = true

        //        locationManager.startMonitoring(for: beaconRegion)
        locationManager.startRangingBeacons(in: beaconRegion)
    }
}

Here's what my log looks like:

Found beacon
Found beacon
Found beacon
// App minimised and reopened here
Found beacon
Found beacon
Found beacon
Found beacon
Found beacon
Found beacon
Beacon not found
Beacon not found
Beacon not found
Beacon not found
Beacon not found
Beacon not found

Upvotes: 0

Views: 1297

Answers (2)

Milander
Milander

Reputation: 1061

Interaction with iBeacons can be done with ranging en monitoring. Ranging for a beacon provides you the value/data of the iBeacon, like uuid, major & minors. The problem with ranging is that apple accepts only a few (circa 10 seconds) of ranging time in the background. Monitoring can be done in the background. You should check if you can range in background (print/logs) ifso, detecting the ibeacon is the problem.

ps: When you start ranging inside a region the didEnter delegate method doesn't get called, because you are already in the region.

Upvotes: 0

davidgyoung
davidgyoung

Reputation: 65025

Try adding the monitoring delegate callbacks didEnter(region: region) and didExit(region: region). Not sure why it would change things, bit it is unusual that the code starts monitoring but does not have them.

EDIT: After seeing updated code, I suspect the issue may be the way ranging is started. Instead of starting it in the didChangeAuthorization callback, just start it in viewDidLoad. The code will not crash if authorization has not been given. It just won't actually scan until it is.

Upvotes: 1

Related Questions