This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Background ble operations with ios

HI, i'm trying to perform the following operations with the Core Bluetooth Framework of iOS:

  1. Connection to peripheral

  2. Services Discovery

  3. Characteristics Discovery

  4. Start Notify on a particular characteristic

These operations have to be triggered in background, when a callback not related to Core Bluetooth (Core Location Framework) fires up.

I have correctly set the Bluetooth Background settings for the app and when the application is put in background through the central button, all is ok: core location callback fires up and the core bluetooth steps are executed correctly. The problem comes when the application is killed by swiping up with the task manager: in this case when the core location callback fires up the phone is able to connect to the peripheral (1) but it does not discover services.

I'm using iPhone 6 with iOS 10.3.1 and micro nrf51822.

Here is my code:

CBCentralManager initialization (viewDidLoad)

self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{ CBCentralManagerOptionRestoreIdentifierKey:@"myCentralManagerIdentifier"}];

Core Location Callback:

     (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
NSLog(@"*** enter region");

    
    NSString *savedUuid = [[NSUserDefaults standardUserDefaults] stringForKey:@"preferenceUuid"];
    
    
    if (savedUuid!=NULL){
        NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:savedUuid];
        NSArray *arrayUuid = [NSArray arrayWithObjects:uuid, nil];
        
        _knownPeripheral = [[self.centralManager retrievePeripheralsWithIdentifiers:arrayUuid] objectAtIndex:0];
    }
    if (_knownPeripheral!=NULL){
        [self.centralManager connectPeripheral:_knownPeripheral options:nil];
    }

}

CoreBluetooth Callbacks:

(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { [self.knownPeripheral discoverServices:nil]; }

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
// Core Bluetooth creates an array of CBService objects —- one for each service that is discovered on the peripheral.

    
    for (CBService *service in peripheral.services) {
        
        if (([service.UUID isEqual:[CBUUID UUIDWithString:K_BT_SERVICE_BATTERY]])) {
            [peripheral discoverCharacteristics:nil forService:service];
        }
    }

}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {

    for (CBCharacteristic *characteristic in service.characteristics) {

        
        if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:K_BT_CHARACTERISTIC_BATTERY]]) {
            
            [self.sensorTag setNotifyValue:YES forCharacteristic:characteristic];
        }

}

How can i perform correctly the steps from 1) to 4) when the application is awaked from a killed state?

Thank you in advance

  • This is the correct behaviour, if the user kills the app then it will never be woken up automatically again.

    However, if the app is killed by iOS due to memory warnings, etc.. it will be restored and you can resume your background operations.

    The only thing you can do is let the users know that they shouldn't kill the app.

    You may see the reference here

    Specifically this line:

    In most cases, the system does not relaunch apps after they are force quit by the user. One exception is location apps, which in iOS 8 and later are relaunched after being force quit by the user. In other cases, though, the user must launch the app explicitly or reboot the device before the app can be launched automatically into the background by the system. When password protection is enabled on the device, the system does not launch an app in the background before the user first unlocks the device.

    Edit: To be more specific, what you are doing (ONLY if you are only using location to wake up the phone) is wrong, and probably your app will not make it through the approval process even if it eventually worked.

    When CoreLocation wakes up the phone, it's limited to CoreLocation functionality, not all BLE features will properly work, the only reason you are getting ability to connect to a peripheral is because it's probably has already been connected before and is cached. but you will not be able to start scanning and discovering services, etc... as expected.

    The only reason iOS will wake your phone up when it comes to a BLE context is the following events only:

    • An app acting in the central role receives data from a connected peripheral.
    • An app acting in the peripheral role receives commands from a connected central.

    Hope this answers your question?

  • Thank you for your clear response. I'm actually trying to do what you have guessed: awake the app with the core location framework (which seems not limited by force quit by the user) and then use core bluetooth in order to reconnect peripheral. I'm aware that Apple approval process can not be passed by using this method but, at the moment, I'm just trying to understand if it's faisable. Just another question: is an app (which acts as a BLE peripheral) awaked from killed state (with force quit of the user) if it receives command from a connected central?

  • Hi @Johnny_h, no worries :), ok it's good that you know that there is minor risks involved in using this trick, i had to note it out in case you didn't know, to answer your other question, unfortunately no, the app is not awaked if killed by the user in this case,it will only be awakened if iOS kills the app while in background mode due to memory warnings, to save resources etc ...

    It's almost like the music app on iOS, once you quit the app the music stops immediately, but if you put it in the background it resumes working as intended, if iOS has to kill it, it'll automatically restart and resume playing music so it's almost like you can put 100% faith that your app will continue to work seamlessly if the user doesn't force close it

Related