Objective-c蓝牙表示已连接,但CBCentralManager未发现它

问题描述:

在我的应用程序中,我首先使用代理方法retrieveConnectedPeripheralsWithServices搜索以前连接的设备,然后在没有发现任何内容的情况下扫描附近的设备。下面是代码Objective-c蓝牙表示已连接,但CBCentralManager未发现它

- (void)searchForPeripherals { 
    NSLog(@"*** scanning for Bluetooth peripherals... ***"); 

    //Check to see if any devices were connected already 
    if(self.ourPeripheral != nil) { 
     [self connectToDevice]; 

    } else { 
     //Search for previously paired devices... 
     bool foundPairedDevices = [self checkForAndConnectToPreviouslyPairedDevices]; 

     //None found, scan for new devices nearby... 
     if(!foundPairedDevices) { 
      NSLog(@"No paired boxes found, checking device powered state..."); 

      //If the app user has "bluetooth" option turned on 
      if(self.centralManager.state == CBCentralManagerStatePoweredOn) { 
       NSLog(@"--- central manager powered on."); 
       NSLog(@"...begin scanning..."); 

       [self.centralManager scanForPeripheralsWithServices:nil 
                  options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @(YES)}]; 

      //No, user has "bluetooth" turned off 
      } else { 
       NSLog(@"--- central manager is NOT powered on."); 
      } 
     } 
    } 
} 


- (bool)checkForAndConnectToPreviouslyPairedDevices { 
    NSLog(@"our peripheral device: %@", self.ourPeripheral); 

    NSArray *dcBoxesFound = [self.centralManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]]; 
    NSLog(@"Previously paired DC boxes?: %@", dcBoxesFound); 

    //Are there any previously paired devices? 
    if(dcBoxesFound != nil && [dcBoxesFound count] > 0) { 
     CBPeripheral *newestBoxFound = [dcBoxesFound firstObject]; 
     newestBoxFound.delegate = self; 

     self.ourPeripheral = newestBoxFound; 
     self.deviceUUID = [CBUUID UUIDWithString:[newestBoxFound.identifier UUIDString]]; 

     [self connectToDevice]; 

     return YES; 

    } else { 
     return NO; 
    } 
} 


- (void)connectToDevice { 
    if(self.ourPeripheral != nil) { 
     [self.centralManager connectPeripheral:self.ourPeripheral options:nil]; 
    } 
} 


- (void)centralManager:(CBCentralManager *)central 
didDiscoverPeripheral:(CBPeripheral *)peripheral 
    advertisementData:(NSDictionary *)advertisementData 
        RSSI:(NSNumber *)RSSI { 

    NSLog(@"scanned and found this peripheral: %@", peripheral); 
    NSLog(@"advertisment data: %@", advertisementData); 

    if(!self.isConnectedToDevice && [[advertisementData objectForKey:@"kCBAdvDataLocalName"] localizedCaseInsensitiveContainsString:@"dc-"]) { 
     NSLog(@"\n"); 
     NSLog(@"-------------------------------------------"); 
     NSLog(@"DC peripheral found! Attempting to connect to the following...: %@", peripheral); 

     peripheral.delegate = self; 
     self.ourPeripheral = peripheral; 

     self.deviceUUID = [CBUUID UUIDWithString:[peripheral.identifier UUIDString]]; 

     [self connectToDevice]; 

     NSLog(@"-------------------------------------------"); 
     NSLog(@"\n"); 
    } 
} 


- (void)centralManager:(CBCentralManager *)central 
    didConnectPeripheral:(CBPeripheral *)peripheral { 
    NSLog(@"--- didConnectPeripheral"); 

    peripheral.delegate = self; 
    [peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]]; 
} 

的问题

当我启动它通常连接就好了应用。一切都很好。然后在非常难以预测的奇怪时间,BT连接以某种方式“卡住”。我坚持的意思是它永远不会真正连接。我的盒子上的蓝色光线就像系统已连接到它一样,但在我的应用程序中,这发生了什么。

1)retrieveConnectedPeripheralsWithServices方法找到一个空的先前连接的设备阵列,告诉调用它的方法,没有找到以前连接的设备。

2)scanForPeripheralsWithServices:nil方法被触发,并开始使用didDiscoverPeripheral方法进行扫描。

3)didDiscoverPeripheral甚至从来没有一次发现任何箱附近与其他

“DC-”的东西或kCBAdvDataLocalName前缀如果我进入iOS的设置 - >蓝牙 - >忘了这个设备(有打它两次,这让我觉得它“卡住”不知何故),然后实际上一起关闭BT选项......等待2秒钟,然后再打开它......然后重新启动应用程序,这一切加载正常。

1)应用程序启动

2)见的没有以前连接的设备

3)扫描计算机的外围设备,并发现我的前缀盒名为 “DC-什么”

4)问我配对BT设备,然后我有全部功能回

如果我然后关闭应用程序,并重新启动它,retrieveConnectedPeripheralsWithServices找到我以前连接的盒子没有问题,并无缝连接...

那么...这里发生了什么?为什么它似乎有时会被“卡住”?

编辑:

我也知道配对和连接是不一样的事情,所以一些方法被命名为真的很差。

这是蓝牙LE编程的一个常见问题,由于所有API都是异步的,所以变得更加困难。

典型的解决方案是在没有完成的情况下让代码重试。因为你不一定会得到错误信息(你可能不会得到下一个回调),你最终不得不做的是设置定时器在合理的时间段后开始重试 - 比如说5-10秒。

正如你已经注意到的,在某些情况下(如在后台,如果设备连接,或以其他方式停止广告),你只会得到一个回调didDiscoverPeripheral。因此,您真的需要保存CBPeripheral对象的副本,以便在超时发生时可以重新使用它。这里是基本的逻辑,我会用:

  1. 当你发现在didDiscoverPeripheral一个新的外设,保存对象实例在一个名为peripheralForConnectionAttempt变量,然后启动5秒计时器。
  2. 如果连接在didConnectPeripheral中成功完成,请将值peripheralForConnectionAttempt设置为零。
  3. 定时器关闭时,检查peripheralForConnectionAttempt是否为零,如果是,则重试此对象,就好像调用了didDiscoverPeripheral一样。您可能需要一个柜台来将重试次数限制为10次或类似的次数。

侧面说明:

当你说蓝光卡上,这可能意味着BLE外围设备认为它已经建立了一个BLE连接。这样做的外围设备通常会停止广告,直到连接断开。如果iOS设备认为它未连接并且外围设备确实存在,则会导致您处于不良情况,因此您必须以某种方式中断连接。不幸的是,CoreLocation没有给你这样的API。

在一个项目中,我通过在蓝牙外围设备固件中发生通信超时而断开连接来完成此操作。但是如果你不控制固件,你显然不能这样做。

将电源连接到蓝牙将打破任何活动连接,如您所见。但在iOS上,您无法以编程方式执行此操作。

如果您不控制外设固件,并且无法想出任何方法来避免锁定与设备的连接(可能通过更改您的操作的时间?),那么您可能没有办法只是简单地检测这个问题,在适当的时候提醒用户,并且在用例允许的情况下指导用户循环使用蓝牙。我知道这不是一个理想的解决方案。

+0

真棒非常感谢你。我拥有该设备,并且有能力更改固件,因此我应该在盒子中更改哪些内容?我还不是很确定,因为我对草图和微控制器非常陌生,如何检查您提到的超时。 – GoreDefex

+0

这一切都取决于你的设备如何工作。如果它在〜5秒内没有得到任何通信,我会断开它。这可能是在连接之后,或者总是根据您的使用情况而定。 – davidgyoung