AVPlayerViewController not displaying playback controls in iOS 18

Hi everyone,

I’ve encountered an issue with the showsPlaybackControls property in AVPlayerViewController after updating to iOS 18. Even though it’s set to true, the native playback controls (play, pause, etc.) are no longer appearing as they used to in previous iOS versions. This behavior was consistent and worked perfectly prior to iOS 18.

Additionally, I’m seeing the same problem when using the VideoPlayer in SwiftUI. The native controls that should appear by default seem to have vanished after the update. Has anyone else experienced this? Is there any workaround or additional configuration required to restore the native controls?

Any help or insights would be appreciated. Thanks!

struct CustomPlayerView: UIViewControllerRepresentable {
        
        let player: AVPlayer
        
        func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {
            playerController.player = player
            playerController.showsPlaybackControls = true
            player.play()
        }
        
        func makeUIViewController(context: Context) -> AVPlayerViewController {
            return AVPlayerViewController()
        }
    }
Answered by DTS Engineer in 808004022

Hello @fandrade,

I see, I can reproduce now in a TabView, please file a bug report for this issue using Feedback Assistant.

Best regards,

Greg

Facing the same issue. Did you find any solution @fandrade ?

Hello @fandrade,

I was unable to reproduce the issue described using this code on iOS 18.1 beta 5, does it reproduce for you there with this code?

import SwiftUI
import AVKit
import AVFoundation

struct ContentView: View {
    
    @State private var player: AVPlayer?
    
    var body: some View {
        if let player {
            CustomPlayerView(player: player)
        } else {
            ProgressView()
                .task {
                    let player = AVPlayer(url: Bundle.main.url(forResource: "example", withExtension: "mov")!)
                    
                    self.player = player
                }
        }
    }
}

struct CustomPlayerView: UIViewControllerRepresentable {
    
    let player: AVPlayer
    
    func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {
        playerController.player = player
        playerController.showsPlaybackControls = false
        player.play()
    }
    
    func makeUIViewController(context: Context) -> AVPlayerViewController {
        return AVPlayerViewController()
    }
}

Best regards,

Greg

I’m adding some extra info: this problem only happens when the player is in a modal (when is shown by a present).

@DTS Engineer the palyback controls are not showing if adding the AVPlayerViewController or SwiftUI VideoPlayer inside a TabView with .tabViewStyle(.page(indexDisplayMode: .never)) style

TabView(selection: $currentIndex) {
    ForEach(0..<localFiles.count, id:\.self) { index in
        let url = localFiles[index]
        SOVideoPlayer(url: url)
            .clipped()
    }
}
.tabViewStyle(.page(indexDisplayMode: .never))

struct SOVideoPlayer: View {
    let url: URL
    @State private var play = false
    var body: some View {
        CustomVideoPlayer(play: $play, url: url)
            .overlay {
                Image(systemName: "play.fill")
                    .foregroundStyle(.white)
                    .background {
                        Color.black.opacity(0.5)
                            .frame(width: 54, height: 54)
                            .clipShape(.circle)
                    }
                    .simultaneousGesture(
                        TapGesture()
                            .onEnded {
                                play.toggle()
                            }
                    )
                    .opacity(play ? 0 : 1)
            }
            .onDisappear {
                play = false
            }
    }
}
extension SOVideoPlayer {
    fileprivate struct CustomVideoPlayer: UIViewControllerRepresentable {
        @Binding var play: Bool
        let url: URL
        func makeUIViewController(context: Context) -> AVPlayerViewController {
            let controller = AVPlayerViewController()
            let player = AVPlayer(url: url)
            controller.player = player
            controller.showsPlaybackControls = true
            return controller
        }
        func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
            if play {
                uiViewController.player?.play()
            } else {
                uiViewController.player?.pause()
            }
        }
    }
}

I found the solution to the problem. I want to clarify once again that this issue only occurs with iOS 18+.

I think it's a lifecycle thing. By adding the UIHostingController that contains the SwiftUI view (which in turn contains the Player) as child and notifying the addition to the parent, the player controls become visible again.

New lines:

addChild(hostingController)  
hostingController.didMove(toParent: self)

Below is a complete code example:

addChild(hostingController)  hostingController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingController.view)
hostingController.didMove(toParent: self)
/// set constraints

Hello @fandrade,

I see, I can reproduce now in a TabView, please file a bug report for this issue using Feedback Assistant.

Best regards,

Greg

@DTS Engineer @fandrade Is there a bug raised/fixed already? Experiencing the same issue in TabView.

Surprisingly, found a solution here: https://forums.developer.apple.com/forums/thread/711360

Adding the following in makeUIViewController() solved the issue.

@DTS Engineer @fandrade

controller.beginAppearanceTransition(true, animated: false) 
AVPlayerViewController not displaying playback controls in iOS 18
 
 
Q