我在使用 CoreBluetooth 连接到蓝牙 LE 设备时遇到了类似的问题,在我的情况下,我从我的 Mac(中央)连接到 iOS 设备(外围设备)。
如果我理解正确,模式非常一致,当我第一次运行我的 Mac 应用程序进行调试时,它总是检测到并连接到任何蓝牙 LE 设备(外围设备),最重要的是,它还可以很好地发现它们的服务/特性。问题从第二次运行开始(例如,更改一些代码,点击 cmd-R 重新启动调试)。中央仍然检测外围设备并连接到它们,但是它无法发现任何服务/特征。换句话说,委托peripheral:didDiscoverServices:
永远peripheral:didDiscoverCharacteristicsForService:error:
不会被调用。
经过大量试验和错误的解决方案非常简单。似乎 CoreBluetooth 缓存services
和characteristics
仍然连接的外围设备,虽然在本地看起来它已经与应用程序断开连接,但外围设备仍然保持与系统的蓝牙连接。对于这些类型的连接,不需要(重新)发现服务和特性,只需直接从外围对象访问它们,检查nil
是否应该发现它们。此外,如前所述,由于外围设备处于连接之间的状态,因此最好cancelPeripheralConnection:
在尝试连接之前立即调用。它的要点如下,假设我们已经发现了要连接的外围设备:
-(void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
[central cancelPeripheralConnection:peripheral]; //IMPORTANT, to clear off any pending connections
[central connectPeripheral:peripheral options:nil];
}
-(void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
peripheral.delegate = self;
if(peripheral.services)
[self peripheral:peripheral didDiscoverServices:nil]; //already discovered services, DO NOT re-discover. Just pass along the peripheral.
else
[peripheral discoverServices:nil]; //yet to discover, normal path. Discover your services needed
}
-(void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
for(CBService* svc in peripheral.services)
{
if(svc.characteristics)
[self peripheral:peripheral didDiscoverCharacteristicsForService:svc error:nil]; //already discovered characteristic before, DO NOT do it again
else
[peripheral discoverCharacteristics:nil
forService:svc]; //need to discover characteristics
}
}
-(void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
for(CBCharacteristic* c in service.characteristics)
{
//Do some work with the characteristic...
}
}
这对我来说适用于 Mac 应用程序中的 CBCentralManager。从未在 iOS 中测试过,但我认为它应该非常相似。