iOS如何保持程序在后台长时间运行_IOS

iOS 为了让设备尽量省电,减少不必要的开销,保持系统流畅,因而对后台机制采用墓碑式的“假后台”。除了系统官方极少数程序可以真后台,一般开发者开发出来的应用程序后台受到以下限制:

1.用户按Home之后,App转入后台进行运行,此时拥有180s后台时间(iOS7)或者600s(iOS6)运行时间可以处理后台操作

2.当180S或者600S时间过去之后,可以告知系统未完成任务,需要申请继续完成,系统批准申请之后,可以继续运行,但总时间不会超过10分钟。

3.当10分钟时间到之后,无论怎么向系统申请继续后台,系统会强制挂起App,挂起所有后台操作、线程,直到用户再次点击App之后才会继续运行。

当然iOS为了特殊应用也保留了一些可以实现“真后台”的方法,摘取比较常用的:

1.VOIP

2.定位服务

3.后台下载

4.在后台一直播放无声音乐(容易受到电话或者其他程序影响,所以暂未考虑)

5….更多

其中VOIP需要绑定一个Socket链接并申明给系统,系统将会在后台接管这个连接,一旦远端数据过来,你的App将会被唤醒10s(或者更少)的时间来处理数据,超过时间或者处理完毕,程序继续休眠。

后台现在是iOS7引入的新API,网上实现的代码比较少,博主也没有细心去找。

由于博主要做的App需要在后台一直运行,每隔一段时间给服务器主动发送消息来保持帐号登陆状态,因而必须确保App不被系统墓碑限制。

博主最先尝试了很多方法,包括朋友发来的一个Demo,每180s后台时间过期就销毁自己然后再创建一个后台任务,但是实际测试只有10分钟时间。最后因为考虑到VOIP对服务端改动太大,时间又太紧,所以选择了定位服务的方法来保持后台。

要启动定位服务:

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

2.在AppDelegate.m中定义CLLocationManager * locationManager;作为全局变量方便控制

3.在程序启动初期对定位服务进行初始化:

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

​4.在程序转入后台的时候,启动定位服务

[locationManager startUpdatingLocation];(第一次运行这个方法的时候,如果之前用户没有使用过App,则会弹出是否允许位置服务,关于用户是否允许,后面代码中有判断)

这样在定位服务可用的时候,程序会不断刷新后台时间,实际测试,发现后台180s时间不断被刷新,达到长久后台的目的。

但是这样使用也有一些问题,在部分机器上面,定位服务即使打开也可能不能刷新后台时间,需要完全结束程序再运行。稳定性不知道是因为代码原因还是系统某些机制原因。

下面贴上代码:

注意:代码中包含朋友给的demo中,180s时间后销毁自己再创建自己的后台方法,我自己实现过程中加入了定位服务来确保后台能够一直在线。

源码参考部分来自网上,因为翻了Google,找了很多英文方面的博文,在此感谢原作者分享。

判断用户是否打开了定位服务,是否禁用了该程序的定位权限:

