iOS 喚醒被Kill的APP保證藍牙的長連接


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與藍牙的長連接。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章