简体   繁体   中英

How to detect ibeacon device without knowing UUID in iOS?

I would like to develop app which detects a lot of beacon device without knowing uuid. However I cannot find way to do this. I have to define uuid in code.

I have developed a POC which works with known devices.

My View Controller code:

-(void)setUpview
{
     // Regardless of whether the device is a transmitter or receiver, we need a beacon region.
    NSUUID * uid = [[NSUUID alloc] initWithUUIDString:@"78CDC73D-D678-4B35-A88A-C2E09E5B963F"];//[UIDevice currentDevice].identifierForVendor;
    treasureId = @"com.eden.treasure";
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uid identifier:treasureId];

    // Location manager.
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;

    if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [self.locationManager requestAlwaysAuthorization];
    }

    [self.locationManager startMonitoringForRegion:self.beaconRegion];
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
    [self locationManager:self.locationManager didStartMonitoringForRegion:self.beaconRegion];

    [self.beaconRegion setNotifyEntryStateOnDisplay:YES];
    [self.beaconRegion setNotifyOnEntry:YES];
    [self.beaconRegion setNotifyOnExit:YES];

//    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
    if ([UIDevice currentDevice].userInterfaceIdiom==UIUserInterfaceIdiomPad || [[[UIDevice currentDevice] model] isEqualToString:@"iPad Simulator"])
    {
        [self configureTransmitter];
    }
    else {
        [self configureReceiver];
    }
}


-(void)configureTransmitter
{
    // The received signal strength indicator (RSSI) value (measured in decibels) for the device. This value represents the measured strength of the beacon from one meter away and is used during ranging. Specify nil to use the default value for the device.
    NSNumber * power = [NSNumber numberWithInt:-63];
    self.peripheralData = [self.beaconRegion peripheralDataWithMeasuredPower:power];
    // Get the global dispatch queue.
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // Create a peripheral manager.
    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:queue];
}

-(void)configureReceiver {
    // Location manager.
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    [self.locationManager requestAlwaysAuthorization];
    [self.locationManager startMonitoringForRegion:self.beaconRegion];
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}
#pragma mark - CBPeripheralManagerDelegate methods

-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
    // The peripheral is now active, this means the bluetooth adapter is all good so we can start advertising.
    if (peripheral.state == CBPeripheralManagerStatePoweredOn)
    {
        [self.peripheralManager startAdvertising:self.peripheralData];
    }
    else if (peripheral.state == CBPeripheralManagerStatePoweredOff)
    {
        NSLog(@"Powered Off");
        [self.peripheralManager stopAdvertising];
    }  
}
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    if(state == CLRegionStateInside)
    {
        NSLog(@"%@",[NSString stringWithFormat:@"You are inside region %@", region.identifier]);
    }
    else if(state == CLRegionStateOutside)
    {
        NSLog(@"%@",[NSString stringWithFormat:@"You are outside region %@", region.identifier]);
    }
    else
    {
        return;
    }
}

-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
    if ([beacons count] == 0)
        return;

    NSString * message;
    UIColor * bgColor;
    CLBeacon * beacon = [beacons firstObject];

    switch (beacon.proximity) {
        case CLProximityUnknown:
            message = [NSString stringWithFormat:@"ProximityUnknown -- %ld", (long)beacon.proximity];
            bgColor = [UIColor blueColor];
            break;
        case CLProximityFar:
            message = [NSString stringWithFormat:@"ProximityFar -- %ld", (long)beacon.proximity];
            bgColor = [UIColor colorWithRed:.0f green:.0f blue:230.0f alpha:1.0f];
            break;
        case CLProximityNear:
            message = [NSString stringWithFormat:@"ProximityNear -- %ld", (long)beacon.proximity];
            bgColor = [UIColor orangeColor];
            break;
        case CLProximityImmediate:
        default:
            message = [NSString stringWithFormat:@"ProximityImmediate -- %ld", (long)beacon.proximity];
            bgColor = [UIColor redColor];
            break;
    }
    if (beacon.proximity != self.previousProximity)
    {
        [lblStatus setText:message];
        [self.view setBackgroundColor:bgColor];
        self.previousProximity = beacon.proximity;  
    }  
}

So is there any way to detect iBeacon without knowing uuid?

Note: Example application that is using same feature as check This link broadcasting broadcasting signals(Virtual Beacons).

Any help would be highly appreciated.

There are no public APIs in iOS to detect beacons without first knowing at least the ProximityUUID of the beacon. This is by design -- Apple only wants you to be able to see your own beacons, which means knowing the ProximityUUID.

That said, the operating system certainly knows how to see any beacon and there may be private APIs you can use to do this . Just understand that you can't use private APIs to develop an app for the App Store, as Apple will not approve the use of such code. You can use private APIs to make a utility for use your own iOS device, but the private APIs may stop working with any iOS upgrade

With those caveats stated, using CoreLocation it may be possible to define a wildcard CLBeaconRegion that can be used to look for any beacon using a private API. See here for one approach.

You need to use the CoreBluetooth library to scan for devices. Once you find your iBeacon from the list of discovered devices, you will have query the iBeacon's services and characteristics to find the UUID. Here's how I did it:

import CoreBluetooth
import CoreLocation

extension Data {

    public var hexString: String {
        var str = ""
        enumerateBytes { (buffer, index, stop) in
            for byte in buffer {
                str.append(String(format: "%02X", byte))
            }
        }
        return str
    }
}

class viewController: UIViewController, CLLocationManagerDelegate, CBCentralManagerDelegate, CGPeripheralDelegate {

    var locationManager: CLLocationManager = CLLocationManager()
    var myBeaconRegion: CLBeaconRegion!
    var centralManager: CBCentralManager!
    var discoveredPeripheral: CBPeripheral?

    override viewDidLoad() {

        centralManager = CBCentralManager(delegate: self, queue: nil)
    }

    func centralManagerDidUpdateState(_ central: CBCentralManager) {

        if central.state != .poweredOn {
            return
        }

        centralManager.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicateKeys: true])
    }

    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {

        if (RSSI.intValue > -15 || RSSI.intValue < -35) {
            return // With those RSSI values, probably not an iBeacon.
        }

        if peripheral != discoveredPeripheral {
            discoveredPeripheral = peripheral // Need to retain a reference to connect to the beacon.
            centralManager.connect(peripheral, options: nil)
            central.stopScan() // No need to scan anymore, we found it.
        }
    }

    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {

        peripheral.discoverServices(nil)
    }

    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {

        discoveredPeripheral = nil
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {

        guard error == nil else {
            return
        }

        if let services = peripheral.services {
            for service in services {
                peripheral.discoverCharacteristics(nil, for: service)
            }
        }
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {

        guard error == nil else {
            return
        }

        if let characteristics = service.characteristics {
            for characteristic in characteristics {
                if characteristic.uuid.uuidString == "2B24" { // UUID
                    peripheral.readValue(for: characteristic)
                }
            }
        }
    }

    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {

        guard error == nil else {
            return;
        }

        if value = characteristic.value {
            // value will be a Data object with bits that represent the UUID you're looking for.
            print("Found beacon UUID: \(value.hexString)")
            // This is where you can start the CLBeaconRegion and start monitoring it, or just get the value you need.
        }
    }

I was also searching for the same & I got my answer on this example enter link description here

This is searching all iBeacons without UUID

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM