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

Objective c 在应用程序处于后台时,在中断后恢复代码的执行,objective-c,ios,xcode,avaudioplayer,avaudiosession,Objective C,Ios,Xcode,Avaudioplayer,Avaudiosession,我花了几天的时间在SO和其他网站上寻找答案,但没有任何运气 本质上,我给自己设置的挑战是为iOS创建一个闹钟应用程序,无论用户在哪里(前台或后台),它都会发出声音。我已经通过使用AVAudioPlayer实例实现了这一点,当用户设置警报时,开始播放一个空的声音文件,以便应用程序在后台继续运行。当闹钟响起时(即NSTimer启动时),第二个已经启动并准备播放的播放器开始播放用户唤醒的铃声 此外,我还通过实现AVAudioSessionDelegate方法beginInterruption和endI

我花了几天的时间在SO和其他网站上寻找答案,但没有任何运气

本质上,我给自己设置的挑战是为iOS创建一个闹钟应用程序,无论用户在哪里(前台或后台),它都会发出声音。我已经通过使用AVAudioPlayer实例实现了这一点,当用户设置警报时,开始播放一个空的声音文件,以便应用程序在后台继续运行。当闹钟响起时(即NSTimer启动时),第二个已经启动并准备播放的播放器开始播放用户唤醒的铃声

此外,我还通过实现AVAudioSessionDelegate方法beginInterruption和endInterruptionWithFlags来处理电话、系统计时器或闹钟的中断。它可以在后台和前台模式下工作,但最奇怪的事情发生了:

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

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

以下是.h文件的代码:

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

@interface InterruptionTest3ViewController : UIViewController <AVAudioSessionDelegate,      AVAudioPlayerDelegate>
{
    AVAudioSession *mySession;
    AVAudioPlayer *myPlayer;
}

-(void) playPlayer;
-(void) pausePlayer;
-(void) tester;

@end
所以,这就是大家。再说一次,为什么当应用程序在后台时,计时器在中断后没有被触发?我需要在ApplicationIdentinterBackground方法中设置一些东西吗


非常感谢您!请使用“[NSTimer scheduledTimerWithTimeInterval:5.0目标:myPlayer选择器:@selector(stop)userInfo:nil repeats:NO]”

不是为了避免这个问题,但是在背景中播放空声音是一种攻击。提供在背景中播放声音的功能是为了让您可以播放音乐或其他声音,而不是为了让背景进程保持活力

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

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


如果我没记错的话,当你的应用程序进入后台时,计时器会被暂停或取消。文档中明确指出,当你的应用程序被中断时,即当它被发送到后台时,你应该暂停或取消计时器。

我理解你的担忧,Caleb,但是,据我所知,苹果在处理报警应用程序时往往更为宽容。T他认为UILocalNotification仅用于警告用户的问题对于我正在尝试创建的应用类型来说可能是无用的。我感兴趣的是,用户无法关闭或静音警报,除非他们进入应用中这样做。我不知道这是否是一个有价值的论点,但有些应用确实使用了“空”玩家在后台任务中保留他们的位置,他们似乎已经逃脱了。例如:“Timegg”和“Wake n Shake”。其他一些应用程序这样做并不意味着这不是黑客行为,他们进入应用商店也不意味着你的应用也会这样。用户应该负责应用,而不是反过来;试图强迫用户做某件事的应用程序设计得很差。创建一个用户想要的有吸引力、有用的应用程序要打开,而不是当设备在会议、剧院等场合拍打时需要10秒或更长时间才能打开。这样的体验会说服用户立即删除你的应用。苹果一周前在appStore上推出了Timegg。你可以验证它是否使用了“空音播放”黑客(原文如此)通过设置闹铃,移动到后台,从闹铃设置到闹铃响起之间的任何时刻,如果你试图改变音量,你改变的不是“铃声”音量,但应用程序的音量。此外,他们已经成功地完成了我的问题,即在一次重大中断后在后台恢复执行。谢谢你的回答,Yongbin,但我已经尝试过了,它没有完成我正在寻找的任务。
#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.