应用程序处于后台时,在中断后恢复执行代码

我花了几天时间研究SO和其他网站以获得答案,但没有任何运气。

从本质上讲,我为自己设定的挑战是为iOS创建一个闹钟应用程序,无论用户身在何处(前景或背景)都会发出声音。 我已经通过使用AVAudioPlayer实例并在用户设置警报时开始播放空声音文件,以便应用程序在后台继续运行。 当闹钟响起时(即当NSTimer被解雇时),已经启动并准备播放的第二个播放器开始播放用户醒来的铃声。

此外,我通过实现AVAudioSessionDelegate方法beginInterruption和endInterruptionWithFlags设法通过电话,系统计时器或闹钟来处理中断。 它适用于后台和前台模式,但最奇怪的事情发生在:

当中断结束时,AVAudioPlayer继续播放但是我无法在我的应用程序中执行任何其他代码,除非我再次将应用程序带到前台。

为了深究这一点,我尝试了一个更简单的项目,我将在下面发布。 这个应用程序的作用是,一旦你进入应用程序,AVAudioPlayer类的一个实例开始循环某个声音。 然后当你把它带到后台时,播放器继续循环播放声音。 当中断发生时我暂停播放器,当它结束时我使用一个调度等待几秒钟才调用两个方法,即(void)playPlayer,一个包含恢复播放文件的代码的方法和(void)测试器,一种包含计时器的方法,该计时器设置为在中断后5秒钟停止播放器(或准确地说是7秒)。 两个方法都被调用,如我在其中放入的NSLog所指示的那样,但是计时器永远不会被触发,玩家将继续无限期地播放。

这是.h文件的代码:

#import  #import  #import  @interface InterruptionTest3ViewController : UIViewController  { AVAudioSession *mySession; AVAudioPlayer *myPlayer; } -(void) playPlayer; -(void) pausePlayer; -(void) tester; @end 

这是.m文件的代码:

 #import "InterruptionTest3ViewController.h" @interface InterruptionTest3ViewController () @end @implementation InterruptionTest3ViewController - (void)viewDidLoad { [super viewDidLoad]; mySession = [AVAudioSession sharedInstance]; NSError *setActiveError = nil; [mySession setActive:YES withFlags:AVAudioSessionSetActiveFlags_NotifyOthersOnDeactivation error:&setActiveError]; if (setActiveError) { NSLog(@"Session failed to activate within viewDidLoad"); } else { NSLog(@"Session was activated within viewDidLoad"); } NSError *setCategoryError = nil; [mySession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError]; if (setCategoryError) { NSLog(@"Category failed to be set"); } else { NSLog(@"Category has been set"); } [mySession setDelegate:self]; NSString *path = [[NSBundle mainBundle] pathForResource:@"headspin" ofType:@"wav"]; NSError *initMyPlayerError = nil; myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&initMyPlayerError]; if (initMyPlayerError) { NSLog(@"myPlayer failed to initiate"); } else { NSLog(@"myPlayer has been initiated"); } [myPlayer prepareToPlay]; [self playPlayer]; OSStatus propertySetError = 0; UInt32 allowMixing = true; propertySetError = AudioSessionSetProperty ( kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof (allowMixing), &allowMixing ); [myPlayer setNumberOfLoops:-1]; [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; } -(void) beginInterruption { [myPlayer pause]; } -(void) endInterruptionWithFlags:(NSUInteger)flags { if (flags) { if (AVAudioSessionInterruptionFlags_ShouldResume) { { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC),dispatch_get_main_queue(), ^{ [self playPlayer]; [self tester]; }); } } } } -(void) tester { [NSTimer timerWithTimeInterval:5.0 target:self selector:@selector(pausePlayer) userInfo:nil repeats:NO]; NSLog(@"tester method has been called"); } -(void) playPlayer { [NSTimer timerWithTimeInterval:5.0 target:myPlayer selector:@selector(stop) userInfo:nil repeats:NO]; [myPlayer play]; NSLog(@"playPlayer method has been called"); } -(void) pausePlayer { [myPlayer pause]; } //viewDidUnload etc not listed. 

所以,这就是人们。 同样,为什么在应用程序处于后台时中断后计时器没有被触发? 我是否需要在applicationDidEnterBackground方法中设置一些内容?

非常感谢你提前!

请使用“[NSTimer scheduledTimerWithTimeInterval:5.0 target:myPlayer selector:@selector(stop)userInfo:nil repeats:NO]”;

不要回避这个问题,但是在背景中播放空洞的声音是一个黑客攻击。 提供在后台播放声音的function,以便您可以播放音乐或其他声音,以保证用户的利益,而不是让后台进程保持活动状态。

如果您想在特定时间播放声音或以其他方式提醒用户,请考虑使用本地通知 。

为什么在应用程序处于后台时中断后计时器没有被触发?

如果我没记错的话,当您的应用进入后台时,计时器会被暂停或取消。 文档明确指出,当应用程序中断时,即当它被发送到后台时,您应该“停止计时器和其他周期性任务” 。