是否可以将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;
}
}
}
答案 0 :(得分:47)
标准CoreBluetooth广告可以在应用程序处于后台时进行广播,但如果它们是以CLBeaconRegion
字典启动则不会。解决方法是完全放弃CoreLocation框架,并仅使用CoreBlueTooth创建自己的邻近“框架”。
您仍需要使用Info.plist文件中的相应背景说明符(例如bluetooth-peripheral
和bluetooth-central
)。
代码看起来像这样:
1)使用CBPeripheralManager
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值才能使任何事情变得可行。这与使用任何传感器数据(例如加速计数据)时没有什么不同。
我有一个完全有效的概念,希望在某个时候将它发布到某个地方。
另外,如果卡住了,请使用docs(核心蓝牙编程指南)。
更新:full code sample is up on Github。我作为work related project的一部分来处理这个问题。
更新#2: Apple release major improvements to iBeacon background behavior for iOS7.1
答案 1 :(得分:4)
Can you smell the iBeacon?文章讨论了Estimotes的使用以及Mac和iOS设备的广告。您需要在项目目标中检查“充当蓝牙LE附件”的功能。
答案 2 :(得分:2)
不,当广告的应用在前台运行时,iOS设备只会宣传iBeacon。因此,如果您切换到另一个应用程序或设备进入睡眠状态,广告将停止。
当然,如果你真的希望广告继续,请禁用空闲计时器并进行引导访问,以便iOs设备不会进入休眠状态,并且没有人可以切换到另一个应用程序。
答案 3 :(得分:1)
我也希望能够设置我的(测试)应用程序来从后台宣传iBeacon。 UIBackgroundModes info.plist键上的文档表明蓝牙外设密钥可能有效,但似乎没有。 (我刚刚在几分钟前测试过它。)
我现在正在做的是将空闲计时器设置为禁用,如RawMean所示,然后将屏幕亮度设置为0.最后,当我的测试应用程序充当iBeacon时,我添加了一个抖动事件处理程序,再次点亮屏幕30秒。将屏幕调暗尽可能低有助于减少电池消耗。
答案 4 :(得分:0)
这可以做到。我不想惹恼苹果工程师,所以我不会公开该算法。
总而言之,对服务UUID进行编码的溢出区域只是一堆字节,这些字节是无线传输的。您可以自己嗅一下。特别地,这是短哈希,其随后由一个热编码来表示。通过设置多个位来通信多个UUID。您将以这种方式发生碰撞。例如,UUID 1001的编码与3333相同。您可以自己检查一下:在iPhone的背景上广播UUID 1001,然后对3333进行另一次扫描。它将认为它确实接收了3333。