国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > iOS > 正文

iOS如何保持程序在后臺(tái)長(zhǎng)時(shí)間運(yùn)行

2019-10-21 18:52:18
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

iOS 為了讓設(shè)備盡量省電,減少不必要的開(kāi)銷(xiāo),保持系統(tǒng)流暢,因而對(duì)后臺(tái)機(jī)制采用墓碑式的“假后臺(tái)”。除了系統(tǒng)官方極少數(shù)程序可以真后臺(tái),一般開(kāi)發(fā)者開(kāi)發(fā)出來(lái)的應(yīng)用程序后臺(tái)受到以下限制:

1.用戶(hù)按Home之后,App轉(zhuǎn)入后臺(tái)進(jìn)行運(yùn)行,此時(shí)擁有180s后臺(tái)時(shí)間(iOS7)或者600s(iOS6)運(yùn)行時(shí)間可以處理后臺(tái)操作

2.當(dāng)180S或者600S時(shí)間過(guò)去之后,可以告知系統(tǒng)未完成任務(wù),需要申請(qǐng)繼續(xù)完成,系統(tǒng)批準(zhǔn)申請(qǐng)之后,可以繼續(xù)運(yùn)行,但總時(shí)間不會(huì)超過(guò)10分鐘。

3.當(dāng)10分鐘時(shí)間到之后,無(wú)論怎么向系統(tǒng)申請(qǐng)繼續(xù)后臺(tái),系統(tǒng)會(huì)強(qiáng)制掛起App,掛起所有后臺(tái)操作、線(xiàn)程,直到用戶(hù)再次點(diǎn)擊App之后才會(huì)繼續(xù)運(yùn)行。

當(dāng)然iOS為了特殊應(yīng)用也保留了一些可以實(shí)現(xiàn)“真后臺(tái)”的方法,摘取比較常用的:

1.VOIP

2.定位服務(wù)

3.后臺(tái)下載

4.在后臺(tái)一直播放無(wú)聲音樂(lè)(容易受到電話(huà)或者其他程序影響,所以暫未考慮)

5….更多

其中VOIP需要綁定一個(gè)Socket鏈接并申明給系統(tǒng),系統(tǒng)將會(huì)在后臺(tái)接管這個(gè)連接,一旦遠(yuǎn)端數(shù)據(jù)過(guò)來(lái),你的App將會(huì)被喚醒10s(或者更少)的時(shí)間來(lái)處理數(shù)據(jù),超過(guò)時(shí)間或者處理完畢,程序繼續(xù)休眠。

后臺(tái)現(xiàn)在是iOS7引入的新API,網(wǎng)上實(shí)現(xiàn)的代碼比較少,博主也沒(méi)有細(xì)心去找。

由于博主要做的App需要在后臺(tái)一直運(yùn)行,每隔一段時(shí)間給服務(wù)器主動(dòng)發(fā)送消息來(lái)保持帳號(hào)登陸狀態(tài),因而必須確保App不被系統(tǒng)墓碑限制。

博主最先嘗試了很多方法,包括朋友發(fā)來(lái)的一個(gè)Demo,每180s后臺(tái)時(shí)間過(guò)期就銷(xiāo)毀自己然后再創(chuàng)建一個(gè)后臺(tái)任務(wù),但是實(shí)際測(cè)試只有10分鐘時(shí)間。最后因?yàn)榭紤]到VOIP對(duì)服務(wù)端改動(dòng)太大,時(shí)間又太緊,所以選擇了定位服務(wù)的方法來(lái)保持后臺(tái)。

要啟動(dòng)定位服務(wù):

1.需要引入頭文件:#import

2.在AppDelegate.m中定義CLLocationManager * locationManager;作為全局變量方便控制

3.在程序啟動(dòng)初期對(duì)定位服務(wù)進(jìn)行初始化:

locationManager = [[CLLocationManager alloc] init];locationManager.delegate =self;//or whatever class you have for managing location

?4.在程序轉(zhuǎn)入后臺(tái)的時(shí)候,啟動(dòng)定位服務(wù)

[locationManager startUpdatingLocation];(第一次運(yùn)行這個(gè)方法的時(shí)候,如果之前用戶(hù)沒(méi)有使用過(guò)App,則會(huì)彈出是否允許位置服務(wù),關(guān)于用戶(hù)是否允許,后面代碼中有判斷)

這樣在定位服務(wù)可用的時(shí)候,程序會(huì)不斷刷新后臺(tái)時(shí)間,實(shí)際測(cè)試,發(fā)現(xiàn)后臺(tái)180s時(shí)間不斷被刷新,達(dá)到長(zhǎng)久后臺(tái)的目的。

