Search code examples
iosswiftcore-locationcllocationmanageribeacon

Trying to detect beacons but failed because isMonitoringAvailable always false


Hello i trying to detect and ranging beacons following by apple's docs article

but in my case CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) always gave me false thus i couldn't start monitoring

Of course i set Privacy for location and Location updates on background mode

this is my codes

func initializeLocationManager(){
    locationManager.delegate = self
    locationManager.requestAlwaysAuthorization()
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
}

func rangeBeacons(){
    if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
        let region = CLBeaconRegion(proximityUUID: UUID(uuidString: beacons[0].uuid)!, identifier: beacons[0].identifier)
        locationManager.startMonitoring(for: region)
    }else {
      print("CLLocation Monitoring is unavailable")
    }
}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    if status == .authorizedAlways {
        rangeBeacons()
    }
}

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
    if region is CLBeaconRegion {
        // start monitoring
        if CLLocationManager.isRangingAvailable() {
            locationManager.startRangingBeacons(in: region as! CLBeaconRegion)
        }
    }
    print("didEnter at \(region.identifier)")
}

func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
    print("didExit at \(region.identifier)")
}

func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
    if beacons.count > 0 {
        let nearestBeacon = beacons.first!
        switch nearestBeacon.proximity {
        case .far:
            print("far")
            break
        case .near:
            print("near")
            break
        case .immediate:
            print("It's behind yout")
            break
        case .unknown:
            print("unknown")
        }
    }
}

but if i use locationManager.startRangingBeacons directly instead locationManager.startMonitoring(for: region), it works

but still problem didEnterRegion and didExitRegion are not called

what is the problem in my case

i want to follow exactly same with apple's docs article


Solution

  • It's unclear from the code shown what CLBeaconRegion.self means in context. Try instead using the defined region to see if monitoring is available.

    func rangeBeacons(){
        let region = CLBeaconRegion(proximityUUID: UUID(uuidString: beacons[0].uuid)!, identifier: beacons[0].identifier)
        if CLLocationManager.isMonitoringAvailable(for: region) {
            locationManager.startMonitoring(for: region)
        }else {
           print("CLLocation Monitoring is unavailable")
        }
    }
    

    In practice, there is no real reason to call isMonitoringAvailable. Just start monitoring without this check. If for some reason it fails, you will get a callback to: locationManager:monitoringDidFailForRegion:withError