2017-06-21 7 views
1

Ich spiele Apple Music mit [MPMusicPlayerController applicationMusicPlayer]. (AVPlayer und AVAudioPlayer funktionieren nicht für Apple Music.)Apple Music im Hintergrund abspielen

Während ich im Hintergrund bin, muss ich wissen, wann das Lied beendet ist, damit ich das nächste Lied spielen kann. Leider wird MPMusicPlayerControllerPlaybackStateDidChangeNotification nicht ausgelöst, während sich die App im Hintergrund befindet.

Also habe ich einen Hintergrund-Task erstellt, der beginBackgroundTaskWithExpirationHandler verwendet, der einmal pro Sekunde ein NSTimer absetzt, um nach dem Ende des Songs zu suchen. Ich habe den Audio-Hintergrund-Modus eingestellt, aber meine Aufgabe dauert nur 3 Minuten. Es war mein Verständnis, dass, wenn ich den Audio-Hintergrund-Modus nutze, meine Aufgabe unendlich lange dauern würde. Ist das nicht wahr? Wenn nicht, wie gehe ich damit um? Sicherlich sind andere auf diese Situation gestoßen.

Antwort

0

Ich habe fast die gleiche App im AppStore veröffentlicht. Er spielt Songs mit [MPMusicPlayerController applicationMusicPlayer].

Ja, MPMusicPlayerControllerPlaybackStateDidChangeNotification ist nicht im Hintergrund App. Also habe ich den NSTimer benutzt, um zu bestimmen, wann der Song beendet sein könnte. Sie setzen NSTimer auf 1sec. Ich habe NSTimer auf die Spielzeit des Songs eingestellt. wenn das Lied 3 Minuten 15 Sekunden Zeit hat, setze ich den NSTimer auf 3 Minuten 15 Sekunden.

Wenn der Benutzer die Musik pausiert, pausiere ich den NSTimer. Und wenn Benutzer die Musik fortsetzen, stelle ich den NSTimer auf die Ruhezeit des Liedes ein.

Es funktioniert sehr gut. Ich hoffe, das kann Ihnen helfen. Entschuldigung für mein billiges Englisch.


Schritt, den Sie benötigen;

  1. Audio-Hintergrundmodus in Capabilities Setting einstellen. (Sie fertig)
  2. Verwenden Sie BeginBackgroundTaskWithExpirationHandler in App Delegate.
 
    - (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.Use NSTimer in Modus nicht wiederholt.

 

    #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]; 
    }]; 
+0

Ich denke, der NSTimer im Wiederholungsmodus wird im Hintergrund nicht gut funktionieren. Ich habe es im nicht wiederholten Modus verwendet. –

+0

Ich habe das genau gleiche Ding versucht, aber nach 3 Minuten feuert mein NSTimer nicht mehr. Also meine eigentliche Frage ist, wie bekomme ich mehr als 3 Minuten? Ich habe den Audio-Hintergrund-Modus eingestellt. –

0

Für die Zukunft:

fand ich, dass MPMusicPlayerController nie Audio UIBackgroundMode eingreift, entweder applicationMusicPlayer oder systemMusicPlayer verwenden. Sie können nie mehr als 3 Minuten Hintergrundzeit bekommen. Mit AVAudioPlayer wird jedoch der Audio-Hintergrundmodus aktiviert. Meine (hässliche) Lösung besteht also darin, mit dem AVAudioPlayer im Hintergrund eine stille MP3-Datei abzuspielen. Ich gehe davon aus, dass Apple nicht protestieren wird, das scheint eine legitime Verwendung von Silent Audio zu sein. Beachten Sie, dass für die gleichzeitige Wiedergabe von AVAudioPlayer und MPMusicPlayerController AVAudioSessionCategoryOptionMixWithOthers für AVAudioSession festgelegt werden muss.

+0

Konnten Sie eine Lösung finden, um jetzt Informationen in der Leitstelle abzuspielen? Ich verwende applicationQueuePlayer und kann Musik abspielen, aber das Kontrollzentrum wird nicht mit MPNowPlayingInfoCenter aktualisiert. Es behält die Stock Music App Info. – Benr783

Verwandte Themen