mflac
mflac

Reputation: 353

iOS CBCentralManager doesn't detect CBPeripheral in background when it comes into range

I am working on a test BTLE app. The user can select to start central or peripheral mode. if 2 devices are both active and in range they instantly detect, connect and pass data, but...

If device1 is started in central mode and then placed into background, then device2 is taken out of range and put into peripheral mode, when the peripheral is brought next to the backgrounded central, the central detects the peripheral and gets data.

If device1 is started in peripheral mode and placed in background, then device2 is taken out of range and placed into central mode, and then brought into range it does NOT detect the peripheral. (i waited up to 5 minutes) If i press the "start central" button again, it detects immediately!

the "start central" only does the following:

-(id)init{
    if (self=[super init]) {
        dispatch_queue_t peripheralQueue=dispatch_queue_create("com.Dev.peripheralQueue", 0);
        dispatch_queue_t centralQueue=dispatch_queue_create("com.Dev.centralQueue", 0);

        // Initiate Managers with restore keys for background mode
        self.centralManager=[[CBCentralManager alloc]initWithDelegate:self
                                                                queue:centralQueue
                                                              options:@{CBCentralManagerOptionRestoreIdentifierKey: CM_RESTORE_KEY}];
        self.peripheralManager=[[CBPeripheralManager alloc]initWithDelegate:self
                                                                      queue:peripheralQueue
                                                                    options:@{CBPeripheralManagerOptionRestoreIdentifierKey: PM_RESTORE_KEY}];
        // 1. create The UUIDs
        // 2. create the service and characteristics
//service is alloc/inited and published in did update state
    }
    return self;
}

-(void)switchToCentral
{
    NSLog(@"BTM switchToCentral");
    [self.peripheralManager stopAdvertising];
    [self scan];
    self.isCentral = YES;
}

- (void)scan
{
    [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]
                                                options:@{ CBCentralManagerScanOptionAllowDuplicatesKey:@NO}];
    NSLog(@"CM Scanning started");
}

I added the following shameful hack:

-(void)switchToCentral
{
    NSLog(@"BTM switchToCentral");
    [self stopBroadcasting];
    [self scan];
    self.isCentral = YES;

    dispatch_async(dispatch_get_main_queue(), ^{
        [NSTimer scheduledTimerWithTimeInterval:5
                                         target:self
                                       selector:@selector(centralShouldRescan:)
                                       userInfo:nil
                                        repeats:YES];
    });
}

-(void)centralShouldRescan:(NSTimer*)timer{

    NSLog(@"BTM centralShouldRescan");
    if (self.isCentral) {
        NSLog(@"BTM centralShouldRescan isCentral");
        [self stopBroadcasting];
        [self scan];


    }else{
        NSLog(@"BTM centralShouldRescan isCentral");
        [timer invalidate];
    }
}

and now it works! I am at a loss to understand this.It was my understanding and experience that when CBCentral manager starts to scan, it keeps scanning until stopped, especially if it is in the foreground.

Upvotes: 0

Views: 2242

Answers (1)

Paulw11
Paulw11

Reputation: 115041

Have you implemented the centralManagerDidUpdateState delegate method? I suspect that when you disable the peripheral mode, there is some time delay before the centralManager is ready to scan - this is just a guess. You could try something like -

-(void) centralManagerDidUpdateState:(CBCentralManager *)central
{
    if (central.state == CBCentralManagerStatePoweredOn)
    {
       [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] options:@{ CBCentralManagerScanOptionAllowDuplicatesKey:@NO}];
    }
}

This will ensure the scan is re-initiated if the central manager transitions out of the powered on state.

Upvotes: 1

Related Questions