BLE Scan on Background issue

I encountered some issues about BLE scanning on my project. I must be able to scan BLE device's advertisement string continuously on background mode.


Some problems about BLE scanning on background below:

1. When BLE scan on foreground, it will scan continuously (scan interval about 1-2 second) as below:

strAdvertisementDataLocalName= F_H06LOCKERFFFF

strAdvertisementDataLocalName= F_H06LOCKERFFFF

strAdvertisementDataLocalName= F_H06LOCKERFFFF

But when BLE scan on background, it will scan discontinuously (sometimes max scan interval above 15 second) as below:

strAdvertisementDataLocalName= F_H06LOCKERFFFF

bleScanForBackground

bleScanForBackground

strAdvertisementDataLocalName= F_H06LOCKERFFFF

bleScanForBackground

...

bleScanForBackground

strAdvertisementDataLocalName= F_H06LOCKERFFFF

...

Is this the limitation of iOS on background for BLE scanning? How do I deal with this issue (the scan interval is the same with foreground)?

2. When BLE device is advertising, iOS and android both can get the advertisement string "F_H06LOCKERFFFF"; but when BLE device changes the advertisement string as "F_H127CEC79FEA805LLLL", android can scan the changed advertisement string"F_H127CEC79FEA805LLLL", but iOS scan still the old advertisement string"F_H06LOCKERFFFF".

How do I deal with this issue? This will let iOS BLE scanning the new advertisement string"F_H127CEC79FEA805LLLL" on background?


Thank you for your reply!


// ---------------------------------------------------------------------------------------------------------------------------------------

AppDelegate.m

//

// AppDelegate.m

// Locker_BLE_F1

//


#import "AppDelegate.h"


@interface AppDelegate ()

{

MainViewController *MainVC;

}

@end


@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

NSLog (@"AppDelegate(didFinishLaunchingWithOptions)");

MainVC = (MainViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController;

return YES;

}


- (void)applicationDidEnterBackground:(UIApplication *)application {

NSLog (@"applicationDidEnterBackground");

[MainVC ExecuteBackgroundAction];

[self backgroundHandler];

}


- (void)backgroundHandler {

UIApplication *application = [UIApplication sharedApplication];

__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{

NSLog(@"backgroundHandler1");

dispatch_async(dispatch_get_main_queue(),^{

if( bgTask != UIBackgroundTaskInvalid) {

bgTask = UIBackgroundTaskInvalid;

}

});

}];


// Start the long-running task

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

while ([Common getOpMode] == OP_MODE_BACKGROUND) {

[MainVC bleScanForBackground];

[NSThread sleepForTimeInterval:1.0f];

}

});

}


- (void)applicationWillEnterForeground:(UIApplication *)application {

NSLog (@"applicationWillEnterForeground");

[MainVC ExecuteForegroundAction];

}

@end


MainViewController.m

//

// MainViewController.m

// Locker_BLE_F1

//

#import "MainViewController.h"


@interface MainViewController () {

}

@end


@implementation MainViewController


#pragma mark - View Controller

- (void)viewDidLoad {

[super viewDidLoad];

self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];

}


- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}


- (void) viewDidAppear:(BOOL)animated {

[super viewDidAppear:animated];

}


#pragma mark - BlueTooth (BLE, Central)

// method 1

- (void) centralManagerDidUpdateState:(CBCentralManager *)central {

if (central.state != CBManagerStatePoweredOn) // CBCentralManagerStatePoweredOn)

{

NSLog (@"Please open the Bluetooth from System Setting");

return;

}

[self setBLEStatusWithLog:SCANNING];

NSDictionary* scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];

[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:SERVICE_UUID]] options:scanOptions];

}


// method 2

- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI

{

[self.centralManager stopScan];

NSDictionary* scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];

[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:SERVICE_UUID]] options:scanOptions];

NSString *strAdvertisementDataLocalName, *strDeviceName ;


strAdvertisementDataLocalName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];

if (strAdvertisementDataLocalName == nil) { return; }


strDeviceName = [strAdvertisementDataLocalName substringWithRange:NSMakeRange(0, REMOTE_DEVICE_NAME.length)];

if (![strDeviceName isEqualToString:REMOTE_DEVICE_NAME]) return;


NSLog(@"strAdvertisementDataLocalName= %@", strAdvertisementDataLocalName);


self.connectPeripheral = peripheral;

self.connectPeripheral.delegate = self;

...

}


#pragma mark - General Function

- (void) bleScanForBackground {

[self updateLog:@"bleScanForBackground " LogType:FLOW_LOG];

NSDictionary* scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];

[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:SERVICE_UUID]] options:scanOptions];

}


- (void) ExecuteBackgroundAction {

[self changeOpMode:OP_MODE_BACKGROUND];

if (self.isConnected == true) {

[self bleDisconnect:self.centralManager Peripheral:self.connectPeripheral];

}

}


- (void) ExecuteForegroundAction {

}

@end

To describe detail as below:


BLE device will advertise and change the string "F_H06LOCKERFFFF" ---> "F_H127CEC79FEA805LLLL"(about keeping 6 second) ---> "F_H06LOCKERFFFF" on background mode; that is, App must be able to scan the new string ""F_H127CEC79FEA805LLLL" during 6 second after BLE device change the advertisement string "F_H127CEC79FEA805LLLL".


But the result of test using queue or timer on AppDelegate, the scan interval is not fixed and it might even exceed 15 second between twice scanning,

this will cause app miss the string"F_H127CEC79FEA805LLLL" and doesn't work (it should execute some action but not).


This is the reason about problem 1(scanning time interval) and problem 2(scanning advertisement string).


Thank you for your reply.

1. Yes, it's an iOS designed-in limitation. Why are you using an advertisement string instead of subscribing to a characteristic?

2. File a bug report and post your bug report number.

Thank you for NotMyName's reply.


1. On my project App must scan the advertisement string of some devices on Foreground and Background mode. When App scan the match advertisement string of one device(App save a device paired table inside), it will take some action and response the event. Can any method break through or improve the limition? And this will let the scan interval is fixed. (< 6 second).


2. No bug and I don't know how to post some files to here, these files will clearify my statement.


3. App will get different advertisement string using peripheral.name or AdvertisementLocalName.

peripheral.name ---> FUSHING KBD

AdvertisementLocalName ---> F_H06LOCKERFFFF

Now BLE device advertise the string for AdvertisementLocalName, App use AdvertisementLocalName to get the string, but when device changes the advertisement string(F_H06LOCKERFFFF ---> F_H127CEC79FEA805LLLL), App still get the old string(F_H06LOCKERFFFF), How do I deal with? Whether I must use peripheral.name instead of AdvertisementLocalName and BLE device must also modify its advertisement string to match the peripheral.name.


Thanks for your reply.

BLE Scan on Background issue
 
 
Q