beginBackgroundTaskWithExpirationHandler

12.2.2. 方案 

使用UIApplicationbeginBackgroundTaskWithExpirationHandler: 实例方法。在你完成任务后,调用UIApplicationendBackgroundTask:方法。 

12.2.3. 讨论 

当一个iOS应用被送到后台,它的主线程会被暂停。你用NSThreaddetachNewThreadSelector:toTar get:withObject:类方法创建的线程也被挂起了。如果你想在后台完成一个长期任务,就必须调用UIApplicationbeginBackgroundTaskWithExpirationHandler:实例方法,来向iOS借点时间。UIApplicationbackgroundTimeRemaining属性包含了程序完成他的任务可以使用的秒数。如果在这个期限内,长期任务没有被完成,iOS将终止程序。每个对beginBackgroundTaskWithExpirationHandler:方法的调用,必须要相应的调用endBackgroundTask:方法(UIApplication的另一个实例方法)。也就是说,如果你向iOS要更多时间来完成一个任务,你必须告诉iOS你什么时候能完成那个任务,那时,你的程序将iOS 5 Programming Cookbookwww.devdiv.com 翻译整理 

DevDiv 翻译:kyelup cloudhsu 耐心摩卡 wangli2003j3 xiebaochun dymx101 jimmylianf BeyondVincent 20DevDiv 校对:laigb kyelup DevDiv 编辑:BeyondVincent 版本 1.0 | 2012  07  30 日 


和其所有被暂停的线程被放入后台。 

当你的程序在前台时,UIApplicationbackgroundTimeRemaining属性等于DBL_MAX常量,这是double类型可表示的最大值(和这个值相当的integer通常等于-1)。在iOS被要求在程序被完全挂起之前给于更多的执行时间,这个属性指明了在完成任务前程序拥有多少秒。 

在程序中你可以多次调用beginBackgroundTaskWithExpirationHandler:方法。要记住的重点是,当iOS为你的程序返回一个token或者任务标识(task identifier)时,你都必须调用endBackgroundTask:方法,在运行的任务结束时,用来标志任务结束。如果你不这么做的话,iOS会终止你的程序。 

在后台时,程序不应该执行完全的功能,也不应该处理大量数据。事实上,他们只应该完成一个长期任务。 

比如,一个程序正在调用一个web service API,并且还没有从服务器上的那个API接收到响应。在此期间,如果程序被送入后台,它可以请求更多的时间,直到它从服务器收到响应。一旦响应被接收,程序必须保存其状态,并调用UIApplicationendBackgroundTask:实例方法将任务标记为完成。 

让我们看一个例子。我将从在应用程序委托中定义一个UIBackgroundTaskIdentifier类型的属性开始。同时,让我们定义一个NSTimer,当程序被送到后台时,我们将用它每隔1秒向控制台窗口输出一条消息: 

#import <UIKit/UIKit.h> 

@interface Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate : UIResponder <UIApplicationDelegate> 

@property (nonatomic, strong) UIWindow *window; 

@property (nonatomic, unsafe_unretained) UIBackgroundTaskIdentifier backgroundTaskIdentifier

@property (nonatomic, strong) NSTimer *myTimer; 

@end 

接下来我们继续同步属性: 

#import "Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate.h" @implementation Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate 

@synthesize window = _window; 

@synthesize backgroundTaskIdentifier; @synthesize myTimer; 

现在,让我们创建定时器,并在程序被送到后台时启动它: 

