Search code examples
iosbluetooth-lowenergyiobluetooth

My bluetooth peripheral is sometimes not recognized by my iphone in background. Proximo by Kensington works


I am developing a Bluetooth 4.0 BLE hardware device. It works in a very simple way. It advertises a single service UUID and an additional special payload which contain 0xFF (Manufacturer Specific Data). It does not publish any GATT profile data except the service UUID in the advertisement.

The main idea is that when a user come close to the device a message should be displayed on the iphone. I am not trying to create another iBeacon protocol but this app will have a specific purpose :)

The app works flawlessly when in foreground and it also sometimes work when the app is in background, especially minutes after I put the phone to sleep. I have enabled the "bluetooth-central" background mode in UIBackgroundModes.

It is very common that the application never notices that the bluetooth hardware is closeby while the app is in background and this is the main problem that I need help with. For months I have thought that this is just how iOS works.

Now I have bought a Kensington Proximo Bluetooth Tracker Fob, and after some testing I have discovered that this device can really wake the iPhone up. I am trying to figure out how.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSDictionary *options = @{ CBCentralManagerOptionRestoreIdentifierKey:@"myCentralManagerIdentifier", CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithBool:NO]};
    self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:options];
    return YES;
}

- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)dict {
    NSLog(@"Restored, %@", dict);
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    NSDictionary *options = @{ CBCentralManagerOptionRestoreIdentifierKey:@"myCentralManagerIdentifier", CBCentralManagerScanOptionAllowDuplicatesKey:[NSNumber numberWithBool:NO]};

    if (self.manager.state == CBCentralManagerStatePoweredOn) {
        //Note, the actual UUID has been replaced below:
        [self.manager scanForPeripheralsWithServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:@"12345678-1234-1234-1234-123456789012"]] options:options];
    }
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
    UILocalNotification* localNotification = [[UILocalNotification alloc] init];
    localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];
    localNotification.alertBody = @"It is close!";
    localNotification.soundName = UILocalNotificationDefaultSoundName;
    localNotification.applicationIconBadgeNumber = 1;
    localNotification.timeZone = [NSTimeZone defaultTimeZone];
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    NSLog(@"%@", advertisementData);
}

Solution

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

    In short: In background your app will not detect the device when scanning if it has seen the device before. You can connect to a known device by trying to connect to it. I guess the Kensington Tracker does this.