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;
}
}
}
標準の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値を「緩和」または「平均化」して実行可能にする必要があることがわかりました。これは、センサーデータ(加速度計データなど)を使用している場合と変わりません。
私はこの概念を完全に機能させ、ある時点でどこかに公開したいと思っています。
また、行き詰まった場合は docs (Core Bluetooth Programming Guide)を使用してください。
更新:A Githubに完全なコードサンプルがあります 。 作業関連プロジェクト の一部としてこれに取り組みました。
iBeaconの匂いがしますか? の記事では、Estimotesの使用とMacおよびiOSデバイスからの広告の両方について説明しています。プロジェクトターゲットの機能「Bluetooth LEアクセサリとして機能」を確認する必要があります。
いいえ、iOSデバイスは、広告を行うアプリがフォアグラウンドで実行されている場合にのみiBeaconを広告します。そのため、別のアプリに切り替えるか、デバイスがスリープ状態になると、広告は停止します。
もちろん、広告を本当に続けたい場合は、アイドルタイマーを無効にしてガイド付きアクセスを実行し、iOsデバイスがスリープ状態にならず、他のアプリに切り替えられないようにします。
また、バックグラウンドからiBeaconをアドバタイズするために(テスト)アプリをセットアップできることを望んでいます。 UIBackgroundModes info.plistキーに関するドキュメントは、bluetooth-peripheralキーが機能する可能性があることを示唆していますが、機能していないようです。 (数分前にテストしました。)
私が今やっていることは、RawMeanが示唆するように、アイドルタイマーを無効に設定し、画面の明るさを0に設定することです。 30秒間再び立ち上がります。画面をできるだけ暗くすることで、バッテリーの消耗をある程度抑えることができます。
これを行うことができます。怒りたくありませんApple私の玄関口のエンジニアなので、アルゴリズムを公開しません。
要約すると、サービスUUIDをエンコードするオーバーフローエリアは、無線で送信されるバイトの束にすぎません。自分で嗅ぐことができます。特に、それは1つのホットエンコーディングで後で表現される短いハッシュです。複数のビットを設定することにより、複数のUUIDが通信されます。このようにして衝突が発生します。たとえば、UUID 1001のエンコードは3333と同じです。これを自分で確認できます。iPhoneでUUID 1001をバックグラウンドでブロードキャストし、もう1つのスキャンで3333をスキャンします。