- (BOOL) isMultitaskingSupported{ 

BOOL result = NO; 

if ([[UIDevice currentDevice] 

respondsToSelector:@selector(isMultitaskingSupported)]){ result = [[UIDevice currentDevice] isMultitaskingSupported]; 

return result; 

- (void) timerMethod:(NSTimer *)paramSender{ 

NSTimeInterval backgroundTimeRemaining = 

[[UIApplication sharedApplication] backgroundTimeRemaining]; 

if (backgroundTimeRemaining == DBL_MAX){ NSLog(@"Background Time Remaining = Undetermined"); 

} else { iOS 5 Programming Cookbook www.devdiv.com 翻译整理 

DevDiv 翻译:kyelup cloudhsu 耐心摩卡 wangli2003j3 xiebaochun dymx101 jimmylianf BeyondVincent 21DevDiv 校对:laigb kyelup DevDiv 编辑:BeyondVincent 版本 1.0 | 2012  07  30 日 


NSLog(@"Background Time Remaining = %.02f Seconds", 

backgroundTimeRemaining); 

} } 

- (void)applicationDidEnterBackground:(UIApplication *)application{ 

if ([self isMultitaskingSupported] == NO){ 

return; } 

self.myTimer = 

[NSTimer scheduledTimerWithTimeInterval:1.0f 

target:self 

selector:@selector(timerMethod:) userInfo:nil 

repeats:YES]; 

self.backgroundTaskIdentifier = 

[application beginBackgroundTaskWithExpirationHandler:^(void) { [self endBackgroundTask]; 

}]; } 

你可以看到,在后台任务的完成处理者(completion handler)中,我们调用了应用程序委托的endBackgroundTask方法。这是一个我们编写的方法,如下: 

- (void) endBackgroundTask{ 

dispatch_queue_t mainQueue = dispatch_get_main_queue(); 

__weak Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate *weakSelf = self; 

dispatch_async(mainQueue, ^(void) { 

Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate *strongSelf = weakSelf; 

if (strongSelf != nil){ 

[strongSelf.myTimer invalidate]; 

[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier]; 

strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid; } 

}); } 

在长期任务结束后,我们需要做一些事情进行清理: 

1. 结束所有的线程和定时器,不管他们是基础定时器还是GCD中创建的。 

2.调用UIApplicationendBackgroundTask:方法来结束后台任务。 

3.将任务标识设置为UIBackgroundTaskInvalid,标志我们的任务结束。 

最后,当我们的应用回到前台,如果我们的后台任务还在执行中,我们需要确保我们在干掉它: 

- (void)applicationWillEnterForeground:(UIApplication *)application{ 

if (self.backgroundTaskIdentifier != UIBackgroundTaskInvalid){ 

[self endBackgroundTask]; } 

在我们的例子中,不论何时程序被送到后台,我们都会要求更多时间以完成一个长期任务(例如,在这里是我们计时器的代码)。在我们的时间里,我们不断的读取UIApplication实例中backgroundTimeRemaining属性的值,将它打印到控制台。在UIApplicationbeginBackgroundTask WithExpirationHandler: 实例方法中,在程序的额外时间内完成一个长期任务之前,我们提供的代码将被执行(一版大概在任务过期前510秒)。在此,我们只要调用UIApplicationendBackgroundTask:实例方法来结束任务









做了一个产品,需要人气支持一下,android和iphone上91市场搜索#super junior粉丝团#,或者直接到页面下载http://m.ixingji.com/m.html?p=X16,大家帮忙捧捧场


官方文档:http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

中文的好文章

http://www.devdiv.com/thread-47004-1-1.html

http://www.cnblogs.com/haipingwu/archive/2011/03/18/1987962.html

 iOS4 请求更多后台时间

http://blog.csdn.net/zhangao0086/article/details/6739266


在IOS后台执行是本文要介绍的内容,大多数应用程序进入后台状态不久后转入暂停状态。在这种状态下,应用程序不执行任何代码,并有可能在任意时候从内存中删除。应用程序提供特定的服务,用户可以请求后台执行时间,以提供这些服务。

判断是否支持多线程

[html]  view plain copy
  1. <span style="font-size:16px;">UIDevice* device = [UIDevice currentDevice];    
  2. BOOL backgroundSupported = NO;    
  3. if ([device respondsToSelector:@selector(isMultitaskingSupported)])    
  4. backgroundSupported = device.multitaskingSupported; </span>  

声明你需要的后台任务

Info.plist中添加UIBackgroundModes键值,它包含一个或多个string的值,包括

audio:在后台提供声音播放功能,包括音频流和播放视频时的声音

location:在后台可以保持用户的位置信息

voip:在后台使用VOIP功能

前面的每个value让系统知道你的应用程序应该在适当的时候被唤醒。例如,一个应用程序,开始播放音乐,然后移动到后台仍然需要执行时间,以填补 音频输出缓冲区。添加audio键用来告诉系统框架,需要继续播放音频,并且可以在合适的时间间隔下回调应用程序;如果应用程序不包括此项,任何音频播放 在移到后台后将停止运行。

除了添加键值的方法,IOS还提供了两种途径使应用程序在后台工作:

Task completion—应用程序可以向系统申请额外的时间去完成给定的任务

Local notifications—应用程序可以预先安排时间执行local notifications 传递

实现长时间的后台任务

应用程序可以请求在后台运行以实现特殊的服务。这些应用程序并不连续的运行,但是会被系统框架在合适的时间唤醒,以实现这些服务

1.追踪用户位置:略

2.在后台播放音频:

[html]  view plain copy
  1. 1. //后台播放  
  2. AVAudioSession *session = [AVAudioSession sharedInstance];  
  3. [session setActive:YES error:nil];  
  4. [session setCategory:AVAudioSessionCategoryPlayback error:nil];  
  5.   
  6. 2. 让后台可以处理多媒体的事件  
  7. [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];  
  8. Remote-control events originate as commands issued by headsets and external accessories that are intended to control multimedia presented by an application. To stop the reception of remote-control events, you must call endReceivingRemoteControlEvents.  
  9.   
  10. 3.系统进入后台运行时,让程序可以运行一段时间。使用此方法争取一定的时间,在程序进入后台后处理一些事情。  
  11. - (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^)(void))handler  
  12. This method lets your application continue to run for a period of time after it transitions to the background.  
  13. your application could call this method to ensure that had enough time to transfer an important file to a remote server or at least attempt to make the transfer and note any errors. You should not use this method simply to keep your application running after it moves to the background.  


3.实现VOIP应用:


在后台完成有限长度的任务

官方文档http://developer.apple.com/library/iOS/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

在被终止之前的任意时间,应用程序会调用beginBackgroundTaskWithExpirationHandler:方法让系统给出额外 的时间来完成一些需要在后台长时间执行的任务。(UIApplication的backgroundTimeRemaining属性包含程序运行的总时 间)

可以使用task completion去保证那些比较重要但是需要长时间运行的程序不会由于用户切入后台而突然关闭。比如,你可以用这项功能来将用户的信息保存到disk上或者从网络下载一个重要的文件。有两种方式来初始化这样的任务:

1、将长时间运行的重要任务用beginBackgroundTaskWithExpirationHandler:和endBackgroundTask:包装。这样就在程序突然切入后台的时候保护了这些任务不被中断。

2、当你的应用程序委托applicationDidEnterBackground:方法被调用时再启动任务

中的两个方法必须是一一对应的,endBackgroundTask:方法告诉系统任务已经完成,程序在此时可以被终止。由于应用程序只有有限的时 间去完成后台任务,你必须在超时或系统将要终止这个程序之前调用这个方法。为了避免被终止,你也可以在一个任务开始的时候提供一个expiration handler和endBackgroundTask:方法。(可以查看backgroundTimeRemaining属性来确定还剩多少时间)。

一个程序可以同时提供多个任务,每当你启动一个任务的时候,beginBackgroundTaskWithExpirationHandler: 方法将返回一个独一无二的handler去识别这个任务。你必须在endBackgroundTask:方法中传递相同的handler来终止该任务。

[html]  view plain copy
  1. Listing 4-2 Starting a background task at quit time    
  2. - (void)applicationDidEnterBackground:(UIApplication *)application    
  3. {    
  4. UIApplication* app = [UIApplication sharedApplication];    
  5. bgTask = [app beginBackgroundTaskWithExpirationHandler:^{    
  6. [app endBackgroundTask:bgTask];    
  7. bgTask = UIBackgroundTaskInvalid;    
  8. }];    
  9. // Start the long-running task and return immediately.    
  10. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,    
  11. 0), ^{    
  12. // Do the work associated with the task.    
  13. [app endBackgroundTask:bgTask];    
  14. bgTask = UIBackgroundTaskInvalid;    
  15. });    
  16. }   

