AVKit
AVPlayerViewController
Swift
iOS Development
Video Playback

How to play video with AVPlayerViewController AVKit in Swift

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

AVPlayerViewController is the default high-quality video UI in iOS because it handles playback controls, fullscreen transitions, and many system media behaviors automatically. The API is small, but production integration requires deliberate lifecycle, buffering, and error handling. This guide focuses on practical Swift patterns that stay stable in real apps.

Quick Modal Playback Pattern

The most direct approach is presenting AVPlayerViewController modally and starting playback once presented.

swift
1import UIKit
2import AVKit
3
4final class VideoLauncherViewController: UIViewController {
5    private var player: AVPlayer?
6
7    func playVideo(from url: URL) {
8        let player = AVPlayer(url: url)
9        self.player = player
10
11        let vc = AVPlayerViewController()
12        vc.player = player
13
14        present(vc, animated: true) {
15            player.play()
16        }
17    }
18}

Keep a strong reference to player when you need later controls such as pause or replay.

Embedded Playback with Child Controller

Use child containment when video should appear inside a larger layout instead of fullscreen modal.

swift
1import UIKit
2import AVKit
3
4final class EmbeddedVideoViewController: UIViewController {
5    private let playerVC = AVPlayerViewController()
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9
10        addChild(playerVC)
11        playerVC.view.translatesAutoresizingMaskIntoConstraints = false
12        view.addSubview(playerVC.view)
13        playerVC.didMove(toParent: self)
14
15        NSLayoutConstraint.activate([
16            playerVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
17            playerVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
18            playerVC.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
19            playerVC.view.heightAnchor.constraint(equalToConstant: 250)
20        ])
21    }
22
23    func configure(url: URL) {
24        playerVC.player = AVPlayer(url: url)
25    }
26}

This pattern works well for feed cards, course screens, and article detail pages.

Observe Playback Completion

For replay UI or analytics, observe end-of-item notifications.

swift
1import AVFoundation
2
3final class PlayerObserver {
4    private var token: NSObjectProtocol?
5
6    func startObserving(player: AVPlayer, onComplete: @escaping () -> Void) {
7        guard let item = player.currentItem else { return }
8        token = NotificationCenter.default.addObserver(
9            forName: .AVPlayerItemDidPlayToEndTime,
10            object: item,
11            queue: .main
12        ) { _ in
13            onComplete()
14        }
15    }
16
17    deinit {
18        if let token {
19            NotificationCenter.default.removeObserver(token)
20        }
21    }
22}

Observer cleanup is essential to avoid duplicate callback behavior after navigation.

Handle Status and Recovery

Check status before assuming playback problems are network-related.

swift
1import AVFoundation
2
3func describeStatus(_ player: AVPlayer) {
4    guard let item = player.currentItem else {
5        print("No item")
6        return
7    }
8
9    switch item.status {
10    case .readyToPlay:
11        print("Ready")
12    case .failed:
13        print("Failed", item.error?.localizedDescription ?? "unknown")
14    case .unknown:
15        print("Unknown")
16    @unknown default:
17        print("Future status")
18    }
19}
20
21func replay(_ player: AVPlayer) {
22    player.seek(to: .zero)
23    player.play()
24}

Expose user-visible retry actions instead of silent failure loops.

Picture in Picture and UX Controls

On supported versions, configure picture-in-picture behavior for better multitasking.

swift
1import AVKit
2
3func configurePictureInPicture(_ controller: AVPlayerViewController) {
4    if #available(iOS 14.2, *) {
5        controller.canStartPictureInPictureAutomaticallyFromInline = true
6    }
7}

Also consider:

  • pausing when screen disappears if background playback is not intended.
  • disabling repeated play taps while presentation animation runs.
  • preserving playback position for resume flows.

These details improve usability more than UI cosmetics.

Interruptions and App Lifecycle Handling

Playback can pause due to phone calls, Siri, or app background transitions. Handle interruption notifications so UI state stays accurate.

swift
1import AVFoundation
2
3final class AudioInterruptionObserver {
4    private var token: NSObjectProtocol?
5
6    func start() {
7        token = NotificationCenter.default.addObserver(
8            forName: AVAudioSession.interruptionNotification,
9            object: nil,
10            queue: .main
11        ) { note in
12            print("Interruption event:", note.userInfo ?? [:])
13        }
14    }
15
16    deinit {
17        if let token {
18            NotificationCenter.default.removeObserver(token)
19        }
20    }
21}

Also decide whether playback should resume automatically or wait for user confirmation after interruptions.

Diagnostics for Support and QA

If users report playback failures, collect actionable context:

  • URL source type, local or remote.
  • item status and error domain.
  • device model and iOS version.
  • network conditions for streaming cases.

Structured diagnostics reduce guesswork and speed up incident resolution.

Common Pitfalls

  • Presenting player before URL validation and then showing blank controls.
  • Not retaining player when later interaction requires state access.
  • Forgetting observer cleanup, causing duplicated completion events.
  • Ignoring item status and treating every failure as connectivity issue.
  • Testing only simulator and missing device-specific audio behaviors.

Summary

  • AVPlayerViewController is the preferred iOS video UI for most use cases.
  • Modal presentation is fastest; child containment is best for inline layouts.
  • Add status checks, completion observation, and replay handling.
  • Configure picture-in-picture and lifecycle behavior intentionally.
  • Keep player lifecycle explicit to avoid fragile playback behavior.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.