2012-03-12 139 views
10

因此,我有一個應用程序,播放一串歌曲,而用戶可以翻閱漫畫書。我使用AVAudioPlayer,並且設置了按照設定的順序播放歌曲。所以當一首歌完成時,下一首將會播放。當應用程序打開時,此功能完美無瑕。當應用程序在後臺時發生問題。我將應用程序設置爲在後臺播放,而且工作正常。所以當用戶按下主屏幕時,音樂繼續播放。問題發生在歌曲結束時,它應該像打開應用時播放下一首歌一樣。相反沒有任何反應根據我的NSLog語句正確的方法被調用,但沒有任何反應。這是我的代碼:iOS - AVAudioPlayer不會在後臺繼續播放下一首歌曲

- (void)audioPlayerDidFinishPlaying: (AVAudioPlayer *)player successfully: (BOOL) flag { 

NSLog(@"Song finished"); 

if ([songSelect isEqualToString: @"01icecapades"]) { 
    isPlay = @"yes"; 
    songSelect = @"02sugarcube"; 
    imageSelect = @"playbanner02"; 
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; 
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; 
} 
else if ([songSelect isEqualToString: @"02sugarcube"]) { 
    isPlay = @"yes"; 
    songSelect = @"03bullets"; 
    imageSelect = @"playbanner03"; 
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; 
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; 
} 
else if ([songSelect isEqualToString: @"03bullets"]) { 
    isPlay = @"yes"; 
    songSelect = @"04satanama"; 
    imageSelect = @"playbanner04"; 
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; 
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; 
} 
else if ([songSelect isEqualToString: @"04satanama"]) { 
    isPlay = @"yes"; 
    songSelect = @"05uglyjoke"; 
    imageSelect = @"playbanner05"; 
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; 
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; 
} 
else if ([songSelect isEqualToString: @"05uglyjoke"]) { 
    isPlay = @"yes"; 
    songSelect = @"01icecapades"; 
    imageSelect = @"playbanner01"; 
    [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; 
    [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; 
}} 

上面是識別哪首歌正在播放,然後設置正確的歌曲的代碼。然後觸發另一種設置播放器的方法。

- (void)triggerSong { 
NSLog(@"triggerSong called"); 
NSString  *path; 
NSError  *error; 
// Path the audio file 
path = [[NSBundle mainBundle] pathForResource:songSelect ofType:@"mp3"]; 
// If we can access the file... 
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) 
{  
    // Setup the player 
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; 
    //player = [initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; 
    [player setDelegate: self]; 
    // Set the volume (range is 0 to 1) 
    player.volume = 1.0f;  
    [player prepareToPlay]; 
    [player setNumberOfLoops:0]; 
    [player play]; 
    NSLog(@"player play"); 
    [error release]; 
    player.delegate = self; 
    // schedules an action every second for countdown 
    [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateTimeLeft) userInfo:nil repeats:YES]; 
}} 

現在我假設這不是最好的方式來做到這一點,但它應用程序處於前景狀態時效果很好。我一直在查看文檔,我似乎無法找到造成這個問題的原因。我希望有人能夠看到我的方法有錯誤。就像我之前說過的,triggerSong方法中的兩個NSLogs被調用,所以我不明白爲什麼AVAudioPlayer(播放器)沒有被調用。

我也有我的info.plist正確的設置,我有這個在我viewDidLoad中:

//Make sure the system follows our playback status 
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; 
[[AVAudioSession sharedInstance] setActive: YES error: nil]; 

感謝任何見解。非常感激。

回答

26

Relevant discussion

簡短的回答:

你需要這個代碼或者您的第一個視圖控制器的初始化或viewDidLoad方法:

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; 

長的答案W /示例:

這是我的例子。和你一樣,我從一個可以在後臺播放音樂的應用程序開始,但在第一個剪輯結束之後無法繼續播放。我製作了原始Music.mp3的一個副本,並將其命名爲Music2.mp3。我的意圖是在Music.mp3結束後立即播放Music2.mp3(audioPlayerDidFinishPlaying :)。我與後臺任務瘋玩了一段時間,直到我得到這個工作沒有後臺任務:

-(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]; 
    } 
} 

最終的結果是,我的應用程序現在開始連續循環播放Music2.mp3,即使該應用程序是的背景。

+0

你是最棒的!非常感謝。它工作完美。 – 2012-03-16 02:40:36

+0

沒問題!祝你好運。 – Squatch 2012-03-16 12:23:46

+1

FYI ..你的鏈接是錯誤的...它應該是https://devforums.apple.com/message/264397 – 2013-12-02 06:00:05

4

只是爲了確認哪些Squatch說,這也是雨燕的解決方案:

UIApplication.sharedApplication().beginReceivingRemoteControlEvents() 
0

OS X使用表現出的AVAudioPlayer同樣的問題,但是UIApplication的是一款iOS只構建。 OS X需要使用NSApplication,但NSApplication不會返回,直到應用程序終止,因此我們需要使用線程。作爲獎勵,在NSApplication的深處有一個assert()需要主線程。

這種混合C++/Objective C的功能是爲這個OS X的問題,一個解決辦法:

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(); 
}; 
相關問題