上述例子中,bgTask变量是一个类的成员变量,存储着指向该后台任务标示的指针。

在expriation handler中,可以添加关闭任务所需的代码。尽管如此,加入的代码不能执行太长的时间,当expriation handler被调用的时候,该程序已经非常接近被关闭,所以只有极短的时间来清除状态信息并终止任务。

安排Local Notification的传递

UILocalNotification类提供了一种方法来传递local notifications。和push notifications需要设置remote server不同,local notifications 在程序中安排并在当前的设备上执行。满足如下条件可以使用该能力:

1、一个基于时间的程序,可以在将来特定的时间让程序post 一个alert,比如闹钟

2、一个在后台运行的程序,post 一个local notification去引起用户的注意

为了安排local notification 的传递,需要创建一个UILocalNotification的实例,并设置它,使用UIApplication类方法来安排它。Local notification对象包含了所要传递的类型(sound,alert,或者badge)和时间何时呈现) 。UIApplication类方法提供选项去确定是立即传递还是在指定的时间传递

[html]  view plain copy
  1. Listing 4-3 Scheduling an alarm notification    
  2. - (void)scheduleAlarmForDate:(NSDate*)theDate    
  3. {    
  4. UIApplication* app = [UIApplication sharedApplication];    
  5. NSArray* oldNotifications = [app scheduledLocalNotifications];    
  6. // Clear out the old notification before scheduling a new one.    
  7. if ([oldNotifications count] > 0)    
  8. [app cancelAllLocalNotifications];    
  9. // Create a new notification.    
  10. UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease];    
  11. if (alarm)    
  12. {    
  13. alarm.fireDate = theDate;    
  14. alarm.timeZone = [NSTimeZone defaultTimeZone];    
  15. alarm.repeatInterval = 0;    
  16. alarm.soundName = @"alarmsound.caf";    
  17. alarm.alertBody = @"Time to wake up!";    
  18. [app scheduleLocalNotification:alarm];    
  19. }    
  20. }   


