iOS 通過定位獲取常駐后臺

我們知道ios 的應(yīng)用,大部分都是進(jìn)入后臺,就不會執(zhí)行任何操作,但是 ,很多時候我們希望程序進(jìn)入后臺,也能執(zhí)行一些檢測操作,比如說,應(yīng)用進(jìn)入后臺,我們?nèi)匀豢梢詫崟r去獲取當(dāng)前的位置信息。下面我們來了解下,ios 獲取后臺時間的幾種方式
根據(jù)蘋果文檔中關(guān)于后臺執(zhí)行的描述,任何app都有3分鐘左右的后臺任務(wù)執(zhí)行時間。 3分鐘后,app會被iOS強(qiáng)行掛起。
但是,有幾類app允許有“無限的”后臺運(yùn)行時間:

  1. Audio。
  2. Location/GPS。
  3. VoIP。

你可以將任何app聲明為上述3種類型以獲得無限的后臺運(yùn)行時間,但當(dāng)你提交app到App Store時,蘋果會審查你的app,一旦發(fā)現(xiàn)你“濫用”了后臺API,你的app將被拒絕。也即是說你在info.plist 設(shè)置這幾種backgroundmode,你的程序必須含有這些功能,你的程序才會有審核通過,你想獲取應(yīng)用進(jìn)入后臺獲取更多的后臺時間,還要看蘋果給不給機(jī)會了。。。

1 上面有一種方式蘋果文檔說到任何應(yīng)用都有3分鐘的后臺執(zhí)行任務(wù)時間。好吧先看下一段代碼
(1)

- (void)applicationDidEnterBackground:(UIApplication *)application {
    UIApplication*   app = [UIApplication sharedApplication];
    __block    UIBackgroundTaskIdentifier bgTask;
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid)
            {
                bgTask = UIBackgroundTaskInvalid;
            }
        });
 }];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (bgTask != UIBackgroundTaskInvalid)   
            {
                bgTask = UIBackgroundTaskInvalid;
        }); 
    });
}

這種方式,是不需要再info.plist 配置就可以在申請到短時間的后臺運(yùn)行時間,蘋果也不會對這個進(jìn)行審核
2 第二種方式,也是今天想著重提到的,就是通過定位獲取更多的后臺使用的時間,這種適合于需要在后臺收集用戶的定位的場景,例如滴滴打車此類應(yīng)用。
上面已經(jīng)提到了這種方式,需要在info.plist 設(shè)置

C96A6568-2EEA-475D-B76E-556F05B43A7F.png

因為在蘋果在info.plist 進(jìn)行了設(shè)置,蘋果也會對其 進(jìn)行審核。
接下來是在來看下代碼段

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    _task = [BGTask shareBGTask];
    UIAlertView *alert;
    //判斷定位權(quán)限
    if([UIApplication sharedApplication].backgroundRefreshStatus == UIBackgroundRefreshStatusDenied)
    {
        alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"應(yīng)用沒有不可以定位,需要在在設(shè)置/通用/后臺應(yīng)用刷新開啟" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
        [alert show];
    }
    else if ([UIApplication sharedApplication].backgroundRefreshStatus == UIBackgroundRefreshStatusRestricted)
    {
        alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"設(shè)備不可以定位" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
        [alert show];
    }
    else
    {
        _location = [[CLLocationManager alloc]init];
        _location.desiredAccuracy = kCLLocationAccuracyBestForNavigation;//導(dǎo)航級別的精確度
        _location.allowsBackgroundLocationUpdates = YES; //允許后臺刷新
        _location.pausesLocationUpdatesAutomatically = NO; //不允許自動暫停刷新
        _location.distanceFilter = kCLDistanceFilterNone;  //不需要移動都可以刷新
        [_location startUpdatingLocation];
        [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(log) userInfo:nil repeats:YES];
    }
    return YES;
}
//進(jìn)入后臺開啟定位
- (void)applicationDidEnterBackground:(UIApplication *)application {
    [_location startUpdatingLocation];
}

