先介绍一下网上比较多的一种解决方案:
在AppDelegate或NSTimer定义的地方加入如下代码,实现让App进入后台NSTimer继续计时:
UIApplication* app = [UIApplication sharedApplication];
self.bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
经测试发现当app进入后台的确能正常计时, 这种方法有什么问题呢?
- 这个是苹果官方提供的一种方法,最多只能维持app在后台10分钟。超过了时间NSTimer一样会停止,起不到无限计时的作用。
- 经测试在iOS9上只能维持1-2分钟。
下面来看一下iOS提供的5中后台无限运行模式:
- 播放音频-----应用程序可以在后台持续的播音或者录音。
- 接收位置更新-----随着设备位置的变化应用程序要持续获得地理位置更新。
- 执行有限长度的任务----在有限的时间内,无论任何情况下应用程序都可以执行任何代码。
- 正在下载杂志-----杂志类应用特例,应用程序能够在后台下载
- 提供voip(voice-over-ip)服务---应用程序能够在后台执行任意的代码,当然苹果会限制它的用途,你的应用必须提供voip服务。
我们要实现NSTimer无限计时就必须要借助这5种模式中的一种, 下面我们就以播放音频为例来说明。
-
在Info.plist中配置权限。
- 导入AVFoundation库,在AppDelegate中加入以下代码:
@property(nonatomic, strong) AVAudioPlayer *audioPlayer;
@property(nonatomic, assign) UIBackgroundTaskIdentifier bgTask;
-(void)applicationDidEnterBackground:(UIApplication *)application{
UIApplication* app = [UIApplication sharedApplication];
self.bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(applyForMoreTime) userInfo:nil repeats:YES];
}
-(void)applyForMoreTime {
if ([UIApplication sharedApplication].backgroundTimeRemaining < 30) {
NSURL *filePathUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"1" ofType:@"wav"]];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:filePathUrl error:nil];
[self.audioPlayer play];
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
self.bgTask = UIBackgroundTaskInvalid;
}];
}
}
经测试上述代码能保证NSTimer在后台无限计时了。
github代码下载地址: here