AVPlayerViewController is a built-in video player controller in the Apple ecosystem, designed for playing media content on iOS and tvOS. It provides a full-screen interface with controls, subtitle support, and AirPlay without the need to write a custom UI. According to Apple Developer Documentation, 2026, AVPlayerViewController integrates in just a few lines of code and supports HLS, MP4, and most media formats.
Key Takeaways
AVPlayerViewController is a component of the AVKit framework that provides a ready-made interface for playing video in Apple applications. It relieves developers from having to create a custom player from scratch by offering standard controls: play/pause, scrubbing, volume adjustment, and full-screen mode.
Unlike the low-level AVPlayerLayer, which requires manual UI construction, AVPlayerViewController fully manages the player lifecycle. The controller automatically handles screen rotation, adapts to the Safe Area on iPhones with a notch, and supports multitasking on iPad.
According to Apple Documentation (2026), AVPlayerViewController is compatible with AVPlayer and AVQueuePlayer, allowing playback of both single files and playlists. URLs from local storage, HLS network streams, and encrypted FairPlay content are supported.
The component appeared in iOS 8 along with AVKit as a replacement for the deprecated MPMoviePlayerController. In iOS 11, support for Picture in Picture and subtitle display was added. In iOS 14, the controller received a customizable transport bar through the AVPlayerViewControllerDelegate. Starting with iOS 16, support for dynamic media file replacement without recreating the player was introduced.
The modern AVPlayerViewController is optimized for ProMotion displays — the video frame rate automatically synchronizes with the screen refresh rate. On tvOS, the component adapts to the Siri Remote focus interface, and on macOS, to the QuickTime Player windowed mode.
At the core of the controller is the AVPlayer and AVPlayerItem pairing. AVPlayer is the playback object that manages the timeline, speed, and state. AVPlayerItem is a wrapper around a specific media file, containing metadata, tracks, and loading information.
When initialized, AVPlayerViewController receives a reference to AVPlayer and automatically creates an AVPlayerLayer for displaying video. The controller subscribes to AVPlayer KVO notifications about status changes such as readyToPlay, loading errors, and playback completion.
The controls (transport bar) are displayed on tap. In iOS 15+, they support customization through AVPlayerViewControllerCustomizationDelegate, allowing you to hide or replace standard buttons.
After creating the controller and assigning AVPlayer, the viewDidLoad method is called, which starts preparing the video stream. When AVPlayerItem transitions to the AVPlayerItemStatusReadyToPlay status, the player is ready to display frames. When the play() method is called, video stream decoding begins via Video Toolbox.
When leaving the screen, the controller automatically pauses playback and releases decoder resources. On iOS 13+, to maintain playback when the app is minimized, Background Modes and Audio Session must be configured. According to WWDC 2024, it is recommended to use AVPlayerPlaybackCoordinator for synchronization with the iOS media center.
The component provides a rich set of features out of the box, making it attractive for most projects. Below are key capabilities that require no additional code.
The transport bar is the bottom part of the interface containing the main control buttons. By default, the bar hides after 3 seconds of user inactivity and appears on tap. In iOS 16+, the delegate can be used to control the visibility of individual elements.
In debug mode, the transport bar can be forced to show using the AVPlayerViewController.requiresLinearPlayback property, which also prevents the video from being paused. This is useful for ad breaks and educational content.
Basic integration of the controller takes no more than 10 lines of code. First, create an AVPlayer instance with the media file URL, then pass it to AVPlayerViewController and display the controller on screen.
import AVKit
let player = AVPlayer(url: URL(string: "https://example.com/video.mp4")!)
let playerVC = AVPlayerViewController()
playerVC.player = player
present(playerVC, animated: true) {
player.play()
}
After calling present, the controller displays full screen. The video starts loading from the network, and once the buffer reaches the readyToPlay threshold, playback automatically begins after calling play().
let asset = AVAsset(url: videoURL)
let item = AVPlayerItem(asset: asset)
let metadata = AVMutableMetadataItem()
metadata.key = AVMetadataKey.commonKeyTitle
metadata.value = "My Video"
item.addMetadata(metadata)
let player = AVPlayer(playerItem: item)
let playerVC = AVPlayerViewController()
playerVC.player = player
Using AVPlayerItem gives you control over metadata, timecodes, audio track selection, and subtitles. Through AVPlayerItem, you can also monitor loading progress, buffering, and network errors using KVO on the status property.
Starting with iOS 11, developers can customize the transport bar through the AVPlayerViewControllerDelegate protocol. The playerViewController(_:willBeginFullScreenPresentationWithAnimationCoordinator:) method is called before entering full-screen mode and allows you to prepare the UI.
To hide individual buttons, use the AVPlayerViewController.showsPlaybackControls property. If set to false, the transport bar completely disappears, leaving only the video stream. Useful for custom overlay elements.
class CustomPlayerViewController: UIViewController {
private let playerVC = AVPlayerViewController()
override func viewDidLoad() {
super.viewDidLoad()
playerVC.delegate = self
playerVC.showsPlaybackControls = true
playerVC.entersFullScreenWhenPlaybackBegins = true
}
}
extension CustomPlayerViewController: AVPlayerViewControllerDelegate {
func playerViewController(
_ playerViewController: AVPlayerViewController,
willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator
) {
// Add overlay button
}
func playerViewController(
_ playerViewController: AVPlayerViewController,
didUpdate legibleMediaSelection: AVMediaSelectionGroup
) {
print("New subtitle language selected")
}
}
The delegate allows intercepting subtitle change events, entering and exiting full-screen mode, as well as starting and ending Picture in Picture. At WWDC 2024, Apple recommended using the delegate for analytics — log each transition within 100 ms.
AVPlayerViewController automatically displays all available subtitles and audio tracks if they are embedded in the media file or specified in the HLS manifest. Users can switch them via the menu that appears when tapping the subtitle icon in the transport bar.
For HLS streams, the M3U8 manifest contains a list of available language variants. AVPlayer loads the corresponding WebVTT subtitle segments and passes them to AVPlayerLayer for rendering. iOS 16+ introduced subtitle styling support through AVTextStyleRule.
func selectAudioTrack(languageCode: String) {
guard let group = player.currentItem?
.asset.mediaSelectionGroup(forMediaCharacteristic: AVMediaCharacteristic.audible)
else { return }
for option in group.options {
if option.extendedLanguageTag?.hasPrefix(languageCode) == true {
player.currentItem?.select(option, in: group)
}
}
}
The selectAudioTrack method searches among the audio options of the audible group for the variant whose extendedLanguageTag matches the desired language code. This allows implementing the “Original Audio” feature in apps with multilingual content.
Picture in Picture (PiP) mode allows displaying video in a floating window on top of other apps. On iPad, this feature has been available since iOS 9, on iPhone — since iOS 14. AVPlayerViewController automatically adds a PiP button to the transport bar when subscribed to UIBackgroundModes.
To activate PiP, add the UIBackgroundModes key with the audio and airplay values to Info.plist. After that, a PiP button appears in the controller, which collapses the video into a floating window of 192x108 points when tapped.
PiP events are handled through the delegate: playerViewController(_:willStartPictureInPictureFromFullScreen:) and playerViewController(_:didStopPictureInPicture:). According to Apple HIG, the minimum PiP window size should be at least 120x68 points to maintain content readability.
Frequently Asked Questions
No, YouTube videos require using a web view WKWebView or the YouTube iOS Helper library, as YouTube uses its own DRM system. AVPlayerViewController is designed for direct media streams via URL.
Set the showsPlaybackControls property to false. After that, the screen remains empty — only the video stream. To bring back custom buttons, add an overlay via addSubview on top of the controller.
Yes, the controller fully supports HLS Live. The transport bar shows a Live indicator instead of a progress slider. Latency depends on HLS configuration — minimum 6 seconds with low-latency settings.
Subscribe to KVO on the AVPlayerItem.status property. On error, the status changes to .failed. Get details through the error property of AVPlayerItem and show the user an alert explaining the issue — often it’s a network problem or an invalid URL.
Yes, use AVAsset with a custom AVAssetResourceLoader to feed data from RAM. Implement the AVAssetResourceLoaderDelegate and return bytes from a buffer instead of reading from disk.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also