CBPeripheral advertisementData 在 OSX 与 iOS 上发现外围设备时不同 (GAP/GATT)
CBPeripheral advertisementData is different when discovering peripherals on OSX vs iOS (GAP/GATT)
我希望将我的一些 CoreBluetooth 代码从 iOS 移植到 OS X。我已经设置了一组共享的 CoreBluetooth 包装器,iOS 应用程序和 OS X 应用程序以完全相同的方式使用相同的 BLE 设备。
正在扫描外围设备:
override init() {
super.init()
let queue = DispatchQueue.global(qos: .background)
centralManager = CBCentralManager(delegate: self, queue: queue)
}
func startScanning() {
let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: true]
let deviceUUID = CBUUID(string: Project.Service.Device)
let recoveryUUID = CBUUID(string: Project.Service.DFURecovery)
centralManager?.scanForPeripherals(withServices: [deviceUUID, recoveryUUID], options: options)
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
// Inspect advertisementData here to decipher what kind of device
}
在我的 iOS 应用程序上,didDiscoverPeripheral 被触发。然后,当我检查广告数据时,我得到了我期望的所有 keys/values:
{
kCBAdvDataIsConnectable = 1;
kCBAdvDataLocalName = "My Device";
kCBAdvDataManufacturerData = <34045254 5877f283 43fdd12d ff530978 45000000 000050c2 6500>;
kCBAdvDataServiceData = {
Battery = <64>;
};
kCBAdvDataServiceUUIDs = (
"My Inforamtion"
);
}
然而,当来自 OS X 应用程序的相同代码 运行(扫描相同设备)时,广告数据缺少某些字段。
{
kCBAdvDataIsConnectable = 1;
kCBAdvDataManufacturerData = <34045254 5877f36e 43fdd12d ff530978 45000000 000050c2 6500>;
}
广告数据中缺少以下 key/value 对。
kCBAdvDataLocalName
kCBAdvDataServiceData
kCBAdvDataServiceUUIDs
我试过像这样将这些键添加到 scanForPeripherals 调用中:
let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: true,
CBAdvertisementDataLocalNameKey: true,
CBAdvertisementDataServiceDataKey: true,
CBAdvertisementDataServiceUUIDsKey: true]
let deviceUUID = CBUUID(string: Nightlight.Service.Device)
let recoveryUUID = CBUUID(string: Nightlight.Service.DFURecovery)
centralManager?.scanForPeripherals(withServices: [deviceUUID, recoveryUUID], options: options)
没有效果。
OSX 每个设备可能会多次调用 didDiscoverPeripheral,每次调用都有不同的广告数据。我想到的解决办法是写一个缓存。
import Foundation
import CoreBluetooth
class AdvertisementDataCache {
/// A dictionary of advertised data to peripheral.uuid
private var cache: [UUID: [String: Any]] = [:]
/// Appends advertisementData to our cache
/// for each unique `peripheral.uuid`.
func append(
advertisementData: [String: Any],
to peripheral: CBPeripheral
) -> [String: Any] {
// Join our cached adverts (our `cache` ivar)
// with new adverts (`advertisementData`)
let joined = advertisementData.reduce(
cache[peripheral.identifier] ?? [:]
) {
var all = [=10=]
all[.key] = .value
return all
}
// write back to our private iVar
cache[peripheral.identifier] = joined
// Return all cached averts for this peripheral
return joined
}
/// Purges all cached avertisements for all peripherals
func clear() {
cache.removeAll()
}
}
然后在 didDiscoverPeripheral:
private var advertisementDataCache = AdvertisementDataCache()
public func centralManager(
_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData adPart: [String: Any],
rssi RSSI: NSNumber
) {
let advertisementData = advertisementDataCache.append(
advertisementData: adPart,
to: peripheral
)
// advertisementData now contains all data contained in multiple callbacks
}
更新。我正在使用 UIKitForMac Beta 2(现在称为 Catalyst)并且遇到了同样的问题。上面列出的解决方案(caching/aggregating 广告数据)也适用于这种情况。
我希望将我的一些 CoreBluetooth 代码从 iOS 移植到 OS X。我已经设置了一组共享的 CoreBluetooth 包装器,iOS 应用程序和 OS X 应用程序以完全相同的方式使用相同的 BLE 设备。
正在扫描外围设备:
override init() {
super.init()
let queue = DispatchQueue.global(qos: .background)
centralManager = CBCentralManager(delegate: self, queue: queue)
}
func startScanning() {
let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: true]
let deviceUUID = CBUUID(string: Project.Service.Device)
let recoveryUUID = CBUUID(string: Project.Service.DFURecovery)
centralManager?.scanForPeripherals(withServices: [deviceUUID, recoveryUUID], options: options)
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
// Inspect advertisementData here to decipher what kind of device
}
在我的 iOS 应用程序上,didDiscoverPeripheral 被触发。然后,当我检查广告数据时,我得到了我期望的所有 keys/values:
{
kCBAdvDataIsConnectable = 1;
kCBAdvDataLocalName = "My Device";
kCBAdvDataManufacturerData = <34045254 5877f283 43fdd12d ff530978 45000000 000050c2 6500>;
kCBAdvDataServiceData = {
Battery = <64>;
};
kCBAdvDataServiceUUIDs = (
"My Inforamtion"
);
}
然而,当来自 OS X 应用程序的相同代码 运行(扫描相同设备)时,广告数据缺少某些字段。
{
kCBAdvDataIsConnectable = 1;
kCBAdvDataManufacturerData = <34045254 5877f36e 43fdd12d ff530978 45000000 000050c2 6500>;
}
广告数据中缺少以下 key/value 对。
kCBAdvDataLocalName
kCBAdvDataServiceData
kCBAdvDataServiceUUIDs
我试过像这样将这些键添加到 scanForPeripherals 调用中:
let options: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: true,
CBAdvertisementDataLocalNameKey: true,
CBAdvertisementDataServiceDataKey: true,
CBAdvertisementDataServiceUUIDsKey: true]
let deviceUUID = CBUUID(string: Nightlight.Service.Device)
let recoveryUUID = CBUUID(string: Nightlight.Service.DFURecovery)
centralManager?.scanForPeripherals(withServices: [deviceUUID, recoveryUUID], options: options)
没有效果。
OSX 每个设备可能会多次调用 didDiscoverPeripheral,每次调用都有不同的广告数据。我想到的解决办法是写一个缓存。
import Foundation
import CoreBluetooth
class AdvertisementDataCache {
/// A dictionary of advertised data to peripheral.uuid
private var cache: [UUID: [String: Any]] = [:]
/// Appends advertisementData to our cache
/// for each unique `peripheral.uuid`.
func append(
advertisementData: [String: Any],
to peripheral: CBPeripheral
) -> [String: Any] {
// Join our cached adverts (our `cache` ivar)
// with new adverts (`advertisementData`)
let joined = advertisementData.reduce(
cache[peripheral.identifier] ?? [:]
) {
var all = [=10=]
all[.key] = .value
return all
}
// write back to our private iVar
cache[peripheral.identifier] = joined
// Return all cached averts for this peripheral
return joined
}
/// Purges all cached avertisements for all peripherals
func clear() {
cache.removeAll()
}
}
然后在 didDiscoverPeripheral:
private var advertisementDataCache = AdvertisementDataCache()
public func centralManager(
_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData adPart: [String: Any],
rssi RSSI: NSNumber
) {
let advertisementData = advertisementDataCache.append(
advertisementData: adPart,
to: peripheral
)
// advertisementData now contains all data contained in multiple callbacks
}
更新。我正在使用 UIKitForMac Beta 2(现在称为 Catalyst)并且遇到了同样的问题。上面列出的解决方案(caching/aggregating 广告数据)也适用于这种情况。