0

EDIT: Following @RobertVaessen comment I implemented the following, however I am still unable to discover the services of the connected peripheral.

-(void) centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *,id> *)dict{

    id tmpObj = [dict objectForKey:CBCentralManagerRestoredStatePeripheralsKey];

    NSArray * keys = [dict allKeys];
    NSString * message = @"";
    for (int i=0; i<[keys count]; i++) {
        NSString * stringTmp = keys[i];
        message = [message stringByAppendingString:@";"];
        message = [message stringByAppendingString:stringTmp];
    }

    // message contains "kCBRestoredScanServices and kCBRestoredPeripherals

    if ([tmpObj isKindOfClass:[NSArray class]]) {
        NSArray * peripheralsArray = (NSArray*)tmpObj;

        for (int i=0; i<[peripheralsArray count]; i++) {
            id objTmp = peripheralsArray[i];
            if ([objTmp isKindOfClass:[CBPeripheral class]]) {
                CBPeripheral * tmpPeripheral = (CBPeripheral*)objTmp;
                 tmpPeripheral.delegate = self;
                [tmpPeripheral discoverServices: self.bleServices];
                // It would reach this part of the code but not discover any services
            }
        }
     }
}

Now the doubt is:

I had already discovered services when the app was in foreground and first connected to the peripheral, does this mean that once the app is woken app again the CBCentralManager will be unable to discover the services?


Theoretical context:

Bluetooth LE state preservation process is described here (see section "Adding Support for State Preservation and Restoration"):

https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html

What I am trying to do:

I am implementing an app that uses BLE State preservation to maintain the connection with a hardware accessory (whilst running in background).

The issue I got is that whenever iOS wakes up my app following a BLE state preservation event my CBCentralManager is unable to discover the services. Weirdly the hardware peripheral "sees" the connection but the iOS app is unable to access it.

In other words: The following methods in the class implementing the CBCentralManager delegate gets called correctly but does not do much (see comments in green below):

-(void) centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary<NSString *,id> *)dict{  
    NSArray * peripherals = [self.central retrieveConnectedPeripheralsWithServices:self.bleServices];  

    for (int i=0; i < peripherals.count; i++) {  
        CBPeripheral * peripheral = (CBPeripheral*) peripherals[i];  

        if (peripheral == nil) {  
            // Never happens  
        }  
        else{  
            // Always happens - also hardware thinks that the peripheral is connected  
            peripheral.delegate = self;  
            [peripheral discoverServices:self.bleServices];  

            // Does not discover any services !  <------------- ERROR!  
        }  
} 





-(void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {  
// Only gets called when [peripheral discoverServices:self.bleServices] is called whilst app is running (either in background or foreground).  
}  

PS: I have asked this also in the Apple Developer forum but had no reply so far.


PPS: I also have activated Background mode in my info.plist file:

enter image description here

mm24
  • 9,280
  • 12
  • 75
  • 170
  • Did you activate the BT background mode in your Info.plist? – Julian F. Weinert Aug 03 '16 at 15:25
  • Yes I did - adding edit to question – mm24 Aug 03 '16 at 15:26
  • Damnit. Was worth trying ;) – Julian F. Weinert Aug 03 '16 at 15:27
  • Yes. Thanks for this. That's why I am sort of struggling.. not sure what it is. Also I am scanning for explicit service UUIDs, which is what is required when scanning in background. – mm24 Aug 03 '16 at 15:28
  • 1
    Take a look at the willRestoreState argument. Does it contain the key CBCentralManagerRestoredStatePeripheralsKey? If yes then try using the value, an array of CBPeripheral objects, instead of calling retrieveConnectedPeriphetals. All of the previously discovered services should be there already. – Verticon Aug 03 '16 at 16:16
  • @RobertVaessen I had a look. However I was unable to fix this. Would you be able to take a look at the updated version of the question? – mm24 Aug 04 '16 at 14:51
  • @mm24 Try probing the tmpPeripheral that you recovered. The services which were previously discovered should already be there - I.e. your state is being restored. I do not think that another call to discoverServices will cause the didDiscoverServices method to be reinvoked for a previously discovered service. I have been meaning to get back to the BLE app that I have been working on - I will do so this weekend and explore your issue more fully. – Verticon Aug 04 '16 at 18:02
  • BTW - I think that my most recent comment should hold true for your original code as well. My first comment may have been a "bum steer" :-( – Verticon Aug 04 '16 at 18:11
  • @RobertVaessen Thanks for getting back to me. How can I trigger the peripheral to read the values? Should I use "[peripheral readValueForDescriptor:]" ? – mm24 Aug 05 '16 at 08:55
  • @mm24 readValueForDescriptor? I thought that you were trying to obtain the services. If you want the services then take a look at the CBPeripheral's services property. – Verticon Aug 05 '16 at 13:47

0 Answers0