(可以最多包含128个 local notifications active at any given time, any of which can be configured to repeat at a specified interval.)如果在调用该notification的时候,程序已经处于前台,那么 application:didReceiveLocalNotification:方法将取而代之。

小结:关于详解在IOS后台执行的内容介绍完了,希望本文对你有所帮助


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Uniapp 是一个跨平台的应用开发框架,需要在不同的平台上实现后台定位保活可能会有些不同。一般来说,在 Android 平台上可以通过 Service 实现后台定位保活,而在 iOS 平台上则需要使用后台任务和后台模式。 在 Android 平台上,可以创建一个 Service,在其中开启一个线程进行定位,保证定位服务一直在后台运行。同时,需要在 AndroidManifest.xml 文件中申明该 Service 的启动方式为 START_STICKY,这样当系统回收资源时,会自动重新启动该 Service。 在 iOS 平台上,需要使用后台任务和后台模式来实现后台定位保活。可以使用 Core Location 框架来实现定位功能,在开启定位时,需要在 Info.plist 文件中加入 NSLocationAlwaysUsageDescription 权限申明,以获取后台定位权限。同时,需要在 AppDelegate.m 文件中申明后台任务和后台模式,例如: ``` - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 启用后台任务和后台模式 [self enableBackgroundTaskAndMode]; return YES; } - (void)enableBackgroundTaskAndMode { // 申明后台任务 self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [self endBackgroundTask]; }]; // 申明后台模式 CLLocationManager *locationManager = [[CLLocationManager alloc] init]; [locationManager setAllowsBackgroundLocationUpdates:YES]; } ``` 需要注意的是,在 iOS 平台上,由于苹果的限制,后台定位保活可能会被系统杀掉,因此需要在代码中添加相应的处理逻辑,例如重新开启定位等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值