簡體   English   中英

iOS 中的 BLE 外設名稱不正確

[英]Incorrect BLE Peripheral Name with iOS

我正在編寫一個 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

iOS SDK 的 CoreBluetooth API 沒有提供強制刷新外設名稱的方法。

當前在 BLEdevice 中的設備名稱更改時,在 iOS 中使用peripheral.name 是不可行的。

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。 它還允許您的應用程序在處於后台狀態時掃描外圍設備。

如果您正在尋找一種在建立連接之前廣播可用動態信息的方法,您可以使用Advertise 或 Scan Response 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]);
}

本地名稱是一個 NSString ,因此在此字段中僅在 BLE 設備上寫入可打印字符。 制造商數據是一個 NSData ,它可以包含任何字節值,所以你甚至可以在這里擁有二進制數據。

根據您使用的 BLE 設備,本地名稱和制造商特定數據的長度是有限的。

在我的 BLE 設備上,我可以發送 128 位服務 UUID 和一個 8 字符的本地名稱以及廣告數據。 制造商特定數據進入掃描響應數據並且可以是 29 字節長。

使用 Adv./Scan Response Data 的好處是,它可以在此 BLE 設備上更改而無需重啟。

建議:

  1. 掃描時使用服務UUID進行過濾(UUID必須是廣告數據的一部分!我在上面的描述中省略了)
  2. 使用廣告/掃描響應數據進行進一步過濾
  3. 只要沒有可用的確定性刷新,就忘掉peripheral.name

你的猜測是正確的。
這是因為core-blutetooth緩存

通常“不支持”更改 BLE 設備上的名稱/服務/特性。 所有這些參數都被緩存。

有兩種方法可以解決這個問題:

  • 重新啟動藍牙適配器,以便清除藍牙緩存(恐怕無法以編程方式執行此操作,但我可能錯了)
  • 您的設備 BLE 實現了 GATT Service Changed 特性:在此處閱讀相關信息: core_v4.1.zip
    第 3 卷,G 部分, 2.5.2和第 3 卷,G 部分, 7.1

或者檢查您的 BLE 設備的廣告數據。 它可能有一個name屬性,每次 BLE 設備廣告數據時都應該刷新該屬性(廣告數據不會被緩存)。

CBPeripheralDelegate協議包含一個方法...

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

...這是為此目的而制作的。

編輯 - 剛剛意識到上面接受的答案的第二部分具有相同的解決方案:-(我應該更仔細地閱讀。無論如何我都會把這個答案留在這里,因為它包含了 RoboVM 代碼。

我找到了解決這個問題的方法。 添加 GATT 服務更改特性不起作用,直接從設備名稱特性 2A00 讀取設備名稱也不起作用,因為 iOS 隱藏了通用訪問服務。 但是,如果外圍設備在廣告數據包中包含其本地名稱,則可以使用檢索鍵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);
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM