Video player options not visible on iOS 16

  • Experiencing the same here, no controls, however there appears to be gestures configured as I'm able to play (by tapping the center of the video), and scrub (by tap-dragging across the video)

  • Likewise, I'm experiencing the same as well. Has anyone found a solution for this at all? I've tried numerous suggestions, but nothing seems to invoke the controls UI by default.

Add a Comment

Apple Recommended

Replies

Do you already have a solution for this problem?

I also Experiencing the same problem. the avplayerviewcontroller in iOS 16 have no playback overlay

  • I ended up creating a button over the top of the video that looks pretty much identical to the one in iOS 15 that disappears when tapped and plays the video. It's a bit of a kludge, but I couldn't find any native way to achieve it in iOS 16.

Add a Comment

I had this problem too. I downloaded apple sample code.
https://developer.apple.com/documentation/avkit/playing_video_content_in_a_standard_user_interface This code works fine for iOS 16. Video player options are visible. I found differences with my code. I added only view from AVPlayerViewController, but I didn't add AVPlayerViewController

old code:

container.addSubview(playerViewController.view) 

new code:

parent.addChild(playerViewController)
container.addSubview(playerViewController.view) 

Now it works fine

Add a Comment

@YuriKuzminsky that worked for me - well done!

How about SwiftUI? I have same problem with AVPlayer and AVPlayerViewController((

None of these solutions work for me on Xcode 14.0 and iOS 16. Taking the previous suggestion, I ran Apple's own AVKit sample against iOS 15.5 and iOS 16. Their code has the same issue: on iOS 16, you don't see any preview controls until you tap once on the player. That's definitely a change that wasn't communicated to the dev community, AFAIK.

For Swift UI -> IOS 16

CustomVideoPlayer() .compositingGroup() // Mandatory

struct CustomVideoPlayer : UIViewControllerRepresentable {

var player: AVPlayer

func makeUIViewController(context: UIViewControllerRepresentableContext) -> AVPlayerViewController {

 let controller = AVPlayerViewController()
 controller.player = player
 return controller

}

func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext) { }

try this kludge:

   func updateControlsvisibility(view: UIView?){
    guard let view = view else {
      return
    }
    if view.isKind(of: NSClassFromString("AVButton") ?? NSNull.self){
      view.alpha = 1.0
      view.isHidden = false
      var parent = view.superview
      while let p = parent{
        p.alpha = 1.0
        p.isHidden = false
        parent = p.superview
      }
      return
    }
    for subview in view.subviews{
      if subview != view {
        self.updateControlsvisibility(view: subview)
      }
    }
  }

//when the AVPlayerViewController is ready to display call this function
         playerViewController.observe(\.isReadyForDisplay) { [weak self] observed, _ in
          if observed.isReadyForDisplay {
            self?.updateControlsvisibility(view: playerViewController.view)
          }
        }

this will work for U:

  func updateControlsvisibility(view: UIView?){
    guard let view = view else {
      return
    }
    if view.isKind(of: NSClassFromString("AVButton") ?? NSNull.self){
      view.alpha = 1.0
      view.isHidden = false
      var parent = view.superview
      while let p = parent{
        p.alpha = 1.0
        p.isHidden = false
        parent = p.superview
      }
      return
    }
    for subview in view.subviews{
      if subview != view {
        self.updateControlsvisibility(view: subview)
      }
    }
  }

//when the AVPlayerViewController is ready to display call this function
 playerViewController.observe(\.isReadyForDisplay) { [weak self] observed, _ in
    if observed.isReadyForDisplay, greateThaniOS16 {
    self?.updateControlsvisibility(view: playerViewController.view) 
    }
}

I think a work around for this issue can be adding

if #available(iOS 16.0, *) {
    avPlayerViewController.setValue(false, forKey: "canHidePlaybackControls")
}

and removing it after one second. So the code will look like something like this:

let avPlayer: AVPlayer = AVPlayer(url: newURL)
avPlayerViewController = AVPlayerViewController()
if let avPlayerViewController = avPlayerViewController {
    avPlayerViewController.delegate = self
    avPlayerViewController.player = avPlayer
    if #available(iOS 16.0, *) {
        avPlayerViewController.setValue(false, forKey: "canHidePlaybackControls")
    }
    addChild(avPlayerViewController)
    view.addSubview(avPlayerViewController.view)
}
if #available(iOS 16.0, *) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
        self.avPlayerViewController?.setValue(true, forKey: "canHidePlaybackControls")
    })
}
  • The downside of using this work around is that you'll be using private api calls which can result in your app being rejected by Apple.

Add a Comment

The recommendation does not work for me. I have embedded the AVPlayerViewController in a UIViewController, also the beginAppearanceTransition is called, but no video controls are shown. They are shown when the video is tabbed, but not initially. I don't want to add the workaround suggested by nbeanm but I have not found any other solution yet.

Here is my code:


	func addPlayer(mediaURL: URL) {
		let playerController = AVPlayerViewController()
		playerController.showsTimecodes = true
		playerController.player = AVPlayer(url: mediaURL)
		playerController.beginAppearanceTransition(true, animated: false)
		self.addChild(playerController)
		view.addSubview(playerController.view)

		// Setup the layout. I have created my own layout helper for setting up layout constraints.
		// It should be obvious, that the player uses all the space of it's parent view.
		// My layout helper can be found here: https://github.com/openbakery/PinLayout/
		playerController.view.layout.pin(.top, .bottom, .leading, .trailing)

		playerController.didMove(toParent: self)
		self.actualPreviewController = playerController
		playerController.endAppearanceTransition()
	}


Add a Comment