web-dev-qa-db-ja.com

iOSでのBLEペリフェラル名が正しくありません

BLEデバイスと通信するためのiOSアプリを書いています。デバイスは接続間で名前を変更できますが(BLE接続中ではありません)、iOSはデバイス名の変更を拒否します。

例:名前がSadNameの場合、デバイスに接続できます。切断したり、アプリをシャットダウンしたりして、デバイスの名前をHappyNameに変更します。しかし、デバイスをスキャンすると、iOSは依然として周辺機器名をSadNameとして表示します。

アプリをデバッグして見てみると:

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

周辺機器名の値はSadNameなので、コードで誤って解釈しているものではないと思います。デバイスをスキャンするときのコードは次のとおりです。

[self.CM scanForPeripheralsWithServices:nil options:0]; // Start scanning 

デバイスのUUIDが同じであるため、iOSがキャッシュされたデバイスのリストからプルしているからだと思いますが、それをオーバーライドしたいと思います。

考え?申し訳ありませんが、iOSは初めてです。乾杯-MSchmidtbauer

16
MSchmidtbauer

IOSSDKのCoreBluetoothAPIは、ペリフェラル名を強制的に更新する方法を提供していません。

現在、BLEdeviceのデバイス名が変更されたときにiOSでperipheral.nameを使用することはできません。

Appleは、scanForPeripheralsWithServicesに渡すCBUUIDオブジェクト(1つ以上のサービスUUIDを含む)のリストを指定して、特定のデバイスをスキャンすることをお勧めします。

NSArray *services = @[[CBUUID UUIDWithString: @"2456e1b9-26e2-8f83-e744-f34f01e9d701"] ]; // change to your service UUID!
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:1] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];

[self.manager scanForPeripheralsWithServices:services options:dictionary];

これにより、didDiscoverPeripheralの呼び出し回数が減ります。 scanForPeripheralsWithServicesにnilを渡すだけではいけません。また、バックグラウンド状態のときにアプリが周辺機器をスキャンできるようにします。

接続が確立される前に利用可能な動的情報をブロードキャストする方法を探している場合は、応答データのアドバタイズまたはスキャンを使用できます。周辺機器は、ローカル名およびメーカー固有のデータというエントリをブロードキャストするように構成できます。このデータは、didDiscoverPeripheralで利用できます。

- (void)centralManager:         (CBCentralManager *)central
 didDiscoverPeripheral:  (CBPeripheral *)peripheral
     advertisementData:      (NSDictionary *)advertisementData
                  RSSI:         (NSNumber *)RSSI {
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
NSData *manufacturerData = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey];
NSLog(@"Local: name: %@", localName); 
NSLog(@"Manufact. Data: %@", [manufacturerData description]);
}

ローカル名はNSStringなので、このフィールドのBLEデバイスには印刷可能な文字のみを書き込んでください。 Manufacturer DataはNSDataです、これには任意のバイト値を含めることができるため、ここにバイナリデータを含めることもできます。

使用するBLEデバイスによっては、ローカル名とメーカー固有のデータの長さが制限されます。

BLEデバイスでは、アドバタイズデータとともに128ビットサービスUUIDと8文字のローカル名を送信できます。製造元固有のデータはスキャン応答データに入り、29バイトの長さにすることができます。

Adv./Scan Response Dataを使用することの良い点は、電源を入れ直さなくてもこのBLEデバイスで変更できることです。

提案:

  1. サービスUUIDを使用して、スキャン時にフィルタリングします(UUIDは広告データの一部である必要があります!上記の説明では省略しました)
  2. さらにフィルタリングするには、アドバタイズ/スキャン応答データを使用します
  3. 決定論的な更新が利用できない限り、peripheral.nameを忘れてください
24
Abrow

あなたの推測は正しいです。
それはcore-blutetoothキャッシュ

通常、BLEデバイスでの名前/サービス/特性の変更は「サポートされていません」。これらのパラメータはすべてキャッシュされています。

これを解決するには2つの方法があります。

  • bluetoothアダプターを再起動すると、Bluetoothキャッシュがクリアされます(プログラムでこれを行う方法はないのではないかと思いますが、間違っている可能性があります)
  • お使いのデバイスBLEはGATTサービス変更特性を実装しています:これについて読む ここ
    第3巻、パートG、2.5.2、および第3巻、パートG、7.1

または、BLEデバイスのアドバタイズデータを確認してください。 BLEデバイスがデータをアドバタイズするたびに更新される必要があるnameプロパティがある場合があります(アドバタイズデータはキャッシュされません)。

6
benka

編集-上記の受け入れられた回答の2番目の部分にも同じ解決策があることに気づきました: もっと詳しく読む必要がありました。RoboVMコードが含まれているので、とにかくこの回答をここに残しておきます。

私はこの問題の解決策を見つけました。 iOSがGenericAccessサービスを非表示にしているため、GATT Service Changed特性の追加は機能せず、デバイス名特性2A00からデバイス名を直接読み取ることもできませんでした。ただし、ペリフェラルのローカル名がアドバタイジングパケットに含まれている場合は、---(スキャン結果 で提供されるアドバタイズメントデータディクショナリから取得キーを使用して入手できます CBAdvertisementDataLocalNameKey =。これをBLEデバイスラッパーにコピーし、CBPeripheralから入手できる名前の代わりに使用します。 RoboVMのJavaのサンプルコードを以下に示します。 OBJCまたはSwiftに相当するものは簡単です。

    @Override
    public void didDiscoverPeripheral(CBCentralManager cbCentralManager, CBPeripheral cbPeripheral, CBAdvertisementData cbAdvertisementData, NSNumber rssi) {
        NSData manufacturerData = cbAdvertisementData.getManufacturerData();
        byte[] data = null;
        if(manufacturerData != null)
            data = manufacturerData.getBytes();
        IosBleDevice bleDevice = new IosBleDevice(cbPeripheral);
        String name = cbAdvertisementData.getLocalName();
        if(name != null && !name.equals(cbPeripheral.getName())) {
            CJLog.logMsg("Set local name to %s (was %s)", name, cbPeripheral.getName());
            bleDevice.setName(name);
        }
        deviceList.put(bleDevice.getAddress(), bleDevice);
        if(!iosBlueMaxService.getSubscriber().isDisposed()) {
            BleScanResult bleScanResult = new IosBleScanResult(bleDevice,
                cbAdvertisementData.isConnectable(),
                data);
            bleScanResult.setRssi(rssi.intValue());
            iosBlueMaxService.getSubscriber().onNext(bleScanResult);
        }
    }
0
Clyde

CBPeripheralDelegateプロトコルにはメソッドが含まれています...

- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral NS_AVAILABLE(NA, 6_0);

...これはこの目的のために作られています。

0
Nikolai Ruhe