iOS開發(fā)-鎖屏時斷開連接解決方法小析

在iOS開發(fā)中,當程序進入后臺或者鎖屏時,若程序是用socket進行連接,就有可能與服務器斷開連接。這是因為iOS設備為了讓設備盡量省電,減少不必要的用電時,對app后臺采用了墓碑機制的后臺。
墓碑機制簡單的理解,就是當任務被中斷(進入后臺)時,系統(tǒng)記錄下當前程序的當前狀態(tài)后,再中止程序,當程序再次啟用的時候,恢復到原來的狀態(tài)。
這就導致了才要socket進行連接的程序在進入后臺時會斷開連接,進入前臺需要重新連接。所以,根據(jù)需要,開發(fā)時需要保持后臺是“真后臺”。也就是程序在后臺依然保持運行狀態(tài)。
實現(xiàn)“真后臺”通常使用以下兩種方法:
(1)在后臺一直放歌(歌要為無聲)
(2)在后臺進行定位服務
比較兩種方法,個人認為,雖然兩種方法都是投機的方法,但是第二種比第一種更加合理。因為若程序一直在運行,若用戶在聽歌、接聽電話或者其他需要用到喇叭的操作時可能會收到影響。而定位可以一直不顯示,也不影響其他操作。
在此,著重介紹第二種方法在OC中的方法。
因為進入后臺等操作都屬于APP的生命周期,所以需要在AppDelegate中完成操作。
首先,在AppDelegate的.m文件中導入<CoreLocation/CoreLocation.h>,并加入CLLocationManagerDelegate的代理,并設置所需的東西,示例如下:

#import "AppDelegate.h"
#import <CoreLocation/CoreLocation.h>

@interface AppDelegate ()<CLLocationManagerDelegate>
//定位
@property (strong,nonatomic)CLLocationManager *locationManager;
//后臺任務標識符
@property (assign,nonatomic)UIBackgroundTaskIdentifier bgTask;
//終結處理程序的Block
@property (strong,nonatomic)dispatch_block_t expirationHandler;
//是否到達工作期限
@property (assign,nonatomic)BOOL jobExpired;
//是否在后臺
@property (assign,nonatomic)BOOL background;
@end

在didFinishLaunchingWithOptions方法中初始化locationManager并設置自動喚醒程序和綁定協(xié)議

UIApplication *app = [UIApplication sharedApplication];

    __weak AppDelegate *selfRef = self;
    
    self.expirationHandler = ^{  //創(chuàng)建后臺自喚醒
        [app endBackgroundTask:selfRef.bgTask];
//        后臺任務無效
        selfRef.bgTask = UIBackgroundTaskInvalid;
//        進入后臺任務終結處理
        selfRef.bgTask = [app beginBackgroundTaskWithExpirationHandler:selfRef.expirationHandler];
        selfRef.jobExpired = YES;
        while(selfRef.jobExpired)
        {
//                線程睡眠1s
            [NSThread sleepForTimeInterval:1];
        }
//                開始后臺任務類型
        [selfRef startBackgroundTask];
    };
//        檢測后臺的狀態(tài)
    [self monitorBatteryStateInBackground];
    _locationManager = [[CLLocationManager alloc] init];
    _locationManager.delegate = self;

上述中的相關方法

#pragma mark 檢測后臺的狀態(tài)
- (void)monitorBatteryStateInBackground
{
    self.background = YES;
    [self startBackgroundTask];
}
#pragma mark 開始后臺任務
- (void)startBackgroundTask
{
    if([Api sharedApi].loginedUserId)//當?shù)顷憼顟B(tài)才進入后臺循環(huán)(此處需要自己設定,判斷用戶是否登錄)
    {
//        開啟異步線程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSInteger count=0;
            BOOL NoticeNoBackground=false;//只通知一次標志位
            BOOL FlushBackgroundTime=false;//只通知一次標志位
            self.locationManager.distanceFilter = kCLDistanceFilterNone;//任何運動均接受,任何運動將會觸發(fā)定位更新
            self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;//定位精度
            while(self.background && !self.jobExpired){
                [NSThread sleepForTimeInterval:1];
                count++;
                if(count>60)//每60s進行一次開啟定位,刷新后臺時間
                {
                    count=0;
//                開始定位服務
                    [self.locationManager startUpdatingLocation];
                    [NSThread sleepForTimeInterval:1];
//                停止定位服務
                    [self.locationManager stopUpdatingLocation];
                    FlushBackgroundTime=false;
                }
                if(![Api sharedApi].loginedUserId)//未登錄或者掉線狀態(tài)下關閉后臺(此處需要自己設定,判斷用戶是否登錄)
                {
                    [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
                    return;//退出循環(huán)
                }
                NSTimeInterval backgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining];
                if(backgroundTimeRemaining<30&&NoticeNoBackground==false)
                {
                    NoticeNoBackground=true;
                }
                //測試后臺時間刷新
                if(backgroundTimeRemaining>200&&FlushBackgroundTime==false)
                {
                    [[NSNotificationCenter defaultCenter]postNotificationName:@"MessageUpdate" object:@"刷新后臺時間成功\n"];
                    FlushBackgroundTime=true;
                }
            }
            self.jobExpired = NO;
        });
    }
}

在生命周期的applicationDidBecomeActive方法中寫入

[UIApplication sharedApplication].applicationIconBadgeNumber=0;
//                停止定位服務
    [self.locationManager stopUpdatingLocation];
    self.background = NO;

通過定位協(xié)議的didFailWithError方法來判斷定位服務出錯的原因,并通過didUpdateLocations方法來獲取所定位的位置(注: didUpdateLocations中一定要獲取位置的改變,否則后臺刷新無用),代碼如下:

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error//當定位服務不可用出錯時,系統(tǒng)會自動調用該函數(shù)
    {
      // 自由發(fā)揮
    }
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *loc = [locations lastObject];
    float latitudeMe = loc.coordinate.latitude;
    float longitudeMe = loc.coordinate.longitude;
    NSLog(@"%f,%f",latitudeMe,longitudeMe);
}
  最后,希望這篇文章對各位有所幫助。
  此文參考《關于iOS后臺長時間掛起的方法》
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容