在后台播放Apple音乐

时间:2017-06-21 23:48:16

标签: ios audio mpmusicplayercontroller

我正在使用[MPMusicPlayerController applicationMusicPlayer]播放Apple Music。 (AVPlayer和AVAudioPlayer不适用于Apple Music。)

在后台,我需要知道这首歌何时结束,这样我才能播放下一首歌。不幸的是,当应用程序在后台时,MPMusicPlayerControllerPlaybackStateDidChangeNotification不会被触发。

所以我使用beginBackgroundTaskWithExpirationHandler创建了一个后台任务,它每秒触发一次NSTimer来检查歌曲的结尾。我设置了音频后台模式,但我的任务仍然只有3分钟。我的理解是,如果我使用音频背景模式,我的任务将获得无限的时间。这不是真的吗?如果没有,我该如何处理?当然其他人也遇到过这种情况。

2 个答案:

答案 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设置为歌曲的休息时间。

效果很好。 我希望这可以帮到你。 对不起我的英语。

您可能需要的步骤;

  1. 在功能设置中设置音频背景模式。 (你做完了)
  2. 在App Delegate中使用beginBackgroundTaskWithExpirationHandler。
  3.     - (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];
        }];