Trying to detect beacons but failed because isMonitoringAvailable always false - ios

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

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

I believe the only reason why isMonitoringAvailable can be false for iBeacon (CLBeaconRegion) is when the device you're running the app on doesn't support Bluetooth 4.0.
This includes:
the simulator,
iPhone: 1st-gen, 3G and 3GS,
iPad: 1st-gen and 2nd-gen,
iPod Touch: 1st through 4th gen.
If you're running your app on any device newer than these, then the only remaining thing I can think of is, there's a problem with Bluetooth on your device. In which case, a reboot might help.

Related

beacon proximity detector not working in iOS swift

I'm building an app which detect Beacon device proximity using locate beacon app in iPhone 6 and my app in iPhone 7 but app is unable to detect the Beacon transmitter. I have entered correct UUID and Major Minor number but it is not working. I'm running on iPhone 7 with iOS 13.5 and iPhone 6 with iOS 12 it is not detecting.
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var distancestatuslbl: UILabel!
var locationmanager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
locationmanager = CLLocationManager()
locationmanager.delegate = self
locationmanager.requestAlwaysAuthorization()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways
{
print("Allowed any time")
startScanning()
}
else if status == .authorizedWhenInUse
{
print("Allowed only during run time")
startScanning()
}
}
func startScanning() {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self)
{
let uuid = UUID(uuidString: "2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6")
let majornumber: CLBeaconMajorValue = 123
let minornumber: CLBeaconMinorValue = 456
let beaconregion = CLBeaconRegion(uuid: uuid!, major: majornumber, minor: minornumber, identifier: "com.mybeacon")
locationmanager.startMonitoring(for: beaconregion)
print("Started scanning")
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region is CLBeaconRegion
{
if CLLocationManager.isRangingAvailable()
{
locationmanager.startRangingBeacons(in: region as! CLBeaconRegion)
print("Starting ranging...")
}
}
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
let nearestbeacon = beacons.first!
switch nearestbeacon.proximity {
case .near:
distancestatuslbl.text = "Near"
break
case .immediate:
distancestatuslbl.text = "Immediate"
break
case .far:
distancestatuslbl.text = "Far"
break
default:
print("sdf")
}
}
}
You probably need to call startScanning() in viewDidLoad. As written, it is only called after permission is first granted meaning it only starts the first time you run the app and grant permission, then never again.
Also, check that the beacon actually is transmitting by running the Locate app on the same phone as your app. Does Locate detect?

CoreLocation Non-iBeacon Bluetooth device scan

I want to find Bluetooth devices and get RSSI values using certain period time. I can scan iBeacons. But I also want to find the other Bluetooth devices (like an iPhone device). How can I scan for all devices using CoreLocation?
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
if CLLocationManager.isRangingAvailable() {
startScanning()
}
}
}
}
func startScanning() {
let uuid = UUID(uuidString: "XXXXX")!
let beaconRegion = CLBeaconRegion(proximityUUID: uuid, major: 0, minor: 0, identifier: "XXXXX")
locationManager.startMonitoring(for: beaconRegion)
locationManager.startRangingBeacons(in: beaconRegion)
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
extendBackgroundRunningTime()
if beacons.count > 0 {
print(beacons)
updateDistance(beacons[0].proximity)
} else {
updateDistance(.unknown)
}
}
You Cannot scan Bluetooth device with this method.You can only scan bluetooth device with Core Bluetooth Frame work.
Go through the below tutorial for bluetooth.
Press here for link

swift cant get beacon

Have a project from 2 yrs ago that I just updated from swift 3 to 4. No real significant changes other than the plist getting new permissions. Ran the app on a real device and the beacon isn't being found. UUID, major and minor all verified numerous times to be valid and correct. BKON beacon is sitting next to phone.
plist is like so
location manager is setup like so in viewDidLoad
var locationManager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print("locationManager setup")
locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.delegate = self
}
Region/beacon setup
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
if CLLocationManager.isRangingAvailable() {
setupBeacons()
}
}
}
}
func setupBeacons(){
print("setupBeacons")
if let beaconUUID = UUID.init(uuidString: "58de905b-3b54-bf9d-2d01-4dc018eaf6cc") {
let region1 = CLBeaconRegion(
proximityUUID: beaconUUID,
major: 998,
minor: 1330, //2121
identifier: "Crossing1")
region1.notifyOnEntry = true
region1.notifyOnExit = true
region1.notifyEntryStateOnDisplay = true
startMonitoringBeacon(region: region1)
}
}
func startMonitoringBeacon(region: CLBeaconRegion){
locationManager.startMonitoring(for: region)
locationManager.startRangingBeacons(in: region)
}
I then have the delegate call back set like so
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
print("didRangeBeacons: found \(beacons.count)")
}
But no beacons are ever found. No errors or anything in the other delegate methods (rangingBeaconsDidFailFor, monitoringDidFailFor and didFailWithError). I've already tried removing all beacons from the locationmanager, uninstalling, reinstalling the app numerous times and rebuilding the app from scratch.
Is there something I am missing?

