2017-07-19 98 views
1

在我的應用程序中,我首先使用代理方法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找到我以前連接的盒子沒有問題,並無縫連接...

那麼...這裏發生了什麼?爲什麼它似乎有時會被「卡住」?

編輯:

我也知道配對和連接是不一樣的事情,所以一些方法被命名爲真的很差。

回答

1

這是藍牙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