有關iOS BLE Scan問題想請教:
1. 請參考附檔(iOS_Foreground_Scan_time.png, iOS_Background_scan_time.png), BLE裝置會改變廣播字串 F_H06LOCKERFFFF ---> F_H127CEC79FEA805LLLL(持續6秒) ---> F_H06LOCKERFFFF, 手機App必須在6秒時間內掃描到BLE裝置, App在前景時沒有問題, 連續掃描間隔約1-2秒, 但App在背景時, 掃描間隔不固定, 有時掃描間隔甚至大於15秒以上, 而錯過廣播字串(F_H127CEC79FEA805LLLL), 以至於該動作而不動作, 請問這是iOS BLE在背景下運作的限制嗎? 有沒有方法可以改善(和前景掃描一樣間隔)?
<<註>>: 在AppDelegate使用Timer(1秒或2秒)定時掃描, 得到和(iOS_Background_scan_time.png)一樣的結果
2. 請參考附檔(iOS_BLE_Scan_1.jpg, iOS_BLE_Scan_2.jpg, iOS_BLE_Scan_3.jpg), 當藍牙裝置改變廣播字串時(F_H06LOCKERFFFF ---> F_H127CEC79FEA805LLLL), Android手機可以掃瞄到改變的字串(F_H127CEC79FEA805LLLL), 但是iOS仍然掃瞄到舊字串(F_H06LOCKERFFFF), 我要怎麼處理才能讓iOS掃瞄到新字串?
謝謝您的回覆!!
// ---------------------------------------------------------------------------------------------------------------
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