CLLocationManager not monitoring regions

I am perplexed...I had this working today and now I don't know what is going on. It isn't my iBeacon because I can locate it with the Locate iOS app. I am creating my own location manager, not sure if you would call it a subclass exactly because I am subclassing NSObject. Here it is:
//
// LocationManager.swift
// onebeacon
//
// Created by Eamon White on 2/24/18.
// Copyright © 2018 EamonWhite. All rights reserved.
//
import Foundation
import CoreLocation
protocol LocationManagerDelegate: class {
func locationManagerDidUpdateLocation(_ locationManager: LocationManager, location: CLLocation)
func locationManagerDidUpdateHeading(_ locationManager: LocationManager, heading: CLHeading, accuracy: CLLocationDirection)
func locationManagerDidEnterRegion(_ locationManager: LocationManager, didEnterRegion region: CLRegion)
func locationManagerDidExitRegion(_ locationManager: LocationManager, didExitRegion region: CLRegion)
func locationManagerDidDetermineState(_ locationManager: LocationManager, didDetermineState state: CLRegionState, region: CLRegion)
func locationManagerDidRangeBeacons(_ locationManager: LocationManager, beacons: [CLBeacon], region: CLBeaconRegion)
}
class LocationManager: NSObject, CLLocationManagerDelegate {
private var locationManager: CLLocationManager!
weak var delegate: LocationManagerDelegate?
var beaconsToRange: [CLBeaconRegion]
var currentLocation: CLLocation!
override init() {
self.beaconsToRange = []
super.init()
self.locationManager = CLLocationManager()
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
self.locationManager.distanceFilter = kCLDistanceFilterNone
self.locationManager.headingFilter = kCLHeadingFilterNone
self.locationManager.pausesLocationUpdatesAutomatically = false
self.locationManager.delegate = self
self.enableLocationServices()
}
func enableLocationServices() {
self.checkStatus(status: CLLocationManager.authorizationStatus())
}
func checkStatus(status: CLAuthorizationStatus) {
switch status {
case .notDetermined:
// Request when-in-use authorization initially
locationManager.requestAlwaysAuthorization()
break
case .restricted, .denied:
// Disable location features
print("send an alert that the app will not function")
break
case .authorizedWhenInUse:
locationManager.requestAlwaysAuthorization()
// Enable basic location features
break
case .authorizedAlways:
locationManager.startUpdatingLocation()
locationManager.startUpdatingHeading()
self.monitorBeacons()
// Enable any of your app's location features
break
}
}
func monitorBeacons() {
print("monitorBeacons()")
if CLLocationManager.isMonitoringAvailable(for:
CLBeaconRegion.self) {
print("monitorBeacons().monitoringIsAvailable")
// Match all beacons with the specified UUID
let proximityUUID = UUID(uuidString:
"12345678-B644-4520-8F0C-720EAF059935")
let beaconRegion = CLBeaconRegion(
proximityUUID: proximityUUID!,
major: 0x0001,
minor: 0x0002,
identifier: "iBeacon")
beaconRegion.notifyEntryStateOnDisplay = true;
self.locationManager?.startMonitoring(for: beaconRegion)
print("\(String(describing: self.locationManager?.monitoredRegions)) + monitoredRegions")
}
}
//MARK: - CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for location in locations {
self.delegate?.locationManagerDidUpdateLocation(self, location: location)
}
self.currentLocation = manager.location
}
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
self.delegate?.locationManagerDidUpdateHeading(self, heading: newHeading, accuracy: newHeading.headingAccuracy)
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region is CLBeaconRegion {
// Start ranging only if the feature is available.
if CLLocationManager.isRangingAvailable() {
locationManager?.startRangingBeacons(in: region as! CLBeaconRegion)
// Store the beacon so that ranging can be stopped on demand.
beaconsToRange.append(region as! CLBeaconRegion)
}
}
self.delegate?.locationManagerDidEnterRegion(self, didEnterRegion: region)
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
self.delegate?.locationManagerDidExitRegion(self, didExitRegion: region)
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
if region is CLBeaconRegion {
print("determined state of beacon")
// Start ranging only if the feature is available.
if CLLocationManager.isRangingAvailable() {
print("determined state of beacon and started ranging")
locationManager?.startRangingBeacons(in: region as! CLBeaconRegion)
// Store the beacon so that ranging can be stopped on demand.
beaconsToRange.append(region as! CLBeaconRegion)
}
}
self.delegate?.locationManagerDidDetermineState(self, didDetermineState: state, region: region)
}
func locationManager(_ manager: CLLocationManager,
didRangeBeacons beacons: [CLBeacon],
in region: CLBeaconRegion) {
self.delegate?.locationManagerDidRangeBeacons(self, beacons: beacons, region: region)
}
func locationManagerShouldDisplayHeadingCalibration(_ manager: CLLocationManager) -> Bool {
return true
}
func locationManager(_ manager: CLLocationManager,
didChangeAuthorization status: CLAuthorizationStatus) {
self.checkStatus(status: status)
}
}
In my ViewController I use it in a very straight forward fashion like this (at the top: delegate methods...somewhat inconsequential for the problem, at the bottom: instantiation):
import UIKit
import SceneKit
import ARKit
import CoreLocation
class ViewController: UIViewController, ARSCNViewDelegate, LocationManagerDelegate {
func locationManagerDidUpdateLocation(_ locationManager: LocationManager, location: CLLocation) {
}
func locationManagerDidUpdateHeading(_ locationManager: LocationManager, heading: CLHeading, accuracy: CLLocationDirection) {
}
func locationManagerDidEnterRegion(_ locationManager: LocationManager, didEnterRegion region: CLRegion) {
}
func locationManagerDidExitRegion(_ locationManager: LocationManager, didExitRegion region: CLRegion) {
}
func locationManagerDidDetermineState(_ locationManager: LocationManager, didDetermineState state: CLRegionState, region: CLRegion) {
}
func locationManagerDidRangeBeacons(_ locationManager: LocationManager, beacons: [CLBeacon], region: CLBeaconRegion) {
print("\(beacons) + beacons for ranging")
if beacons.count > 0 {
let nearestBeacon = beacons.first!
let major = CLBeaconMajorValue(truncating: nearestBeacon.major)
let minor = CLBeaconMinorValue(truncating: nearestBeacon.minor)
print("major: \(major)")
print("minor: \(minor)")
print("accuracy: \(nearestBeacon.accuracy)")
switch nearestBeacon.proximity {
case .immediate:
print("--- immediate ---")
case .near:
print("--- near ---")
case .far:
print("--- far ---")
case .unknown:
print("--- proximity unknown ---")
}
}
}
var sceneView: ARSCNView!
var locationManager: LocationManager!
override func viewDidLoad() {
super.viewDidLoad()
sceneView = ARSCNView()
locationManager = LocationManager()
locationManager.delegate = self
...
My console output is:
2018-02-24 20:40:30.927542-0500 onebeacon[1275:423523] [DYMTLInitPlatform] platform initialization successful
2018-02-24 20:40:32.799470-0500 onebeacon[1275:423484] Metal GPU Frame Capture Enabled
2018-02-24 20:40:32.801237-0500 onebeacon[1275:423484] Metal API Validation Enabled
monitorBeacons()
monitorBeacons().monitoringIsAvailable
Optional(Set([CLBeaconRegion (identifier:'iBeacon', uuid:12345678-B644-4520-8F0C-720EAF059935, major:1, minor:2)])) + monitoredRegions
All of the iBeacon details are correct, there is no way they could have changed from earlier today as it has been plugged in this whole time and not accessed. The problem summarized: it appears to add the region to the "regions-to-be-monitored" list, but the monitoring never seems to start because I get no console messages relaying the iBeacon information.
UPDATE
I will leave the answer I provided as it might be part of it (maybe not)...but now it seems to be starting twice:
2018-02-24 21:35:13.341162-0500 onebeacon[1345:444027] [DYMTLInitPlatform] platform initialization successful
2018-02-24 21:35:16.504017-0500 onebeacon[1345:443977] Metal GPU Frame Capture Enabled
2018-02-24 21:35:16.505384-0500 onebeacon[1345:443977] Metal API Validation Enabled
monitorBeacons()
monitorBeacons().monitoringIsAvailable
Optional(Set([CLBeaconRegion (identifier:'iBeacon', uuid:12345678-B644-4520-8F0C-720EAF059935, major:1, minor:2)])) + monitoredRegions
2018-02-24 21:35:16.747004-0500 onebeacon[1345:443977] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2018-02-24 21:35:16.747969-0500 onebeacon[1345:443977] [MC] Reading from public effective user settings.
monitorBeacons()
monitorBeacons().monitoringIsAvailable
Optional(Set([CLBeaconRegion (identifier:'iBeacon', uuid:12345678-B644-4520-8F0C-720EAF059935, major:1, minor:2)])) + monitoredRegions
As you can see the monitorBeacons()... lines happen twice, I checked to make sure that there is no other instantiation of LocationManager and there isn't.
UPDATE
I narrowed it down...the problem seems to be that the didDetermineState function is not firing initially, I have to walk out of range (or close to it) from the beacon...and then walk back and the didDetermineState method fires, does anyone know why it isn't firing when I am starting in the radius of the beacon?
UPDATE
It appears that my phone is recognizing that it is in a region because when I walk out of the region, the didExitRegion method fires, and then the didDetermineState method...odd because the state should already be determined if the didExitRegion method is firing:
2018-02-24 23:01:09.650445-0500 onebeacon[422:33762] [App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction
2018-02-24 23:01:09.651978-0500 onebeacon[422:33762] [App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction
2018-02-24 23:01:15.007844-0500 onebeacon[422:33762] [App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction
2018-02-24 23:01:15.007893-0500 onebeacon[422:33762] [App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction
2018-02-24 23:02:00.002451-0500 onebeacon[422:33762] Status bar could not find cached time string image. Rendering in-process.
...(put in for easier reading)...
did exit region --- CLBeaconRegion (identifier:'iBeacon', uuid:12345678-B644-4520-8F0C-720EAF059935, major:1, minor:2)
determined state of beacon
determined state of beacon and started ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging
[] + beacons for ranging
What is the pre-commit handler warning? Are those relevant?
My didDetermineState function stopped working on initial load of the app. If I walk outside the range of the beacon, and back into range - the didDetermineState method fires (along with enter/exit region methods). I purchased another iBeacon...and it works fine...also, curiously, when I use both beacons together, both beacons get detected on initial load by didDetermineState. I am not sure why didDetermineState stopped working for the one beacon...when being used in isolation.

Display "Cannot find iBeacon" message

My question is very simple. I would like to display an error message i.e. "Cannot find iBeacon" if iBeacon monitoring fails, after calling startSearchingForSessions via a button press after being called in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager = CLLocationManager()
if self.locationManager.responds(to: #selector(CLLocationManager.requestWhenInUseAuthorization)) {
self.locationManager.requestWhenInUseAuthorization()
}
self.locationManager.delegate = self
self.locationManager.pausesLocationUpdatesAutomatically = false
let uuid = UUID(uuidString: "869A6E2E-AE14-4CF5-8313-8D6976058A7A")
self.beaconRegion = CLBeaconRegion(proximityUUID: uuid!, identifier: "com.dejordan.myapp"
startSearchingForSessions()
}
func startSearchingForSessions() {
// Start looking for the beacons with that UUID and Identifier.
self.locationManager.startMonitoring(for: self.beaconRegion)
self.locationManager.startRangingBeacons(in: self.beaconRegion)
self.locationManager.startUpdatingLocation()
}
And handling the found beacons thusly:
// Required by the Location Manager.
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
self.locationManager.startRangingBeacons(in: self.beaconRegion)
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
if state == CLRegionState.outside {
print("Cannot Find Beacon")
}
}
// Required by the Location Manager.
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
self.locationManager.stopRangingBeacons(in: self.beaconRegion)
}
// This is called if any beacons are found.
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
var result = Array<CLBeacon>()
for beacon in beacons {
result.append(beacon)
}
foundBeacons = result
// If we found any, we need to see
// what class they belong to based on information
// from Parse.
self.identifyFoundBeacons()
// We can stop looking for beacons now.
self.locationManager.stopMonitoring(for: self.beaconRegion)
self.locationManager.stopRangingBeacons(in: self.beaconRegion)
self.locationManager.stopUpdatingLocation()
}
I have implemented the delegate error methods in an attempt to find where this occurs but thus far in navigating the mounds of documentation on iBeacon I have come up fruitless.
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Location manager failed: \(error.localizedDescription)")
}
func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
print("Failed monitoring region: \(error.localizedDescription)")
}
Thank you!
If you simply want to know when beacons are not detected (vs. when there was a low-level failure to look for beacons), then simply use the following delegate method:
public func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
if state == CLRegionState.outside {
print("Cannot find beacon")
}
}
Interestingly enough, didRangeBeacons in the delegate method
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion)
gets called with an empty array of [CLBeacon]s, wherein I can use the beacons array size to determine whether or not any beacons were found.
Not what I expected, but this has solved my problem!

Resources