71

iOS 7 デバイスを Bluetooth LE ペリフェラル (iBeacon) として実行し、バックグラウンドでアドバタイズすることはできますか? 以下のコードを使用してフォアグラウンドで広告を表示することができ、別の iOS デバイスからも表示できますが、ホーム画面に戻るとすぐに広告が停止します。plist に bluetooth-peripheral バックグラウンド モードを追加しましたが、デバイスがバックグラウンドで bluetooth を使用したいというプロンプトが表示されても、それは役に立たないようです。私は何か間違ったことをしていますか、それとも 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;
    }
}
}
4

4 に答える 4

52

標準の 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) use を使用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: Apple が iOS7.1 の iBeacon バックグラウンド動作の大幅な改善をリリース

于 2013-11-12T22:39:58.777 に答える
2

いいえ、iOS デバイスは、広告を行うアプリがフォアグラウンドで実行されている場合にのみ iBeacon を広告します。そのため、別のアプリに切り替えるか、デバイスがスリープ状態になると、広告は停止します。

もちろん、本当に広告を継続させたい場合は、アイドル タイマーを無効にしてガイド付きアクセスを実行し、iOS デバイスがスリープ状態にならないようにして、誰も別のアプリに切り替えることができないようにします。

于 2013-10-18T02:29:01.160 に答える
1

また、(テスト) アプリをセットアップして、バックグラウンドから iBeacon をアドバタイズできるようにしたいと考えています。UIBackgroundModes info.plist キーのドキュメントは、bluetooth-peripheral キーが機能する可能性があることを示唆していますが、機能していないようです。(数分前にテストしました。)

今のところ、RawMean が示唆するように、アイドル タイマーを無効に設定し、画面の明るさを 0 に設定しています。最後に、テスト アプリが iBeacon として機能しているときに、画面を点灯させるシェイク イベント ハンドラを追加します。再び 30 秒間上昇します。画面をできるだけ暗くすると、バッテリーの消耗をいくらか減らすことができます。

于 2013-10-29T13:58:42.490 に答える