Search code examples
iosswiftnsnotificationcentermpmediaplayercontroller

How to get notified when iOS music app changes state


I have tried every possible method to subscribe and I'm not getting any notifications

let musicPlayer = MPMusicPlayerController.systemMusicPlayer
let appMusicPlayer = MPMusicPlayerController.applicationMusicPlayer
let queuePlayer = MPMusicPlayerController.applicationQueuePlayer

func subscribe() {


    MPMediaLibrary.requestAuthorization { _ in }      

    musicPlayer.beginGeneratingPlaybackNotifications()
    appMusicPlayer.beginGeneratingPlaybackNotifications()
    queuePlayer.beginGeneratingPlaybackNotifications()

    NotificationCenter.default.addObserver(forName: .MPMusicPlayerControllerPlaybackStateDidChange, object: musicPlayer, queue: .main) { [weak self] notification in
        debugPrint("hello")
    }
    
    NotificationCenter.default.addObserver(forName: .MPMusicPlayerControllerPlaybackStateDidChange, object: appMusicPlayer, queue: .main) { [weak self] notification in
        debugPrint("hello")
    }
    
    NotificationCenter.default.addObserver(forName: .MPMusicPlayerControllerPlaybackStateDidChange, object: queuePlayer, queue: .main) { [weak self] notification in
        debugPrint("hello")
    }

    NotificationCenter.default.addObserver(
        self,
        selector: #selector(playbackStateChanged(_:)),
        name: .MPMusicPlayerControllerPlaybackStateDidChange,
        object: musicPlayer
    )

    NotificationCenter.default.addObserver(
        self,
        selector: #selector(playbackStateChanged(_:)),
        name: .MPMusicPlayerControllerPlaybackStateDidChange,
        object: appMusicPlayer
    )

    NotificationCenter.default.addObserver(
        self,
        selector: #selector(playbackStateChanged(_:)),
        name: .MPMusicPlayerControllerPlaybackStateDidChange,
        object: queuePlayer
    )

}


Solution

  • Mostly likely you are running app on simulator but go through this checklist if you are not.

    • Add "NSAppleMusicUsageDescription" to your .plist file with string value which describes why you need access to Media player framework.

    • Use sample code

      
      
      import SwiftUI
      import MediaPlayer
      
      struct ContentView: View {
          var body: some View {
              VStack {
                  Image(systemName: "globe")
                      .imageScale(.large)
                      .foregroundStyle(.tint)
                  Text("SetupMusic").onTapGesture {
                      setup()
                  }
              }
              .padding()
          }
      }
      
      private func setup() {
          debugPrint("Requesting access")
          MPMediaLibrary.requestAuthorization { permission in
              debugPrint("Setting up music player")
              let musicPlayer = MPMusicPlayerController.systemMusicPlayer
              musicPlayer.beginGeneratingPlaybackNotifications()
              debugPrint("Initial State: \(musicPlayer.playbackState)")
              NotificationCenter.default.addObserver(forName: .MPMusicPlayerControllerPlaybackStateDidChange, object: musicPlayer, queue: .main) {  notification in
                  debugPrint("State changed to \(musicPlayer.playbackState)")
              }
          }
      }
      
      #Preview {
          ContentView()
      }
      
      
      
    1. Run app on real iOS device. Simulator does not support MPMediaPlayer framework.
    2. Hit button to allow for permission.
    3. Once granted you should get initial state. (Stopped/Paused)
    4. Go to system music app and play something on radio.
    5. Launch app again you should see state change to Playing
    6. Swipe down for notifications and pause music and state will change to Paused
    7. Event will only be fired if app is in foreground state.