扫描特定的CBUUID时,核心蓝牙没有find外设
看来这个问题在这里 “回答”,但是没有任何代码来表明他们做了什么不同的事情,我不得不提出一个新的问题。
我有我自己的代码具有相同的行为,其中在OS X上使用Core Bluetooth的CBCentralManager扫描特定的CBUUID没有发现充当CBPeripheralManager的外围设备的iOS设备(除非它及其服务先前已被发现)。 为了看看我的代码是否有问题,我下载了苹果的示例代码 。 在两台iOS设备上运行示例代码可以按预期运行,但是当将CBCentralManager代码复制到OS X应用程序时,它无法findiOS设备。
我已经上传了OS X应用程序的Xcode项目,它在WikiUpload上托pipe,因为这似乎是最不可思议的 。 如果有人愿意的话,我的主机上也有一个副本 。
下面是OS X项目中的AppDelegate.m代码(CoreBluetooth框架在项目中链接):
#import <CoreBluetooth/CoreBluetooth.h> @interface AppDelegate () <CBCentralManagerDelegate, CBPeripheralDelegate> @property (strong, nonatomic) CBCentralManager *centralManager; @property (strong, nonatomic) CBPeripheral *discoveredPeripheral; @property (strong, nonatomic) NSMutableData *data; @property (weak) IBOutlet NSWindow *window; @end @implementation AppDelegate @synthesize centralManager = _centralManager, discoveredPeripheral = _discoveredPeripheral, data = _data; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application // Start up the CBCentralManager _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; // And somewhere to store the incoming data _data = [[NSMutableData alloc] init]; } - (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application } #pragma mark - Central Methods /** centralManagerDidUpdateState is a required protocol method. * Usually, you'd check for other states to make sure the current device supports LE, is powered on, etc. * In this instance, we're just using it to wait for CBCentralManagerStatePoweredOn, which indicates * the Central is ready to be used. */ - (void)centralManagerDidUpdateState:(CBCentralManager *)central { if (central.state != CBCentralManagerStatePoweredOn) { // In a real app, you'd deal with all the states correctly return; } // The state must be CBCentralManagerStatePoweredOn... // ... so start scanning [self scan]; } /** Scan for peripherals - specifically for our service's 128bit CBUUID */ - (void)scan { // This brings up nothing, unlike on iOS where it finds the device straight away [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }]; // [self.centralManager scanForPeripheralsWithServices:nil // options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES }]; NSLog(@"Scanning started"); } /** This callback comes whenever a peripheral that is advertising the TRANSFER_SERVICE_UUID is discovered. * We check the RSSI, to make sure it's close enough that we're interested in it, and if it is, * we start the connection process */ - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { NSLog(@"Discovered %@ at %@", peripheral.name, RSSI); //Took out RSSI check if (self.discoveredPeripheral != peripheral) { // Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it self.discoveredPeripheral = peripheral; // And connect NSLog(@"Connecting to peripheral %@", peripheral); [self.centralManager connectPeripheral:peripheral options:nil]; } } /** If the connection fails for whatever reason, we need to deal with it. */ - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]); [self cleanup]; } /** We've connected to the peripheral, now we need to discover the services and characteristics to find the 'transfer' characteristic. */ - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { NSLog(@"Peripheral Connected"); // Stop scanning [self.centralManager stopScan]; NSLog(@"Scanning stopped"); // Clear the data that we may already have [self.data setLength:0]; // Make sure we get the discovery callbacks peripheral.delegate = self; // Search only for services that match our UUID [peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]]; } /** The Transfer Service was discovered */ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { if (error) { NSLog(@"Error discovering services: %@", [error localizedDescription]); [self cleanup]; return; } // Discover the characteristic we want... // Loop through the newly filled peripheral.services array, just in case there's more than one. for (CBService *service in peripheral.services) { [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]] forService:service]; } } /** The Transfer characteristic was discovered. * Once this has been found, we want to subscribe to it, which lets the peripheral know we want the data it contains */ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { // Deal with errors (if any) if (error) { NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); [self cleanup]; return; } // Again, we loop through the array, just in case. for (CBCharacteristic *characteristic in service.characteristics) { // And check if it's the right one if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { // If it is, subscribe to it [peripheral setNotifyValue:YES forCharacteristic:characteristic]; } } // Once this is complete, we just need to wait for the data to come in. } /** This callback lets us know more data has arrived via notification on the characteristic */ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if (error) { NSLog(@"Error discovering characteristics: %@", [error localizedDescription]); return; } NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding]; // Have we got everything we need? if ([stringFromData isEqualToString:@"EOM"]) { // We have, so show the data, //[self.textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]]; NSLog(@"Text: %@", [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]); // Cancel our subscription to the characteristic [peripheral setNotifyValue:NO forCharacteristic:characteristic]; // and disconnect from the peripehral [self.centralManager cancelPeripheralConnection:peripheral]; } // Otherwise, just add the data on to what we already have [self.data appendData:characteristic.value]; // Log it NSLog(@"Received: %@", stringFromData); } /** The peripheral letting us know whether our subscribe/unsubscribe happened or not */ - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if (error) { NSLog(@"Error changing notification state: %@", error.localizedDescription); } // Exit if it's not the transfer characteristic if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { return; } // Notification has started if (characteristic.isNotifying) { NSLog(@"Notification began on %@", characteristic); } // Notification has stopped else { // so disconnect from the peripheral NSLog(@"Notification stopped on %@. Disconnecting", characteristic); [self.centralManager cancelPeripheralConnection:peripheral]; } } /** Once the disconnection happens, we need to clean up our local copy of the peripheral */ - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"Peripheral Disconnected"); self.discoveredPeripheral = nil; // We're disconnected, so start scanning again [self scan]; } /** Call this when things either go wrong, or you're done with the connection. * This cancels any subscriptions if there are any, or straight disconnects if not. * (didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved) */ - (void)cleanup { // Don't do anything if we're not connected if (!self.discoveredPeripheral.isConnected) { return; } // See if we are subscribed to a characteristic on the peripheral if (self.discoveredPeripheral.services != nil) { for (CBService *service in self.discoveredPeripheral.services) { if (service.characteristics != nil) { for (CBCharacteristic *characteristic in service.characteristics) { if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID]]) { if (characteristic.isNotifying) { // It is notifying, so unsubscribe [self.discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic]; // And we're done. return; } } } } } } // If we've got this far, we're connected, but we're not subscribed, so we just disconnect [self.centralManager cancelPeripheralConnection:self.discoveredPeripheral]; }
在AppDelegate.h中有UUID定义:
#ifndef LE_Transfer_TransferService_h #define LE_Transfer_TransferService_h #define TRANSFER_SERVICE_UUID @"E20A39F4-73F5-4BC4-A12F-17D1AD07A961" #define TRANSFER_CHARACTERISTIC_UUID @"08590F7E-DB05-467E-8757-72F6FAEB13D4" #endif
这里有什么问题? 根据上面的链接问题,服务必须是广告数据包的一部分,但据我所见,这正是iOS外设正在做的
[self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }];
CoreBluetooth可能非常令人沮丧。 这里有几件事要尝试:
#1:已连接的外围设备停止广告。 如果您成功连接到外设,则需要重新启动广告。
#2:iOScaching发现状态和提供的服务。 没有编程方法来刷新/清除caching。 尝试在iOS设备和Mac上禁用BT,然后重新启用它。 然后尝试另一个连接。
#3:你的UUID有问题。 尝试使用UUID参数设置为nil扫描外围设备。 你应该发现范围内的所有外围设备。
#4:如果Wifi处于打开状态,Mac上的BT连接可能会非常挑剔。 尝试在Mac上禁用Wifi,然后重试。 我已经发现BTLE完全无法启用Wifi,所以我不得不在使用以太网时,在我的MacBook上执行任何BTLE开发。