首页 文章

iOS的BLE外设名称不正确

提问于
浏览
14

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

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

如果我调试应用程序并查看:

(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从它的缓存设备列表中提取它,但我想覆盖它 .

思考?对不起,我是iOS新手 . 干杯 - MSchmidtbauer

4 回答

  • 0

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

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

    Apple建议通过指定传递给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];
    

    这减少了didDiscoverPeripheral的调用次数 . 不要只将nil传递给scanForPeripheralsWithServices . 它还允许您的应用在处于后台状态时扫描外围设备 .

    如果您正在寻找在 Build 连接之前广播可用信息的方法,则可以使用 Advertise or Scan Response Data . 外设可以配置为广播名为 Local NameManufacturer Specific Data 的条目 . 这些数据在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 ,因此在此字段中仅在BLE设备上写入可打印字符 . Manufacturer Data is an NSData ,这可以包含任何字节值,因此您甚至可以在此处获得二进制数据 .

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

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

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

    建议:

    • 扫描时使用服务UUID进行过滤(UUID必须是广告数据的一部分!我在上面的描述中省略了它)

    • 使用播发/扫描响应数据进行进一步过滤

    • 只要没有确定性刷新可用,就忘记了peripheral.name

  • 0

    你的猜测是正确的 .
    这是因为 core-blutetooth cache .

    通常,“不支持”更改BLE设备上的名称/服务/特性 . 所有这些参数都被缓存了 .

    有两种方法可以解决这个问题:

    • 重新启动蓝牙适配器,因此蓝牙缓存被清除(我担心没有办法以编程方式执行此操作,但我可能错了)

    • 您的设备BLE实施GATT服务变更特征:了解此here
      第3卷,第G部分, 2.5.2 和第3卷,第G部分, 7.1 .

    或者,检查BLE设备的广告数据 . 它可能具有 name 属性,每次BLE设备广告数据时都应该刷新(广告数据不会被缓存) .

  • 5

    CBPeripheralDelegate 协议包含一个方法......

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

    ......为此目的而制作的 .

  • 22

    编辑 - 刚才意识到上面接受的答案的第二部分有相同的解决方案:-(我应该仔细阅读 . 无论如何我会在这里留下这个答案,因为它包含RoboVM代码 .

    我找到了解决这个问题的方法 . 添加GATT服务更改的特性不起作用,也没有直接从设备名称特征2A00读取设备名称,因为iOS隐藏了通用访问服务 . 但是,如果外围设备在广告包中包含其本地名称,则可以使用检索密钥CBAdvertisementDataLocalNameKeyscan result上提供的广告数据字典中获取 . 我将其复制到我的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);
            }
        }
    

相关问题