但是這樣使用也有一些問(wèn)題,在部分機(jī)器上面,定位服務(wù)即使打開(kāi)也可能不能刷新后臺(tái)時(shí)間,需要完全結(jié)束程序再運(yùn)行。穩(wěn)定性不知道是因?yàn)榇a原因還是系統(tǒng)某些機(jī)制原因。

下面貼上代碼:

注意:代碼中包含朋友給的demo中,180s時(shí)間后銷(xiāo)毀自己再創(chuàng)建自己的后臺(tái)方法,我自己實(shí)現(xiàn)過(guò)程中加入了定位服務(wù)來(lái)確保后臺(tái)能夠一直在線(xiàn)。

源碼參考部分來(lái)自網(wǎng)上,因?yàn)榉薌oogle,找了很多英文方面的博文,在此感謝原作者分享。

判斷用戶(hù)是否打開(kāi)了定位服務(wù),是否禁用了該程序的定位權(quán)限:

if(![CLLocationManager locationServicesEnabled] || ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied))//判斷定位服務(wù)是否打開(kāi){   [InterfaceFuncation ShowAlertWithMessage:@"錯(cuò)誤"AlertMessage:@"定位服務(wù)未打開(kāi)/n保持在線(xiàn)需要后臺(tái)定位服務(wù)/n請(qǐng)到 設(shè)置-隱私 中打開(kāi)定位服務(wù)"ButtonTitle:@"我錯(cuò)了"];   return;}

?AppDelegate.m源碼:

 

