如何在iOS中不知道UUID的情况下检测iBeacon设备?

5
我想开发一个应用程序,可以在不知道UUID的情况下检测到许多信标设备。然而,我找不到实现这一点的方法。我必须在代码中定义UUID。
我已经开发了一个可以与已知设备配合使用的POC。
我的视图控制器代码:
-(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;  
    }  
}

那么有没有办法在不知道UUID的情况下检测iBeacon呢?

注意:使用与此链接广播信号(虚拟信标)相同功能的示例应用程序。

任何帮助将不胜感激。


你不应该能够这样做。如果它是一个真正的 iBeacon(而不是经典 BLE 设备和 iBeacon 的混合体),iOS 应该自动翻译 BLE 广播消息,并仅让其对 CLBeacon 可用。如果它是一个有时广播经典 BLE 信息的混合体,您可以使用 CBPeripheralManager 找到它,并获取 UUID 以扫描 CLBeacon。主要问题是 iOS 只提供高级 API 而不是低级 API,而对于 Android,他们(可以)自己解析消息,因此可以扫描并响应任何他们想要的内容。 - Larme
你需要知道你要查找的UUID。你不能扫描所有的UUID。 - Paulw11
3个回答

12

iOS中没有公共API可以在不首先知道至少ProximityUUID的情况下检测信标。 这是设计如此-苹果只希望您能看到自己的信标,这意味着需要知道ProximityUUID。

话虽如此,操作系统当然知道如何查看任何信标,可能有私有API可用于此。 但是要明白,您不能使用私有API开发App Store应用程序,因为苹果不会批准使用此类代码。 您可以使用私有API制作适用于自己的iOS设备的实用程序,但是私有API可能会因iOS升级而停止工作。

在说明了这些注意事项之后,使用CoreLocation可能可以定义通配符CLBeaconRegion,该区域可用于使用私有API查找任何信标。 可以查看这里获取一种方法。


你说得对,我们已经使用上述示例进行了测试,并且显示出了正确的结果,包括具有不同UUID的iBeacons /虚拟iBeacons。但由于它是私有API,这对实际开发没有用处。无论如何,感谢您提供的信息。非常感谢。 - Merry
大家好,我是新手,对于iBeacon与iOS的集成有一些问题。如果我们只有MajorID,是否可以跟踪这些iBeacon而不需要MinorID?如果可能的话,在代码中它是什么样子的?如何在不同的位置或区域跟踪它们? - Va Visal
是的,这是可能的。您只需在区域定义中留下次要的空值即可实现此操作。 - davidgyoung
1
我编写了该应用程序,并预先编程了十几个UUID,这些UUID是流行的信标制造商的默认值。因此,它可以与许多信标配合使用,但不是所有信标,除非您配置其他UUID。 - davidgyoung
1
每个信标制造商通常会生成自己的UUID,然后按照惯例在出货时使用该UUID作为其所有信标的标准默认设置。您可以通过(a)阅读他们的文档或(b)购买其中一个信标并查看它传输的UUID来了解每个信标制造商默认使用哪些UUID。 - davidgyoung
显示剩余2条评论

1
你需要使用 CoreBluetooth 库来扫描设备。一旦你从发现的设备列表中找到你的 iBeacon,你需要查询 iBeacon 的服务和特征来找到 UUID。这是我做的方法:
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.
        }
    }

我尝试了你的代码...由于"str.append(String(format: "%02X", byte))",这段代码正在改变标识符的值...请验证十六进制转换一次.. - Chaaruu Jadhav

0

我也在寻找同样的答案,最终在这个例子中找到了解决方案在此输入链接描述

这将搜索所有没有UUID的iBeacon


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接