我正在使用[MPMusicPlayerController applicationMusicPlayer]播放Apple Music。 (AVPlayer和AVAudioPlayer不适用于Apple Music。)
在后台,我需要知道这首歌何时结束,这样我才能播放下一首歌。不幸的是,当应用程序在后台时,MPMusicPlayerControllerPlaybackStateDidChangeNotification不会被触发。
所以我使用beginBackgroundTaskWithExpirationHandler创建了一个后台任务,它每秒触发一次NSTimer来检查歌曲的结尾。我设置了音频后台模式,但我的任务仍然只有3分钟。我的理解是,如果我使用音频背景模式,我的任务将获得无限的时间。这不是真的吗?如果没有,我该如何处理?当然其他人也遇到过这种情况。
答案 0 :(得分:2)
供将来参考:
我发现MPMusicPlayerController从不使用applicationMusicPlayer或systemMusicPlayer来使用音频UIBackgroundMode。所以你的背景时间永远不会超过3分钟。但是,AVAudioPlayer会加入音频背景模式。所以我的(丑陋)解决方案是在后台使用AVAudioPlayer循环播放静音MP3。我将假设Apple不会抗议,这似乎是合法使用无声音频。请注意,要同时播放AVAudioPlayer和MPMusicPlayerController,您必须为AVAudioSession设置AVAudioSessionCategoryOptionMixWithOthers。
答案 1 :(得分:0)
我在AppStore中发布了几乎相同的应用程序。 它使用[MPMusicPlayerController applicationMusicPlayer]播放歌曲。
是的,MPMusicPlayerControllerPlaybackStateDidChangeNotification没有来到后台应用程序。 所以,我使用NSTimer确定歌曲何时结束。 您将NSTimer设置为1秒。我将NSTimer设置为歌曲播放时间段。即当歌曲有3分15秒的时间时,我将NSTimer设置为3分15秒。
当用户暂停音乐时,我会暂停NSTimer。 当用户恢复音乐时,我将NSTimer设置为歌曲的休息时间。
效果很好。 我希望这可以帮到你。 对不起我的英语。
您可能需要的步骤;
- (void)applicationWillResignActive:(UIApplication *)application { _bgid = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^(void) { [[UIApplication sharedApplication] endBackgroundTask:_bgid]; _bgid = UIBackgroundTaskInvalid; }]; } - (void)applicationDidBecomeActive:(UIApplication *)application { if ( _bgid != UIBackgroundTaskInvalid ) { [[UIApplication sharedApplication] endBackgroundTask:_bgid]; } }
3.在非重复模式下使用NSTimer。
#import "NMCountdownTimer.h" @interface NMCountdownTimer () { @private NSTimer *_timer; NSTimeInterval _rest; NMMethodCompletion _completion; } @end @implementation NMCountdownTimer - (void)start:(NSTimeInterval)secs completion:(NMMethodCompletion _Nullable)completion { _completion = completion; if ( secs > 0.0f ) { NSLog(@"[ ] start (secs:%f)", secs); _timer = [NSTimer scheduledTimerWithTimeInterval:secs target:self selector:@selector(fired) userInfo:nil repeats:FALSE]; _rest = 0.0f; } } - (void)pause { if ( _timer && ( _rest == 0.0f ) ) { _rest = [[_timer fireDate] timeIntervalSinceReferenceDate] - [[NSDate date] timeIntervalSinceReferenceDate]; NSLog(@"[ ] pause (rest:%f)", _rest); [_timer invalidate]; _timer = nil; } } - (void)resume { if ( ( ! _timer ) && ( _rest > 0.0f ) ) { NSLog(@"[ ] resume (rest:%f)", _rest); _timer = [NSTimer scheduledTimerWithTimeInterval:_rest target:self selector:@selector(fired) userInfo:nil repeats:FALSE]; _rest = 0.0f; } } - (void)kill { [_timer invalidate]; _timer = nil; _rest = 0.0f; _completion = nil; NSLog(@"[ ] kill"); } - (void)fired { [_timer invalidate]; _timer = nil; _rest = 0.0f; if ( _completion ) { _completion ( nil ); } NSLog(@"[ ] fired"); } - (void)dealloc { #if ( Namera_SHOW_DEALLOC && FALSE ) NSLog(@"[DEA] %@ NMCountdownTimer", self ); #endif _timer = nil; _completion = nil; } @end
somewhere in your code like this; NSTimeInterval playback_duration = [[song valueForProperty: MPMediaItemPropertyPlaybackDuration] doubleValue]; .... MPMediaItemCollection *collection = [MPMediaItemCollection collectionWithItems:[NSArray arrayWithObject:song]]; [_musicCtr setQueueWithItemCollection:collection]; [_musicCtr play]; [_countdown_timer start:playback_duration completion:^(id _Nullable object) { [weakSelf execute_next_song]; }];