經(jīng)測試而得只要這樣無論在前臺或者是后臺,log 這個方法都是有打印的。這里必須注意一點(diǎn)就是

  _location.distanceFilter = kCLDistanceFilterNone;  //不需要移動都可以刷新

之前因為要這樣設(shè)置,不然就各種掉坑,不移動就不會執(zhí)行定位,不定位的話,那么后臺進(jìn)程也就掛起了,那么就不能執(zhí)行任何操作
(2)其實這種后臺刷新是很暴力的,導(dǎo)航儀不斷在定位,你才可以獲取后臺活躍的時間,去執(zhí)行你的一些想要的操作,但是不斷的定位會導(dǎo)致,電量消耗過快,我測試一個小時獎金跑去了10%的電量,那么有沒有一些更優(yōu)的方案,減少定位的次數(shù),然后又能讓后臺活躍呢
下面來講解下思路

D953031F-A8AD-4223-8D22-622586039EE2.png

這個優(yōu)化面臨的問題,就是當(dāng)程序進(jìn)入了后臺,如果讓定位停止了,那么程序就后臺就無法活躍了,就是把程序進(jìn)入后臺的問題解決了,那就好辦了,看了上圖,也可以看出,思路主要是在當(dāng)前正在定位的時候,10秒后關(guān)閉當(dāng)前的定位,然后此時開啟后臺任務(wù)backgroundtask,那么只要就會有3分鐘的活躍時間,那么在這個后臺任務(wù)有效時間內(nèi)再次開啟定位的話,程序在后臺便依舊可以活躍,那么只要開啟和關(guān)閉循環(huán)進(jìn)行,就可以實現(xiàn)常駐后臺了,那么這個時間間隔可以自定義,在自己需要的范圍內(nèi)即可,但是不能超過3分鐘,那么接下來在看看主要代碼實現(xiàn)

//定位回調(diào)里執(zhí)行重啟定位和關(guān)閉定位
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    NSLog(@"定位收集");
//正在手機(jī)定位不執(zhí)行任何操作
    if (isCollect) {
        return;
    }
    [self performSelector:@selector(restartLocation) withObject:nil afterDelay:120];
    [self performSelector:@selector(stopLocation) withObject:nil afterDelay:10];
    isCollect = YES;
}
-(void)restartLocation
{
    NSLog(@"重新啟動定位");
    CLLocationManager *locationManager = [BGLogation shareBGLocation];
    locationManager.delegate = self;
    locationManager.distanceFilter = kCLDistanceFilterNone; // 不移動也可以后臺刷新回調(diào)
    if ([[UIDevice currentDevice].systemVersion floatValue]>= 8.0) {
        [locationManager requestAlwaysAuthorization];
    }
    [locationManager startUpdatingLocation];
    [self.bgTask beginNewBackgroundTask];
}
//停止后臺定位
-(void)stopLocation
{
    NSLog(@"停止定位");
    isCollect = NO;
    CLLocationManager *locationManager = [BGLogation shareBGLocation];
    [locationManager stopUpdatingLocation];
}

接下來是demo 的地址
https://github.com/heysunnyboy/locationdemo.git
可以看到下面的代碼 ,在delegate 里設(shè)置的定時器一直都在跑沒有停止就知道這個后臺常駐是有效的

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    _task = [BGTask shareBGTask];
    UIAlertView *alert;
    //判斷定位權(quán)限
    if([UIApplication sharedApplication].backgroundRefreshStatus == UIBackgroundRefreshStatusDenied)
    {
        alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"應(yīng)用沒有不可以定位,需要在在設(shè)置/通用/后臺應(yīng)用刷新開啟" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
        [alert show];
    }
    else if ([UIApplication sharedApplication].backgroundRefreshStatus == UIBackgroundRefreshStatusRestricted)
    {
        alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"設(shè)備不可以定位" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
        [alert show];
    }
    else
    {
        self.bgLocation = [[BGLogation alloc]init];
        [self.bgLocation startLocation];
        [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(log) userInfo:nil repeats:YES];
    }
    return YES;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容