iOS - AVAudioPlayer doesn't continue to next song while in background

前端 未结 3 921
不知归路
不知归路 2020-12-14 23:45

So I have an app that plays a bunch of songs while the user can flip through a comic book. I use AVAudioPlayer and I have it set up to play the songs in a set order. So wh

相关标签:
3条回答
  • 2020-12-14 23:58

    OS X exhibits the same problem using AVAudioPlayer, however UIApplication is an iOS-only construct. OS X requires using NSApplication instead, but NSApplication doesn't return until the application is terminating so we need to use threads. As a bonus, there's an assert() somewhere in the depths of NSApplication that demands the main thread.

    This hybrid C++/Objective C function is one workaround for this OS X issue:

    void do_the_dumb (void real_application(void)) {
        std::thread thread ([real_application]() {
            real_application();
            [[NSApplication sharedApplication] terminate: [NSApplication sharedApplication]];
        });
        [[NSApplication sharedApplication] run];
        thread.join();
    };
    
    0 讨论(0)
  • 2020-12-15 00:00

    Relevant discussion

    SHORT ANSWER:

    You need this code in either your first view controller's init or viewDidLoad method:

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    

    LONG ANSWER W/ SAMPLE:

    Here is my example. Like you, I began with an app that would play music in the background but could never continue playing after the first clip ended. I made a copy of the original Music.mp3 and named it Music2.mp3. My intention was to play Music2.mp3 as soon as Music.mp3 ended (audioPlayerDidFinishPlaying:). I goofed around with the background tasks for awhile until I got this working WITHOUT the background task:

    -(id)init{
        self = [super initWithNibName:@"MediaPlayerViewController" bundle:nil];
        if(self){
    
            //Need this to play background playlist
            [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    
            //MUSIC CLIP
            //Sets up the first song...
            NSString *musicPath = [[NSBundle mainBundle] pathForResource:@"Music" ofType:@"mp3"];
            if(musicPath){
                NSURL *musicURL = [NSURL fileURLWithPath:musicPath];
                audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil]; 
                [audioPlayer setDelegate:self];
            }
        }
        return self;
    }
    
    
    -(IBAction)playAudioFile:(id)sender{
    
        if([audioPlayer isPlaying]){
            //Stop playing audio and change test of button
            [audioPlayer stop];
            [sender setTitle:@"Play Audio File" forState:UIControlStateNormal];
        }
        else{
            //Start playing audio and change text of button so
            //user can tap to stop playback
            [audioPlayer play];
            [sender setTitle:@"Stop Audio File" forState:UIControlStateNormal];
        }
    }
    
    
    -(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
        [audioButton setTitle:@"Play Audio File" forState:UIControlStateNormal];
        [playRecordingButton setTitle:@"Play Rec File" forState:UIControlStateNormal];
    
        //PLAY THE SECOND SONG
        NSString *musicPath2 = [[NSBundle mainBundle] pathForResource:@"Music2" ofType:@"mp3"];
        if(musicPath2){
    
            NSURL *musicURL2 = [NSURL fileURLWithPath:musicPath2];
            audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL2 error:nil];
            [audioPlayer setDelegate:self];
            NSLog(@"Play it again: \n%@", musicPath2);
            [audioPlayer play];
        } 
    }
    

    The end result is that my app is now playing Music2.mp3 on a continuous loop, even if the app is in the background.

    0 讨论(0)
  • 2020-12-15 00:12

    Just to confirm what Squatch said, this is also the solution in Swift:

    UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
    
    0 讨论(0)
提交回复
热议问题