if(![CLLocationManager locationServicesEnabled] || ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied))//判断定位服务是否打开
{
   [InterfaceFuncation ShowAlertWithMessage:@"错误"AlertMessage:@"定位服务未打开\n保持在线需要后台定位服务\n请到 设置-隐私 中打开定位服务"ButtonTitle:@"我错了"];
   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 = ^{ //创建后台自唤醒,当180s时间结束的时候系统会调用这里面的方法
    [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循环进程的结束");
       [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;//取消应用程序通知脚标
   [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)//当登陆状态才启动后台操作
   {
      self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:self.expirationHandler];
      NSLog(@"Entered background");
      [selfmonitorBatteryStateInBackground];
    }
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError*)error//当定位服务不可用出错时,系统会自动调用该函数
{
   NSLog(@"定位服务出错");
   if([error code]==kCLErrorDenied)//通过error的code来判断错误类型
   {
      //Access denied by user
      NSLog(@"定位服务未打开");
      [InterfaceFuncation ShowAlertWithMessage:@"错误"AlertMessage:@"未开启定位服务\n客户端保持后台功能需要调用系统的位置服务\n请到设置中打开位置服务"ButtonTitle:@"好"];
   }
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray*)locations//当用户位置改变时,系统会自动调用,这里必须写一点儿代码,否则后台时间刷新不管用
{
    NSLog(@"位置改变,必须做点儿事情才能刷新后台时间");
    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)//当登陆状态才进入后台循环
    {
      // Start the long-running task.
      NSLog(@"登录状态后台进程开启");
      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;//只通知一次标志位
          BOOLFlushBackgroundTime=false;//只通知一次标志位
          locationManager.distanceFilter = kCLDistanceFilterNone;//任何运动均接受,任何运动将会触发定位更新
          locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;//定位精度
          while(self.background && !self.jobExpired)
          {
              NSLog(@"进入后台进程循环");
              [NSThreadsleepForTimeInterval:1];
              count++;
              if(count>60)//每60s进行一次开启定位,刷新后台时间
              {
                  count=0;
                  [locationManager startUpdatingLocation];
                  NSLog(@"开始位置服务");
                  [NSThreadsleepForTimeInterval:1];
                  [locationManager stopUpdatingLocation];
                  NSLog(@"停止位置服务");
                  FlushBackgroundTime=false;
               }
               if(!isLogined)//未登录或者掉线状态下关闭后台
               {
                  NSLog(@"保持在线进程失效,退出后台进程");
                  [InterfaceFuncation ShowLocalNotification:@"保持在线失效,登录已被注销,请重新登录"];
                  [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
                  return;//退出循环
               }
               NSTimeIntervalbackgroundTimeRemaining = [[UIApplication sharedApplication] backgroundTimeRemaining];
               NSLog(@"Background Time Remaining = %.02f Seconds",backgroundTimeRemaining);
               if(backgroundTimeRemaining<30&&NoticeNoBackground==false)
               {
                   [InterfaceFuncation ShowLocalNotification:@"向系统申请长时间保持后台失败,请结束客户端重新登录"];
                   NoticeNoBackground=true;
               }
               //测试后台时间刷新
               if(backgroundTimeRemaining>200&&FlushBackgroundTime==false)
               {
                  [[NSNotificationCenterdefaultCenter] postNotificationName:@"MessageUpdate"object:@"刷新后台时间成功\n"];
                  FlushBackgroundTime=true;
                  //[InterfaceFuncation ShowLocalNotification:@"刷新后台时间成功"];
                }
            }
            self.jobExpired =NO;
         });
     }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索ios锁屏保持运行、,以便于您获取更多的相关知识。

时间: 2024-10-24 09:49:46

iOS如何保持程序在后台长时间运行_IOS的相关文章

C#的winform程序发布后,第一次运行很慢

问题描述 C#的winform程序发布后,第一次运行很慢,不关闭程序,等第二次运行的时候,速度就正常了.若关闭程序,重开,第一次运行也是如此...有人说是,预编译.是这样的吗?为啥会这样?有什么解决方法?求大神解答. 解决方案 解决方案二:可能在初次运行的时候读取了大量的数据到内存.解决方案三:引用1楼guwei4037的回复: 可能在初次运行的时候读取了大量的数据到内存. 没有啊,程序很小的,数据量也不大.解决方案四:引用1楼guwei4037的回复: 可能在初次运行的时候读取了大量的数据到内

程序奔溃-长时间运行程序出错问题

问题描述 长时间运行程序出错问题 写了一个C#的数据包解析上传的程序,主要逻辑是程序一直对某一端口进行监听(会有收集数据的硬件,并且端口号是手动输入),每当有数据来,就将数据经过xml文档格式进行解析出来,写入远程数据库.现在一直测试1周的情况下,会出现无法上传数据情况,那会用串口助手监听是有数据上传的.请问:如何解决? 解决方案 我以前碰到过这种情况,很可能是内存泄露,每次都有内存没释放,长时间积累就导致崩溃. 这是我用C++出现的情况,不知道对你有用没?

java应用程序放了一段时间后,再运行的时候出现了很多原本没有的错误。

问题描述 java应用程序放了一段时间后,再运行的时候出现了很多原本没有的错误. 我的一个Java写的带GUI的应用程序,打包到jar包中.原本可以运行,且没什么太大的问题.放了一段时间(期间没修改过,修改时间还显示最原始的时间),重新运行时,出现了很多本来没有的非常明显的错误(主要是在GUI上的错误).请高手帮忙指出可能哪里出问题了? 解决方案 那里那里那里那里那里那里

weblogic部署服务,c3po+hibernate应用,程序跑一段时间后内存溢出

问题描述 weblogic部署服务,c3po+hibernate应用,程序跑一段时间后内存溢出 Exception in thread "C3P0PooledConnectionPoolManager-Helper Thread-#0" java.lang.OutOfMemoryError: Java heap space at oracle.jdbc.driver.OracleStatement.prepareAccessors(OracleStatement.java:870) a

iOS单聊,程序杀死后,再启动,发送不出去消息。

问题描述 我在登陆的时候,没有设置自动登录,每次进入app的时候,我都会手动登录一下,但程序杀死后,再启动app不能发送消息. 解决方案 没有设置自动登录,杀死程序,再次进入的时候要做登录操作的,登录成功后才可以再次发送消息的

《企业级ios应用开发实战》一1.3 iOS企业应用程序的发布

1.3 iOS企业应用程序的发布 除了上述特点,iOS企业应用还有一个显著的特点,就是应用程序的发布方式.iOS企业应用具有两种发布方式:In-House和Ad-Hoc,它们并不经过苹果公司的App Store进行发布,而只是在企业内部进行发布.换句话说,不经过苹果商店的应用程序审核程序. 1.3.1 iOS应用程序发布与App Store 2008年3月6日苹果公司推出了iPhone的应用程序开发包(iPhone SDK),吸引了全世界的开发者.2008年7月11日,App Store正式上线

进入系统后长时间无反应

进入系统后长时间无反应 症状:启动刚进入系统界面时,点什么都打不开,要等一分钟左右才能打开. 解决办法: 一.首先,请升级杀毒软件的病毒库,全面杀毒,以排除病毒原因. 二.开始→运行,输入msconfig→确定.在打开的系统系统配置程序里,将一些不重要的服务以及启动程序关闭,重启电脑. 三.进入"我的电脑"--工具--文件夹选项--查看--取消"自动搜索网络文件夹和打印机"的勾选. 四.在Windows XP启动进入桌面后系统会暂时停滞一段时间,这时启动任何程序都会

使程序在用户长时间不操作时退出

原文:http://www.icodeblog.com/2011/09/19/timing-out-an-application-due-to-inactivity/ 概述 先讲讲原理.我创建了一个 UIApplication 的子类ELCUIApplication.目的是为了覆盖 sendEvent: 方法.这个方法在每次触摸时都会调用.触摸可能来自于按钮.文本框以至窗口内的任何东西. 在 sendEvent 方法中,首先调用 super 的方法(确保事件能被传递到它应该到达的地方),然后重置

用ExitWindows来写个程序并且能设置时间的,能让电脑到设置的时间就能自动关机的

问题描述 用ExitWindows来写个程序并且能设置时间的,能让电脑到设置的时间就能自动关机的 新手上路最好详细点,用ExitWindows来写个程序并且能设置时间的,能让电脑到设置的时间就能自动关机的 解决方案 用不着,直接调用Shutdown命令行(可以用ShellExecute或者Winexec) C:Windowssystem32>Shutdown Usage: Shutdown [/i | /l | /s | /r | /g | /a | /p | /h | /e | /o] [/h