iOS基礎藍牙連接和數據通信請在CSDN搜索其他博文,這裏不再贅述。
iOS保證後臺藍牙長連接的方法,經親測過歸納爲以下幾項:
1.後臺靜音音頻的循環播放
後臺循環播放一個靜音的音頻文件來保證APP的持續存活,不失爲一個曲線方法。缺點是需要後臺音頻播放的說明及權限,在APP審覈過程中會有被拒絕的風險。APP後臺持續活動,不論是一直掃描還是連接 Peripheral都可以做到藍牙重連。
2.連接特定的 Peripheral
iOS藍牙連接最基本的方法是掃描,處於後臺的APP無法持續的掃描藍牙,即使使用
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"begin bgend=============");
// 如果在系統規定時間內任務還沒有完成,在時間到之前會調用到這個方法,一般是10分鐘
}];
來申請延長後臺駐留時間也無法一直持續掃描下去。連接特定的 Peripheral保持長連接的方法就是在APP前臺掃描連接過程中保存下Peripheral對象,在進入後臺斷開連接的情況下直接連接這個Peripheral:
- (void)connectPeripheral:(CBPeripheral *)peripheral options:(nullable NSDictionary<NSString *, id> *)options;
來保持後臺的藍牙重連。
這裏還有一種情況就是藍牙設備與iOS系統配對,並且連接的情況,APP斷開藍牙連接的重連問題。這種情況下需要結合
- (NSArray<CBPeripheral *> *)retrieveConnectedPeripheralsWithServices:(NSArray<CBUUID *> *)serviceUUIDs NS_AVAILABLE(10_9, 7_0);
來獲取已經配對的系統藍牙列表,綜合以上情況保持特定的Peripheral連接。
3.iBeacon喚醒APP
爲什麼要做iBeacon喚醒APP呢,之前兩種情況的藍牙後臺重連和長連接的情形是APP必需是存活的狀態,但如果用戶玩遊戲、看視頻之類的操作導致系統因內存原因殺掉後臺的部分APP,之前的方法就沒用了。iBeacon喚醒APP就能起作用了,iBeacon原理可以參考其他文章,而我們應該做的就是在進入或者離開iBeacon範圍內短暫地喚醒APP,這個時間大概在10秒左右,足夠進行藍牙的重連操作了。iBeacon需要始終定位權限,以下爲iBeacon喚醒的代碼實現:
- (void)initManager{
if ([CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]] && !self.iBeaconManager) {
self.iBeaconManager = [[CLLocationManager alloc]init];
self.iBeaconManager.delegate = self;
[self.iBeaconManager requestAlwaysAuthorization];
if ([self.iBeaconManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) {
[self.iBeaconManager setAllowsBackgroundLocationUpdates:YES];
}
_ibeacon = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc]initWithUUIDString:iBeaconMonitorSignal] identifier:@"iBeacon"];
_ibeacon.notifyEntryStateOnDisplay = YES;
[self.iBeaconManager startMonitoringForRegion:_ibeacon];
DDLogError(@"%@ GrootiBeaconManager ibeaconManager startMonitoringForRegion",APP_TAG);
}
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region{
DDLogError(@"%@ GrootiBeaconManager ibeaconManager didStartMonitoringForRegion",APP_TAG);
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
DDLogError(@"%@ GrootiBeaconManager ibeaconManager didEnterRegion",APP_TAG);
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
DDLogError(@"%@ GrootiBeaconManager ibeaconManager didExitRegion",APP_TAG);
[self.iBeaconManager stopRangingBeaconsInRegion:(CLBeaconRegion *)region];
}
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{
DDLogError(@"%@ GrootiBeaconManager ibeaconManager didRangeBeacons %@",region,APP_TAG);
if ([[region.proximityUUID UUIDString]isEqualToString:iBeaconMonitorSignal]){
[self.iBeaconManager stopMonitoringForRegion:region];
[self.iBeaconManager stopRangingBeaconsInRegion:region];
DDLogError(@"%@ GrootiBeaconManager ibeaconManager didRangeBeacons",APP_TAG);
if (![[GrootMainViewInstance sharedInstance].mainController.currentDevice isConnected]) {
[[GrootMainViewInstance sharedInstance].mainController loginToDevice];
DDLogError(@"%@ GrootiBeaconManager ibeaconManager didRangeBeacons*********loginToDevice",APP_TAG);
}
}
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
DDLogError(@"%@ GrootiBeaconManager ibeaconManager didDetermineState %ld",APP_TAG,(long)state);
if (![[GrootMainViewInstance sharedInstance].mainController.currentDevice isConnected]) {
[[GrootMainViewInstance sharedInstance].mainController loginToDevice];
DDLogError(@"%@ GrootiBeaconManager ibeaconManager didDetermineState*********loginToDevice",APP_TAG);
}
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
DDLogError(@"ibeaconManager monitoringDidFailForRegion:%@", error);
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
DDLogError(@"ibeaconManager Location manager failed:%@", error);
}
其中iBeaconMonitorSignal 就是設備發出的iBeacon信號,需要和設備商定,類似於
#define iBeaconMonitorSignal @"10F86430-1346-11E4-9191-0800200C9A66"
設備發iBeacon信號邏輯可以與設備商定,斷開連接多久之後發出iBeacon信號,與藍牙的廣播信號間隔發出等等。以上代碼在進入和離開iBeacon區域均嘗試了重連邏輯,經測試能完美喚醒被殺的APP,然後重連上藍牙,保證APP與藍牙的長連接。