Неправильное имя периферийного устройства BLE с iOS
Я пишу приложение iOS для связи с устройством BLE. Устройство может изменять имена между соединениями (не во время соединения BLE), но iOS отказывается изменять имя устройства.
Например: я могу подключиться к устройству, когда его имя - SadName. Я отключу его, выключите приложение и т.д. И измените имя устройства на HappyName. Но, когда я просматриваю устройства, iOS по-прежнему показывает периферийное имя как SadName.
Если я отлаживаю приложение и смотрю:
(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
значение inner.name - это SadName, поэтому я не думаю, что это то, что я неправильно интерпретирую в коде. Я должен упомянуть, что когда я просматриваю устройства, мой код:
[self.CM scanForPeripheralsWithServices:nil options:0]; // Start scanning
Я предполагаю, что это просто потому, что UUID устройств одинаковы, поэтому iOS вытаскивает его из списка кэшированных устройств, но я хочу переопределить это.
Мысли? Извините, я новичок в iOS.
Приветствия -
MSchmidtbauer
Ответы
Ответ 1
API-интерфейс CoreBluetooth для iOS SDK не дает возможности принудительно обновить периферийное имя.
В настоящее время невозможно использовать имя_файла в iOS при изменении имени устройства в BLEdevice.
Apple предлагает сканировать определенное устройство, указав список объектов CBUUID (содержащий один или несколько идентификаторов UUID), которые вы передаете в 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];
Это уменьшает количество вызовов didDiscoverPeripheral. Не просто передавайте nil на scanForPeripheralsWithServices. Это также позволяет вашему приложению сканировать периферию в фоновом режиме.
Если вы ищете способ передачи динамической информации, доступной до установления соединения, вы можете использовать Реклама или данные ответа сканирования. Периферийное устройство может быть настроено для трансляции записей с именем Локальное имя и Специфические данные производителя. Эти данные доступны в файле 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 в этой папке. Данные производителя NSDatastrong > , это может содержать любое значение байта, поэтому вы можете даже иметь двоичные данные здесь.
В зависимости от используемого устройства BLE длина локального имени и конкретных данных производителя ограничена.
На моем устройстве BLE я могу отправить идентификатор UUID службы 128 бит и 8 char Локальное имя с данными рекламы. Специфические данные производителя входят в данные ответа сканирования и могут составлять 29 байтов.
Хорошо использовать данные Adv./Scan Response, это может быть изменено на этом устройстве BLE без силового цикла.
Предложение:
- Использовать UUID службы для фильтрации при сканировании (UUID должен быть частью рекламных данных! Я опустил его в приведенном выше описании)
- Используйте данные объявления/сканирования для дальнейшей фильтрации
- Забудьте о имени периферии, если нет детерминированного обновления.
Ответ 2
Ваше предположение верно.
Это из-за кеша core-blutetooth
.
В целом изменение имени/услуг/характеристик на устройствах BLE "не поддерживается". Все эти параметры кэшируются.
Существует два способа решения этого вопроса:
- перезагрузите адаптер bluetooth, так что кэш Bluetooth очищается (я боюсь, что нет никакого способа сделать это программно, но я могу ошибаться)
- ваше устройство BLE реализует свойство GATT Service Changed: читайте об этом здесь
Том 3, часть G, 2.5.2 и том 3, часть G, 7.1.
Альтернативно проверяйте рекламные данные вашего устройства BLE. Он может иметь свойство name
, которое должно обновляться каждый раз, когда устройство BLE рекламирует данные (рекламные данные не получают кэширования).
Ответ 3
Протокол CBPeripheralDelegate
содержит метод...
- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral NS_AVAILABLE(NA, 6_0);
..., который сделан для этой цели.
Ответ 4
Edit - просто понял, что вторая часть принятого ответа выше имеет одно и то же решение:-( Я должен был прочитать более внимательно. Я оставлю этот ответ здесь в любом случае, так как он содержит код RoboVM.
Я нашел решение этой проблемы. Добавление измененной характеристики GATT Service не работало и не читало имя устройства непосредственно из атрибута Device Name 2A00, поскольку iOS скрывает службу Generic Access. Однако, если периферийное устройство включает его локальное имя в рекламный пакет, оно доступно из словаря рекламных данных, предоставленного на результат сканирования, используя извлечение key CBAdvertisementDataLocalNameKey
. Я копирую это в свою оболочку устройства BLE и использую его вместо имени, доступного из CBPeripheral. Пример кода в Java для RoboVM приведен ниже. Эквивалент 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);
}
}