在后台运行iPhone作为iBeacon

是否可以将iOS 7设备作为蓝牙LE外设(iBeacon)运行并在后台投放广告? 我已经能够在下面的代码在前台广告,可以从另一个iOS设备看到它,但只要我回到主屏幕停止广告。 我在plist中添加了蓝牙外设的后台模式,但似乎没有帮助,虽然我得到提示说设备要在后台使用蓝牙。 我做错了什么,或者这只是不可能在iOS 7?

peripManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil]; - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral { if (peripheral.state != CBPeripheralManagerStatePoweredOn) { return; } NSString *identifier = @"MyBeacon"; //Construct the region CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:identifier]; //Passing nil will use the device default power NSDictionary *payload = [beaconRegion peripheralDataWithMeasuredPower:nil]; //Start advertising [peripManager startAdvertising:payload]; } 

这是接收/收听端的代码:

 - (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region { //Check if we have moved closer or farther away from the iBeacon… if (beacons.count > 0) { CLBeacon *beacon = [beacons objectAtIndex:0]; switch (beacon.proximity) { case CLProximityImmediate: [self log:[NSString stringWithFormat:@"You're Sitting on it! %li", (long)beacon.rssi]]; break; case CLProximityNear: [self log:[NSString stringWithFormat:@"Getting Warmer! %li", (long)beacon.rssi]]; break; default: [self log:[NSString stringWithFormat:@"It's around here somewhere! %li", (long)beacon.rssi]]; break; } } } 

标准CoreBluetooth广告可以在应用程序在后台进行广播,但不能在CLBeaconRegion字典中启动。 解决方法是完全放弃CoreLocation框架,仅使用CoreBlueTooth创build您自己的邻近“框架”。

您仍然需要在Info.plist文件中使用适当的背景说明符(例如bluetooth-peripheralbluetooth-central )。

代码看起来像这样:

1)使用CBPeripheralManager创build一个标准的外设广告

 NSDictionary *advertisingData = @{CBAdvertisementDataLocalNameKey:@"my-peripheral", CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:identifier]]}; // Start advertising over BLE [peripheralManager startAdvertising:advertisingData]; 

2)使用CBCentralManager使用您指定的UUID扫描该服务。

 NSDictionary *scanOptions = @{CBCentralManagerScanOptionAllowDuplicatesKey:@(YES)}; NSArray *services = @[[CBUUID UUIDWithString:identifier]]; [centralManager scanForPeripheralsWithServices:services options:scanOptions]; 

3)在CBCentralManagerDelegate方法didDiscoverPeripheral ,读取广告的RSSI值。

 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { NSLog(@"RSSI: %d", [RSSI intValue]); } 

4)将RSSI值转换成距离。

 - (INDetectorRange)convertRSSItoINProximity:(NSInteger)proximity { if (proximity < -70) return INDetectorRangeFar; if (proximity < -55) return INDetectorRangeNear; if (proximity < 0) return INDetectorRangeImmediate; return INDetectorRangeUnknown; } 

我发现我需要对RSSI值进行“简化”或“平均化”以获得任何可行的结果。 这与使用任何传感器数据(例如加速计数据)的情况没有什么不同。

我有这个概念,充分发挥作用,希望在某个地方发布。

另外,如果卡住了,请使用文档 (Core Bluetooth Programming Guide)。

更新: 完整的代码示例在Github上 。 我作为一个工作相关的项目的一部分工作 。

更新#2: 苹果发布iOS7.1的iBeacon背景行为的重大改进

你可以闻到iBeacon? 文章讨论了从Mac和iOS设备使用Estimotes和广告的情况。 您需要检查项目目标中的function“作为Bluetooth LE附件”。

不,iOS设备仅在广告应用在前台运行时才宣传iBeacon。 所以,如果你切换到另一个应用程序或如果设备进入睡眠,广告停止。

当然,如果你真的想要广告继续,禁用空闲计时器,并做指导访问,使iOs设备不会进入睡眠,没有人可以切换到另一个应用程序。

我也希望能够设置我的(testing)应用程序从后台广告一个iBeacon。 UIBackgroundModes info.plist键上的文档表明,蓝牙外设键可能工作,但它似乎没有。 (我刚刚testing了几分钟。)

我现在所做的是将空闲计时器设置为禁用,正如RawMean所build议的那样,然后将屏幕亮度设置为0.最后,当我的testing应用程序充当iBeacon时,我添加了一个摇动事件处理程序来点亮屏幕再次持续30秒。 尽可能降低屏幕亮度,有助于减less电量消耗。