是否可以使用目标 C 扫描禁用位置服务的信标?

Posted

技术标签:

【中文标题】是否可以使用目标 C 扫描禁用位置服务的信标?【英文标题】:Is it possible to scan a beacon with location service disable using objective C? 【发布时间】:2016-09-21 13:26:49 【问题描述】:

如果打开蓝牙和定位服务,我可以成功扫描信标。但我想知道当蓝牙处于开启模式且位置服务处于关闭模式时,有什么方法可以扫描信标。

我已经使用了这段代码,但是当位置服务关闭时,这个委托方法不会被调用

-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region 

谁能详细说明我们如何在没有定位服务的情况下扫描信标?

提前致谢。

【问题讨论】:

是的,我猜你可以的。 【参考方案1】:

在蓝牙开启但定位关闭的情况下,您只能使用CoreBluetooth API 而非CoreLocation API 来检测蓝牙 LE 信标设备。

这有效地阻止了您检测 iBeacon 传输,因为 ios 通过 CoreBluetooth 阻止了它们的检测。在此处查看我的博文:http://developer.radiusnetworks.com/2013/10/21/corebluetooth-doesnt-let-you-see-ibeacons.html

不过,您可以使用CoreBluetooth 来检测其他信标格式,例如 AltBeacon 和 Eddystone。我有开源代码显示如何使用iOS beacon tools 来做到这一点。

以下是使用上述工具扫描 AltBeacon、Eddystone-UID、Eddystone-URL 和 Eddystone-EID 并记录检测到的标识符的示例:

self.beaconParsers = [[NSMutableArray alloc] init];
RNLBeaconParser *altBeaconParser = [[RNLBeaconParser alloc] init];
[altBeaconParser setBeaconLayout:@"m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25" error: Nil ];
RNLBeaconParser *uidBeaconParser = [[RNLBeaconParser alloc] init];
[uidBeaconParser setBeaconLayout:@"s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19" error: Nil];
RNLBeaconParser *urlBeaconParser = [[RNLBeaconParser alloc] init];
[urlBeaconParser setBeaconLayout:@"s:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-20v" error: Nil];
RNLBeaconParser *eidBeaconParser = [[RNLBeaconParser alloc] init];
[eidBeaconParser setBeaconLayout:@"s:0-1=feaa,m:2-2=30,p:3-3:-41,i:4-11" error: Nil];
self.beaconParsers = @[ altBeaconParser, uidBeaconParser, urlBeaconParser, eidBeaconParser ];
self.cbManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()
                                                  options:@ CBCentralManagerOptionRestoreIdentifierKey:
                                                               @"myCentralManagerIdentifier" ];

...

- (void)centralManagerDidUpdateState:(CBCentralManager *)central 
  if (central.state == CBCentralManagerStatePoweredOn && self.scanning) 
    CBUUID *eddystone16BitUUID = [CBUUID UUIDWithString:@"FEAA"];
    NSLog(@"eddy uuid is %@", [eddystone16BitUUID UUIDString]);
    [self.cbManager scanForPeripheralsWithServices:@[eddystone16BitUUID] options:@CBCentralManagerScanOptionAllowDuplicatesKey : @(YES)];
    // this scans for BLE peripherals including beacons
    [self.cbManager scanForPeripheralsWithServices:nil options:@CBCentralManagerScanOptionAllowDuplicatesKey : @(YES)];

  
  else 
    if (central.state == CBCentralManagerStateUnknown) 
      NSLog(@"CoreBluetooth state UNKNOWN");
    
    else if (central.state == CBCentralManagerStateResetting)  
      NSLog(@"CoreBluetooth state RESETTING");
    
    else if (central.state == CBCentralManagerStateUnsupported)  
      NSLog(@"CoreBluetooth state UNSUPPORTED");
    
    else if (central.state == CBCentralManagerStateUnauthorized)  
      NSLog(@"CoreBluetooth state UNAUTHORIZED");
    
    else if (central.state == CBCentralManagerStatePoweredOff)  
      NSLog(@"CoreBluetooth state POWERED OFF");
    
  



- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI 
  NSDictionary *serviceData = advertisementData[@"kCBAdvDataServiceData"];

  RNLBeacon *beacon = Nil;
  NSData *adData = advertisementData[@"kCBAdvDataManufacturerData"];

  for (RNLBeaconParser *beaconParser in self.beaconParsers) 
    if (adData) 
      beacon = [beaconParser fromScanData: adData withRssi: RSSI forDevice: peripheral serviceUuid: Nil];
      beacon.bluetoothIdentifier = [peripheral.identifier UUIDString];
    
    else if (serviceData != Nil) 
      for (NSObject *key in serviceData.allKeys) 
        NSString *uuidString = [(CBUUID *) key UUIDString];
        NSScanner* scanner = [NSScanner scannerWithString: uuidString];
        unsigned long long uuidLongLong;

        [scanner scanHexLongLong: &uuidLongLong];
        NSNumber *uuidNumber = [NSNumber numberWithLongLong:uuidLongLong];

        NSData *adServiceData = [serviceData objectForKey:key];
        if (adServiceData) 
          beacon = [beaconParser fromScanData: adServiceData withRssi: RSSI forDevice: peripheral serviceUuid: uuidNumber];
        
      
    
    if (beacon != Nil) 
      break;
    
  

  if (beacon != Nil) 
    NSString *key = [NSString stringWithFormat:@"%@ %@ %@", beacon.id1, beacon.id2, beacon.id3];
    NSLog(@"Detected beacon: %@", key);

【讨论】:

但是即使位置服务关闭,Crome 小部件也能够扫描 IBeacon。你能分享一下你在这背后的知识吗? Chrome 小部件扫描 Eddystone-URL 传输,而不是 iBeacon 传输。这就是为什么没有 CoreLocation 也能做到这一点的原因。在这里查看更多:developer.radiusnetworks.com/2015/07/22/… 查看我的答案编辑,其中包含指向测试的链接,证明您无法使用 CoreBluetooth 检测 iBeacon,以及使用 CoreBluetooth 检测其他信标格式的代码。 非常感谢。您能告诉我如何使用 CoreBluetooth 框架来扫描 Eddystone 信标吗? 抱歉,您根本无法在 iOS 上使用公共 API 扫描所有 iBeacon UUID。 Apple 故意不允许这样做。【参考方案2】:

不,我认为您不能在关闭位置服务的情况下使用系统 iBeacon 支持。 iBeacon 支持由 Core Location 框架提供。

您也许可以编写低级 BLE 代码来查找来自 iBeacons 的消息,但我看到了一些人的帖子,他们无法弄清楚如何做到这一点。此外,您将失去 Core Location 提供的好处,例如即使在检测到信标时您的应用没有运行,也会收到有关信标的通知。

【讨论】:

感谢您的回答。但是即使位置服务关闭,Google Crome 是如何扫描信标的呢?正如我们在 Crome 小部件中看到的最近的信标。你能分享一下这背后的一些想法吗? 我怀疑他们有自己的 BLE 库来检测 iBeacons。【参考方案3】:

不,您不能在没有定位服务的情况下使用 iBeacon。检查苹果文档是怎么说的:

iBeacon 与 iOS 中的定位服务一起使用。使用 iBeacon,您的 iOS 当您接近或离开某个位置时,设备可以提醒应用程序。在 除了监控您的位置,应用程序还知道您何时靠近 到 iBeacon,例如零售店的收银台。代替 使用纬度和经度来确定您的位置,iBeacon 使用 您的 iOS 设备检测到的低功耗蓝牙信号。

更多详情可以阅读Apple support for iBracon

希望这会有所帮助:)

【讨论】:

以上是关于是否可以使用目标 C 扫描禁用位置服务的信标?的主要内容,如果未能解决你的问题,请参考以下文章

为特定应用启用定位服务?

是否可以通过仅禁用该模块来支持在 4.3 之前版本上运行的 android 设备上使用信标技术的应用程序?

iOS 范围检测具有预定义接近度 UDID 的信标

使用 Fused Location Provider 获取启用/禁用位置服务的信息

核心位置 StartMonitoring 后台工作

目标 c - 重大的位置变化