Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

How to disable automatic updates to MPNowPlayingInfoCenter from AVPlayer

I’m building a SwiftUI app whose primary job is to play audio. I manage all of the Now-Playing metadata and Command center manually via the available shared instances:

MPRemoteCommandCenter.shared()
MPNowPlayingInfoCenter.default().nowPlayingInfo

In certain parts of the app I also need to display videos, but as soon as I attach another AVPlayer, it automatically pushes its own metadata into the Control Center and overwrites my audio info.

What I need: a way to show video inline without ever having that video player update the system’s Now-Playing info (or Control Center).

In my app, I start by configuring the shared audio session

        do {
            try AVAudioSession.sharedInstance().setCategory(.playback,
                                                            mode: .default,
                                                            options: [
                                                                .allowAirPlay,
                                                                .allowBluetoothA2DP
                                                            ])
            try AVAudioSession.sharedInstance().setActive(true)
        } catch {
            NSLog("%@", "**** Failed to set up AVAudioSession \(error.localizedDescription)")
        }

and then set the MPRemoteCommandCenter commands and MPNowPlayingInfoCenter nowPlayingInfo like mentioned above.

All this works without any issues as long as I only have one AVPlayer in my app. But when I add other AVPlayers to display some videos (and keep the main AVPlayer for the sound) they push undesired updates to MPNowPlayingInfoCenter:

struct VideoCardView: View {
    @State private var player: AVPlayer
        
    let videoName: String

    init(player: AVPlayer = AVPlayer(), videoName: String) {
        self.player = player
        self.videoName = videoName
        guard let path = Bundle.main.path(forResource: videoName, ofType: nil) else { return }
        let url = URL(fileURLWithPath: path)
        let item = AVPlayerItem(url: url)
        self.player.replaceCurrentItem(with: item)
    }
        
    var body: some View {
        VideoPlayer(player: player)
            .aspectRatio(contentMode: .fill)
            .onAppear {
                player.isMuted = true
                player.allowsExternalPlayback = false
                player.actionAtItemEnd = .none
                player.play()
                
                MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
                MPNowPlayingInfoCenter.default().playbackState = .stopped

                NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
                                                       object: player.currentItem,
                                                       queue: .main) { notification in
                    guard let finishedItem = notification.object as? AVPlayerItem,
                              finishedItem === player.currentItem else { return }
                    player.seek(to: .zero)
                    player.play()
                }
            }
            .onDisappear {
                player.pause()
            }
    }
}

Which is why I tried adding:

MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
MPNowPlayingInfoCenter.default().playbackState = .stopped // or .interrupted, .unknown

But that didn't work.

I also tried making a wrapper around the AVPlayerViewController in order to set updatesNowPlayingInfoCenter to false, but that didn’t work either:

struct CustomAVPlayerView: UIViewControllerRepresentable {
    let player: AVPlayer

    func makeUIViewController(context: Context) -> AVPlayerViewController {
        let vc = AVPlayerViewController()
        vc.player = player
        vc.updatesNowPlayingInfoCenter = false
        vc.showsPlaybackControls = false
        return vc
    }

    func updateUIViewController(_ controller: AVPlayerViewController, context: Context) {
        controller.player = player
    }
}

Hence any help on how to embed video in SwiftUI without its AVPlayer touching MPNowPlayingInfoCenter would be greatly appreciated.

All this was tested on an actual device with iOS 18.4.1, and built with Xcode 16.2 on macOS 15.5

We also face this issue. We are using AVAudioEngine for audio playback and manually control MPNowPlayingInfoCenter. We use AVPlayer for some silent background videos in app but when doing so the video player controls the playbackState with no way to opt-out.

After filing a DTS, feedback and lab I am fairly sure there is no solution for this currently unfortunately. I filed FB9837867 and am crossing my fingers for some progress.

Our current work-around which is not ideal is to set MPNowPlayingInfoCenter.default().nowPlayingInfo = nil whenever we pause the audio playback. This seems to somewhat work but also has some other not great side-effects.

@Rodrigue2g Did you find any better solutions since posting this?

I would encourage you to file feedback and mention FB9837867 as well!

Thank you for your reply, I also just had an AVKit lab and this indeed seems like an issue with the framework(s). To follow up, I filed a feedback (FB18058056) mentioning yours and this discussion.

I also realized that using the CustomAVPlayerView as shown above actually works as long as the app doesn't configure the MPRemoteCommandCenter (by adding targets to the shared instance). In my use case, I do have to configure it (as for many other I recon) so I had to come up with another "fix".

Personally what I did is to pass the scenePhase to the views configuring/displaying the videos so that when the app enters the .inactive or .background state I can pause the AVPlayers and setup the nowPlayingInfo again (either to nil or current audio). I also do this cleanup as soon as the view disappears (via .onDisappear{}).

Ultimately this is not great as there are still some side-effects, for example, If no audio is playing but the user simply opens the view with the video players, the app will appear as Now Playing (even after setting thenowPlayingInfo to nil). But for now, it is a "good enough" workaround, until the underlying issue is addressed.

How to disable automatic updates to MPNowPlayingInfoCenter from AVPlayer
 
 
Q