不正确的BLE外围设备名称与iOS

我正在编写一个iOS应用程序来与BLE设备进行通信。 设备可以在连接之间更改名称(不在BLE连接期间),但iOS拒绝更改设备名称。

例如:当它的名字是SadName时,我可以连接到设备。 我断开它,closures应用程序等,并将设备的名称更改为HappyName。 但是,当我扫描设备的iOS仍显示为SadName的外设名称。

如果我debugging应用程序,并看看:

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

peripheral.name的值是SadName,所以我不认为这是我在代码中解释不正确的东西。 我应该提到,当我扫描设备时,我的代码是:

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

我猜测,这只是因为设备UUID是相同的,所以iOS是从它的caching设备列表拉,但我想重写。

思考? 对不起,我是iOS新手。 干杯 – MSchmidtbauer

iOS SDK的CoreBluetooth API不提供强制刷新外设名称的方法。

目前,当BLE设备中的设备名称改变时,在iOS中使用peripheral.name是不可行的。

Applebuild议通过指定传递给scanForPeripheralsWithServices的CBUUID对象(包含一个或多个服务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]; 

这减less了didDiscoverPeripheral的调用次数。 不要只传递给scanForPeripheralsWithServices的nil。 它也允许您的应用在后台状态下扫描外设。

如果您正在寻找在连接build立之前广播可用的dynamic信息的方法,则可以使用“发布” 或“扫描响应数据” 。 可以将外设configuration为广播名为“ 本地名称”和“ 制造商特定数据”的条目。 这些数据可以在didDiscoverPeripheral中find:

 - (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设备上的可打印字符。 制造商数据是一个NSData ,它可以包含任何字节值,所以你甚至可以在这里有二进制数据。

根据您使用的BLE设备,本地名称和制造商特定数据的长度是有限的。

在我的BLE设备上,我可以发送128位服务UUID和一个8位本地名称与广告数据。 制造商特定数据进入扫描响应数据,可以有29个字节长。

使用Adv./Scan响应数据的好处在于,它可以在没有电源周期的情况下在此BLE设备上进行更改。

build议:

  1. 扫描时使用服务UUID进行过滤(UUID必须是广告数据的一部分!我在上面的描述中省略了它)
  2. 使用广告/扫描响应数据进一步筛选
  3. 只要没有可用的确定性刷新,就忘记peripheral.name

你的猜测是正确的。
这是因为core-blutetooth caching

一般来说,更改BLE设备上的名称/服务/特性是“不被支持的”。 所有这些参数都被caching。

有两种解决方法:

  • 重新启动蓝牙适配器,所以蓝牙caching被清除(恐怕没有办法做到这一点编程,但我可能是错的)
  • 您的设备BLE实现了GATT Service Changed特性:请在此处阅读此处
    第3卷,G部分, 2.5.2和第3卷,G部分7.1

或者检查BLE设备的广告数据。 它可能有一个name属性,每当BLE设备正在广告数据(广告数据不会被caching)时,该属性应该被刷新。

CBPeripheralDelegate协议包含一个方法…

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

为此而制作的…

编辑 – 只是意识到上面接受的答案的第二部分有相同的解决scheme:-(我应该仔细阅读,我将留下这个答案,因为它包括RoboVM代码。

我find了解决这个问题的办法。 由于iOS隐藏通用访问服务,因此添加GATT服务更改特征不起作用,也不直接从设备名称特征2A00读取设备名称。 但是,如果外围设备在广告数据包中包含其本地名称,则可以使用检索关键字CBAdvertisementDataLocalNameKey从扫描结果上提供的广告数据字典中获得该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); } }