This question has been asked here, but it's not solving my problem, I will explain why it doesn't solve the problem at the end of the question.
What I'm doing takes 2 steps:
Let CBCentralManager discover peripherals
Let CLLocationManager listen to beacons discovered in step 1
I found out the UUID of my beacon with the following delegate method:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
print(peripheral.identifier)
}
Then step 2 takes place:
if let uuid = UUID.init(uuidString: "<identifier found in step 1>") {
locationManager.startRangingBeacons(in: .init(proximityUUID: uuid, identifier: UUID().uuidString))
}
My locationManager's delegate method simply prints all beacons in range:
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
print(beacons)
}
But all I'm getting is an empty array. Why? How do I fix this?
The question listed above suggests that when creating a CLBeaconRegion
, we should give a unique identifier, which I am already doing.
The problem is with this statement:
I found out the UUID of my beacon with the following delegate method:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { print(peripheral.identifier) }
The value returned by peripheral.identifier
is not your beacon's proximityUUID
. Because of this, the didRangeBeacons
returns an empty array, because there are no beacons in the vicinity with a proxmityUUID
matching the CLBeaconRegion
you set up.
Here's a deeper explanation:
The peripheral.identifier
field comes from the CBPeripheral
object, which inherits it from CBPeer
. Apple's documentation here describes it this way:
The value of this property represents the unique identifier of the peer. The first time a local manager encounters a peer, the system assigns the peer a UUID, represented by a new NSUUID object. Peers are identified by NSUUID UUIDs instead of by the CBUUID objects that identify a peripheral’s services, characteristics, and characteristic descriptors.
Basically, this field is just a temporary identifier assigned to bluetooth device by iOS. While it is represented by a NSUUID
(as it's called in Objective C or just UUID
in Swift), and the CLBeacon
/CLBeaconRegion
have a proximityUUID
field that is also an instance of NSUUID
, they are not the same value. This is a common source of confusion.
Unfortunately, it is impossible to use CoreBluetooth APIs to get the ProximityUUID of your beacon. Apple intentionally goes to some lengths to prevent you from doing this. Sorry.