ios 在后台将 iPhone 作为 iBeacon 运行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18944325/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:31:58  来源:igfitidea点击:

Run iPhone as an iBeacon in the background

iosbluetoothbluetooth-lowenergyibeacon

提问by jpcoder

Is it possible to run an iOS 7 device as a Bluetooth LE peripheral (iBeacon) and have it advertise in the background? I have been able to get it to advertise in the foreground with the code below and can see it from another iOS device but as soon as I go back to the home screen it stops advertising. I did add the bluetooth-peripheral background mode in the plist but that didn't seem to help although I do get the prompt saying the device wants to use bluetooth in the background. Am I doing something wrong or is this just not possible in iOS 7?

是否可以将 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];
}

Here is the code that is on the receiving/listening end:

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

- (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;
    }
}
}

回答by bentford

Standard CoreBluetooth advertisements can broadcast while the app is in the background, but not if they were started with CLBeaconRegiondictionary. The workaround is to ditch CoreLocation framework altogether and create your own proximity "framework" using only CoreBlueTooth.

标准 CoreBluetooth 广告可以在应用程序处于后台时广播,但如果它们以CLBeaconRegion字典开头则不能广播。解决方法是完全放弃 CoreLocation 框架并仅使用 CoreBlueTooth 创建您自己的邻近“框架”。

You still need to use the appropriate background specifiers in the Info.plist file (e.g. bluetooth-peripheraland bluetooth-central).

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

The code looks something like this:

代码如下所示:

1) create a standard peripheral advertisement using CBPeripheralManager

1) 使用创建一个标准的外围广告 CBPeripheralManager

NSDictionary *advertisingData = @{CBAdvertisementDataLocalNameKey:@"my-peripheral",
                                  CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:identifier]]};

// Start advertising over BLE
[peripheralManager startAdvertising:advertisingData];

2) use use CBCentralManagerto scan for that service using the UUID you specified.

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

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

[centralManager scanForPeripheralsWithServices:services options:scanOptions];

3) in the CBCentralManagerDelegatemethod didDiscoverPeripheral, read the RSSIvalue of the advertisement.

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

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{

    NSLog(@"RSSI: %d", [RSSI intValue]);
}

4) Translate the RSSI values into a distance.

4) 将 RSSI 值转换为距离。

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

    return INDetectorRangeUnknown;
}

I found that I needed to "ease" or "average" the RSSI values to get anything workable. This is no different than when you are working with any sensor data (e.g. accelerometer data).

我发现我需要“简化”或“平均”RSSI 值才能得到任何可行的结果。这与您处理任何传感器数据(例如加速度计数据)时没有什么不同。

I have this concept fully working hope to publish it somewhere at some point.

我有这个概念完全有效,希望在某个时候将它发布到某个地方。

Also, use the docs(Core Bluetooth Programming Guide) if you get stuck.

另外,如果遇到困难,请使用文档(核心蓝牙编程指南)。

Update:A full code sample is up on Github. I worked on this as part of a work related project.

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

Update #2:Apple release major improvements to iBeacon background behavior for iOS7.1

更新 #2:Apple 发布了对 iOS7.1 的 iBeacon 后台行为的重大改进

回答by Cameron Lowell Palmer

The Can you smell the iBeacon?article discusses both the use of Estimotes and advertising from Macs and iOS devices. You need to check the capability “Acts as Bluetooth LE accessory” in the project target.

你能闻到iBeacon显示?文章讨论了 Mac 和 iOS 设备上 Estimotes 和广告的使用。您需要检查项目目标中的“充当蓝牙 LE 附件”功能。

回答by RawMean

No, iOS devices only advertise iBeacon when the app that does the advertising runs in the foreground. so, if you switch to another app or if the device goes to sleep, the advertisement stops.

不,iOS 设备仅在执行广告的应用程序在前台运行时才为 iBeacon 做广告。因此,如果您切换到另一个应用程序或设备进入睡眠状态,广告就会停止。

Of course, if you really want the advertisement to continue, disable the idle timer and do Guided Access so that the iOs device does not go to sleep and no one can switch to another app.

当然,如果您真的希望广告继续播放,请禁用空闲计时器并进行引导访问,以便 iOs 设备不会进入睡眠状态,并且没有人可以切换到另一个应用程序。

回答by Duncan C

I am also hoping to be able to set up my (test) app to advertise an iBeacon from the background. The docs on the UIBackgroundModes info.plist key suggest that the bluetooth-peripheral key might work, but it seems that it doesn't. (I just tested it a few minutes ago.)

我也希望能够设置我的(测试)应用程序以从后台宣传 iBeacon。UIBackgroundModes info.plist 键上的文档表明蓝牙外设键可能有效,但似乎无效。(我几分钟前刚刚测试过。)

What I'm doing for now is setting the idle timer to disabled, as RawMean suggests, and then setting the screen brightness to 0. Finally, when my test app is acting as an iBeacon, I add a shake event handler that lights the screen up again for 30 seconds. Dimming the screen as low as it will go helps reduce battery drain somewhat.

我现在正在做的是将空闲计时器设置为禁用,如 RawMean 建议的那样,然后将屏幕亮度设置为 0。最后,当我的测试应用程序充当 iBeacon 时,我添加了一个点亮屏幕的抖动事件处理程序再次上升 30 秒。尽可能降低屏幕亮度有助于在一定程度上减少电池消耗。