@property(assign, nonatomic) UIBackgroundTaskIdentifier bgTask;@property(strong, nonatomic) dispatch_block_t expirationHandler;@property(assign, nonatomic)BOOL jobExpired;@property(assign, nonatomic)BOOL background;- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions{  UIApplication* app = [UIApplication sharedApplication];  __weak NSUAAAIOSAppDelegate* selfRef =self;  self.expirationHandler = ^{ //創(chuàng)建后臺(tái)自喚醒,當(dāng)180s時(shí)間結(jié)束的時(shí)候系統(tǒng)會(huì)調(diào)用這里面的方法    [app endBackgroundTask:selfRef.bgTask];     selfRef.bgTask = UIBackgroundTaskInvalid;     selfRef.bgTask = [app beginBackgroundTaskWithExpirationHandler:selfRef.expirationHandler];     NSLog(@"Expired");     selfRef.jobExpired =YES;     while(selfRef.jobExpired)     {       // spin while we wait for the task to actually end.       NSLog(@"等待180s循環(huán)進(jìn)程的結(jié)束");       [NSThreadsleepForTimeInterval:1];     }     // Restart the background task so we can run forever.     [selfRef startBackgroundTask];   };   // Assume that we're in background at first since we get no notification from device that we're in background when   // app launches immediately into background (i.e. when powering on the device or when the app is killed and restarted)   [selfmonitorBatteryStateInBackground];   locationManager = [[CLLocationManager alloc] init];   locationManager.delegate =self;   //[locationManager startUpdatingLocation];   returnYES;}- (void)monitorBatteryStateInBackground{   self.background =YES;   [selfstartBackgroundTask];}- (void)applicationDidBecomeActive:(UIApplication *)application{   // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.   NSLog(@"App is active");   [UIApplication sharedApplication].applicationIconBadgeNumber=0;//取消應(yīng)用程序通知腳標(biāo)   [locationManager stopUpdatingLocation];   self.background =NO;}- (void)applicationDidEnterBackground:(UIApplication *)application{   // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.   // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.   //if([self bgTask])   if(isLogined)//當(dāng)?shù)顷憼顟B(tài)才啟動(dòng)后臺(tái)操作   {      self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:self.expirationHandler];      NSLog(@"Entered background");      [selfmonitorBatteryStateInBackground];    }}- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError*)error//當(dāng)定位服務(wù)不可用出錯(cuò)時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用該函數(shù){   NSLog(@"定位服務(wù)出錯(cuò)");   if([error code]==kCLErrorDenied)//通過(guò)error的code來(lái)判斷錯(cuò)誤類(lèi)型   {      //Access denied by user      NSLog(@"定位服務(wù)未打開(kāi)");      [InterfaceFuncation ShowAlertWithMessage:@"錯(cuò)誤"AlertMessage:@"未開(kāi)啟定位服務(wù)/n客戶(hù)端保持后臺(tái)功能需要調(diào)用系統(tǒng)的位置服務(wù)/n請(qǐng)到設(shè)置中打開(kāi)位置服務(wù)"ButtonTitle:@"好"];   }}- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray*)locations//當(dāng)用戶(hù)位置改變時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用,這里必須寫(xiě)一點(diǎn)兒代碼,否則后臺(tái)時(shí)間刷新不管用{    NSLog(@"位置改變,必須做點(diǎn)兒事情才能刷新后臺(tái)時(shí)間");    CLLocation *loc = [locations lastObject];    //NSTimeInterval backgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining];    //NSLog(@"Background Time Remaining = %.02f Seconds",backgroundTimeRemaining);    // Lat/Lon    floatlatitudeMe = loc.coordinate.latitude;    floatlongitudeMe = loc.coordinate.longitude;}- (void)startBackgroundTask{    NSLog(@"Restarting task");    if(isLogined)//當(dāng)?shù)顷憼顟B(tài)才進(jìn)入后臺(tái)循環(huán)    {      // Start the long-running task.      NSLog(@"登錄狀態(tài)后臺(tái)進(jìn)程開(kāi)啟");      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{          // When the job expires it still keeps running since we never exited it. Thus have the expiration handler          // set a flag that the job expired and use that to exit the while loop and end the task.          NSIntegercount=0;          BOOLNoticeNoBackground=false;//只通知一次標(biāo)志位          BOOLFlushBackgroundTime=false;//只通知一次標(biāo)志位          locationManager.distanceFilter = kCLDistanceFilterNone;//任何運(yùn)動(dòng)均接受,任何運(yùn)動(dòng)將會(huì)觸發(fā)定位更新          locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;//定位精度          while(self.background && !self.jobExpired)          {              NSLog(@"進(jìn)入后臺(tái)進(jìn)程循環(huán)");              [NSThreadsleepForTimeInterval:1];              count++;              if(count>60)//每60s進(jìn)行一次開(kāi)啟定位,刷新后臺(tái)時(shí)間              {                  count=0;                  [locationManager startUpdatingLocation];                  NSLog(@"開(kāi)始位置服務(wù)");                  [NSThreadsleepForTimeInterval:1];                  [locationManager stopUpdatingLocation];                  NSLog(@"停止位置服務(wù)");                  FlushBackgroundTime=false;               }               if(!isLogined)//未登錄或者掉線(xiàn)狀態(tài)下關(guān)閉后臺(tái)               {                  NSLog(@"保持在線(xiàn)進(jìn)程失效,退出后臺(tái)進(jìn)程");                  [InterfaceFuncation ShowLocalNotification:@"保持在線(xiàn)失效,登錄已被注銷(xiāo),請(qǐng)重新登錄"];                  [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];                  return;//退出循環(huán)               }               NSTimeIntervalbackgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining];               NSLog(@"Background Time Remaining = %.02f Seconds",backgroundTimeRemaining);               if(backgroundTimeRemaining<30&&NoticeNoBackground==false)               {                   [InterfaceFuncation ShowLocalNotification:@"向系統(tǒng)申請(qǐng)長(zhǎng)時(shí)間保持后臺(tái)失敗,請(qǐng)結(jié)束客戶(hù)端重新登錄"];                   NoticeNoBackground=true;               }               //測(cè)試后臺(tái)時(shí)間刷新               if(backgroundTimeRemaining>200&&FlushBackgroundTime==false)               {                  [[NSNotificationCenterdefaultCenter] postNotificationName:@"MessageUpdate"object:@"刷新后臺(tái)時(shí)間成功/n"];                  FlushBackgroundTime=true;                  //[InterfaceFuncation ShowLocalNotification:@"刷新后臺(tái)時(shí)間成功"];                }            }            self.jobExpired =NO;         });     }}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到IOS開(kāi)發(fā)頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 凤凰县| 仪陇县| 新丰县| 望都县| 开阳县| 南平市| 霍山县| 郁南县| 六盘水市| 福泉市| 额济纳旗| 环江| 藁城市| 石渠县| 安庆市| 玛多县| 临澧县| 商丘市| 茂名市| 商洛市| 新源县| 高要市| 阿克| 临安市| 宁河县| 商南县| 讷河市| 沁源县| 基隆市| 乌鲁木齐市| 双鸭山市| 云梦县| 瓦房店市| 西昌市| 正镶白旗| 敦煌市| 澳门| 石泉县| 大宁县| 建湖县| 宽甸|