Incorrect BLE Peripheral Name with iOS

后端 未结 4 510
生来不讨喜
生来不讨喜 2021-01-31 19:19

I am writing an iOS app to communicate with a BLE device. The device can change names between connections (not during the BLE connection), but iOS refuses to change the device n

相关标签:
4条回答
  • 2021-01-31 19:58

    The CBPeripheralDelegate protocol contains a method...

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

    ... which is made for this purpose.

    0 讨论(0)
  • 2021-01-31 20:02

    Edit - just realized that the second part of the accepted answer above has the same solution :-( I should have read more closely. I will leave this answer here anyway, since it includes RoboVM code.

    I have found a solution to this problem. Adding the GATT Service Changed characteristic didn't work, nor did reading the device name directly from the Device Name characteristic 2A00 since iOS hides the Generic Access service. However, if the peripheral includes its local name in an advertising packet, it is available from the advertisement data dictionary provided on a scan result using the retrieval key CBAdvertisementDataLocalNameKey. I copy this into my BLE device wrapper and use it instead of the name available from the CBPeripheral. Example code in Java for RoboVM is below. The OBJC or Swift equivalent is straightforward.

        @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 讨论(0)
  • 2021-01-31 20:06

    The CoreBluetooth API of iOS SDK does not provide a way to force refresh the peripheral name.

    Currently it is not feasible to use peripheral.name in iOS when the device name in the BLEdevice changes.

    Apple suggests to scan for a specific device by specifying a list of CBUUID objects (containing one or more service UUIDs) that you pass to scanForPeripheralsWithServices:

    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];
    

    This reduces the number of calls of didDiscoverPeripheral. Do not just pass nil to scanForPeripheralsWithServices. It also allows your app to scan for a peripheral when in background state.

    If you are looking for a way to broadcast dynamic information that's available before a connection is established, you can use the Advertise or Scan Response Data. The peripheral can be configured to broadcast the entries called Local Name and Manufacturer Specific Data. This data is availabe in the 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]);
    }
    

    Local Name is an NSString, so write only printable characters on the BLE device in this filed. Manufacturer Data is an NSData, this can contain any byte value, so you can even have binary data here.

    Depending on the BLE device you use, the length of Local Name and Manufacturer Specific Data is limited.

    On my BLE device,I can send the 128 Bit service UUID and a 8 char Local Name with the Advertise Data. The Manufacturer Specific Data goes into the Scan Response Data and can be 29 bytes long.

    Good thing about using the Adv./Scan Response Data is, it can change on this BLE device without a power cycle.

    Suggestion:

    1. Use the service UUID to filter when scanning (UUID must be part of advertising data! I omitted it in the above description)
    2. Use the Advertise/Scan Response Data for further filtering
    3. Forget about peripheral.name as long as there is no deterministic refresh available
    0 讨论(0)
  • 2021-01-31 20:09

    Your guessing is correct.
    It is because of the core-blutetooth cache.

    Generally changing name / services / characteristics on BLE devices are "not supported". All these parameters are getting cached.

    There are two ways of solving this:

    • restart bluetooth adapter, so bluetooth cache gets cleared (I'm afraid there is no way to do this programatically, but i might be wrong)
    • your device BLE implements the GATT Service Changed characteristic: read about this here: core_v4.1.zip
      Vol 3, Part G, 2.5.2, and Vol 3, Part G, 7.1.

    Alternatively check the advertisement data of your BLE device. It might have a name property which should get refreshed every time the BLE device is advertising data (advertising data doesn't get cachced).

    0 讨论(0)
提交回复
热议问题