Core Bluetooth no encuentra periféricos al escanear CBUUID específico

Parece que esta pregunta fue "contestada" aquí , pero sin ningún código para mostrar lo que hicieron de otra manera, tengo que hacer una nueva pregunta.

Tengo mi propio código con el mismo comportamiento, en el que el escaneo de CBUUID específicos utilizando CBCentralManager de Core Bluetooth en OS X no descubre un dispositivo iOS que actúe como un periférico con CBPeripheralManager (a less que se hayan descubierto previamente sus services). Para ver si hay algún problema en mi código, descargué el código de ejemplo de Apple . Ejecutar el código de muestra en dos dispositivos iOS funciona según lo previsto, sin embargo, al copyr el código CBCentralManager a una aplicación OS X, no puede encontrar el dispositivo iOS.

Cargué un proyecto Xcode para la aplicación OS X, está alojado en WikiUpload, ya que parece ser el less dudoso. También hay una copy en mi alojamiento , si la gente lo prefiere.

Aquí está el código AppDelegate.m en el proyecto OS X también (el marco CoreBluetooth está vinculado en el proyecto):

#import <CoreBluetooth/CoreBluetooth.h> @interface AppDelegate () <CBCentralManagerDelegate, CBPeripheralDelegate> @property (strong, nonatomic) CBCentralManager *centralManager; @property (strong, nonatomic) CBPeripheral *discovenetworkingPeripheral; @property (strong, nonatomic) NSMutableData *data; @property (weak) IBOutlet NSWindow *window; @end @implementation AppDelegate @synthesize centralManager = _centralManager, discovenetworkingPeripheral = _discovenetworkingPeripheral, 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 requinetworking protocol method. * Usually, you'd check for other states to make sure the current device supports LE, is powenetworking on, etc. * In this instance, we're just using it to wait for CBCentralManagerStatePowenetworkingOn, which indicates * the Central is ready to be used. */ - (void)centralManagerDidUpdateState:(CBCentralManager *)central { if (central.state != CBCentralManagerStatePowenetworkingOn) { // In a real app, you'd deal with all the states correctly return; } // The state must be CBCentralManagerStatePowenetworkingOn... // ... 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 discovenetworking. * 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(@"Discovenetworking %@ at %@", peripheral.name, RSSI); //Took out RSSI check if (self.discovenetworkingPeripheral != peripheral) { // Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it self.discovenetworkingPeripheral = 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 discovenetworking */ - (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 discovenetworking. * 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.discovenetworkingPeripheral = 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.discovenetworkingPeripheral.isConnected) { return; } // See if we are subscribed to a characteristic on the peripheral if (self.discovenetworkingPeripheral.services != nil) { for (CBService *service in self.discovenetworkingPeripheral.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.discovenetworkingPeripheral 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.discovenetworkingPeripheral]; } 

Y en AppDelegate.h están las definiciones de 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 

¿Cuál es el problema aquí? De acuerdo con la pregunta vinculada anterior, el service debe ser parte del package publicitario, pero por lo que veo, eso es exactamente lo que hace el periférico iOS con

 [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }]; 

CoreBluetooth puede ser muy frustrante. Aquí hay un par de cosas para probar:

# 1: un periférico que se ha conectado a las paradas de publicidad. Si realiza una connection exitosa con el periférico, deberá reiniciar la publicidad.

# 2: cachings de iOS descubrieron el estado y brindaron services. No hay una forma programática de actualizar / borrar el caching. Intenta desactivar BT en el dispositivo iOS y en la Mac y volver a habilitarlo. Luego intente otra connection.

# 3: hay un problema con sus UUID. Intente escanear los periféricos con el parámetro UUID establecido en nil. Luego, debe descubrir todos los periféricos en el range.

# 4: La connection BT en una Mac puede ser fastidiosa si la connection Wi-Fi está activada. Intenta desactivar Wi-Fi en tu Mac y vuelve a intentarlo. He encontrado BTLE completamente inutilizable con Wi-Fi habilitado, así que he tenido que usar ethernet al hacer cualquier dispositivo BTLE en mi MacBook.