Search code examples
iosswiftmpmusicplayercontroller

iOS MPMusicPlayerController song changed notification does not have a song object with it


I am developing an app that listens to song changes of the MPMusicPlayerController.

For that, I am adding the following observer:

NotificationCenter.default
    .addObserver(self,
                 selector: #selector(systemSongDidChange(_:)),
                 name: .MPMusicPlayerControllerNowPlayingItemDidChange,
                 object: nil)

The problem is that, when the notification is fired, the nowPlayingItem that can be found at (notification?.object as? MPMusicPlayerController)!.nowPlayingItem is always nil.

Am I doing anything wrong or is there some special trick that must be done to retrieve the actual nowPlayingItem?

Here is a more complete code:

// ...
init() {
    let systemPlayer = MPMusicPlayerController.systemMusicPlayer

    NotificationCenter.default.addObserver(self,
                                           selector: #selector(systemSongDidChange(_:)),
                                           name: .MPMusicPlayerControllerNowPlayingItemDidChange,
                                           object: systemPlayer)

    player.beginGeneratingPlaybackNotifications()
}

private func systemSongDidChange(notification: Notification) {
    let currentSong = (notification.object as? MPMusicPlayerController)?.nowPlayingItem
    // `currentSong` is always `nil` =/
}
// ...

The player I am using is the Apple's Music Player. I am not playing songs from the cloud.


Solution

  • I have just found out why the nowPlayingItem is always being nil.

    It seems that the user must have allowed the app to access the "Media & Apple Music". If this access has not been granted, the app will not have permission to know what is currently playing on the system's player.

    This authorization can be requested as follows:

    // if not yet given or requested
    MPMediaLibrary.requestAuthorization { authorizationStatus in }
    

    or

    // if already requested and denied (will take user to the App Settings Page)
    UIApplication.shared.openURL(URL(string:UIApplicationOpenSettingsURLString)!)