Avkit
Create media playback experiences using AVKit. Use when adding video players with AVPlayerViewController, enabling Picture-in-Picture, routing media with AirPlay, using SwiftUI VideoPlayer views, configuring transport controls, displaying subtitles and closed captions, or integrating AVFoundation playback with system UI.
- Skill ID
- dpearson2699/swift-ios-skills/avkit
- Publisher
- dpearson2699
- Repository
- swift-ios-skills
- Installs
- 0
- Files
- 3
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
dpearson2699/swift-ios-skills/avkitInstalls these files- SKILL.md
- evals/evals.json
- references/avkit-patterns.md
What this skill tells the agent
AVKit
High-level media playback UI built on AVFoundation. Provides system-standard video players, Picture-in-Picture, AirPlay routing, transport controls, and subtitle/caption display. Targets Swift 6.3 / iOS 26+.
Contents
- Setup
- AVPlayerViewController
- SwiftUI VideoPlayer
- Picture-in-Picture
- AirPlay
- Transport Controls and Playback Speed
- Subtitles and Closed Captions
- Common Mistakes
- Review Checklist
- References
Setup
Audio Session Configuration
Playback apps need an audio session category and the matching background mode when they support background audio, AirPlay, or PiP.
- Enable Background Modes > Audio, AirPlay, and Picture in Picture (the
audiovalue inUIBackgroundModes) - Set the audio session category to
.playback - Defer
setActive(true)until playback begins so you do not interrupt other audio prematurely
import AVFoundation
func configureAudioSessionForPlayback() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playback, mode: .moviePlayback)
} catch {
print("Audio session category failed: \(error)")
}
}
func activateAudioSessionWhenPlaybackBegins() {
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print("Audio session activation failed: \(error)")
}
}Imports
import AVKit // AVPlayerViewController, VideoPlayer, PiP
import AVFoundation // AVPlayer, AVPlayerItem, AVAssetAVPlayerViewController
AVPlayerViewController is the standard UIKit player. It provides system playback controls, PiP, AirPlay, subtitles, and frame analysis out of the box. Do not subclass it.
Basic Presentation (Full Screen)
import AVKit
func presentPlayer(from viewController: UIViewController, url: URL) {
let player = AVPlayer(url: url)
let playerVC = AVPlayerViewController()
playerVC.player = player
viewController.present(playerVC, animated: true) {
player.play()
}
}Inline (Embedded) Playback
Add AVPlayerViewController as a child view controller for inline playback. Call addChild, add the view with constraints, then call didMove(toParent:).
func embedPlayer(in parent: UIViewController, container: UIView, url: URL) {
let playerVC = AVPlayerViewController()
playerVC.player = AVPlayer(url: url)
parent.addChild(playerVC)
container.addSubview(playerVC.view)
playerVC.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
playerVC.view.leadingAnchor.constraint(equalTo: container.leadingAnchor),
playerVC.view.trailingAnchor.constraint(equalTo: container.trailingAnchor),
playerVC.view.topAnchor.constraint(equalTo: container.topAnchor),
playerVC.view.bottomAnchor.constraint(equalTo: container.bottomAnchor)
])
playerVC.didMove(toParent: parent)
}Key Properties
playerVC.showsPlaybackControls = true // Show/hide system controls
playerVC.videoGravity = .resizeAspect // .resizeAspectFill to crop
playerVC.entersFullScreenWhenPlaybackBegins = false
playerVC.exitsFullScreenWhenPlaybackEnds = true
playerVC.updatesNowPlayingInfoCenter = true // Auto-updates MPNowPlayingInfoCenterUse contentOverlayView to add non-interactive views (watermarks, logos) between the video and transport controls.
Delegate
Adopt AVPlayerViewControllerDelegate to respond to full-screen transitions, PiP lifecycle events, interstitial playback, and media selection changes. Use the transition coordinator's animate(alongsideTransition:completion:) to synchronize your UI with full-screen animations.
Display Readiness
Observe isReadyForDisplay before showing the player to avoid a black flash:
let observation = playerVC.observe(\.isReadyForDisplay) { observed, _ in
if observed.isReadyForDisplay {
// Safe to show the player view
}
}SwiftUI VideoPlayer
The VideoPlayer SwiftUI view wraps AVKit's playback UI.
Basic Usage
import SwiftUI
import AVKit
struct PlayerView: View {
@State private var player: AVPlayer?
var body: some View {
Group {
if let player {
VideoPlayer(player: player)
.frame(height: 300)
} else {
ProgressView()
}
}
.task {
let url = URL(string: "https://example.com/video.m3u8")!
player = AVPlayer(url: url)
}
}
}Video Overlay
Add a SwiftUI overlay above the video content and below the system playback controls. The overlay can be interactive, but it only receives events the system controls do not handle.
VideoPlayer(player: player) {
VStack {
Spacer()
HStack {
Image("logo")
.resizable()
.frame(width: 40, height: 40)
.padding()
Spacer()
}
}
}UIKit Hosting for Advanced Control
VideoPlayer does not expose all AVPlayerViewController properties. For PiP configuration, delegate callbacks, or playback speed control, wrap AVPlayerViewController in a UIViewControllerRepresentable. See the full pattern in references/avkit-patterns.md.
Picture-in-Picture
PiP lets users watch video in a floating window while using other apps. AVPlayerViewController supports PiP automatically once the app is configured, the device supports PiP, and the current AVPlayerItem is playable video content in an AVPlayer-compatible format. Audio-only items, unsupported containers/codecs, or items that are not ready to display video can make PiP unavailable even when app and device setup are correct. For custom player UIs, use AVPictureInPictureController directly.
Prerequisites
- Audio session category set to
.playback(see Setup) - Background Modes > Audio, AirPlay, and Picture in Picture enabled
- Ready
AVPlayerItemwith playable video media, not audio-only content - Current playback context allows PiP; for custom players, observe
isPictureInPicturePossible
Standard Player PiP
PiP is enabled by default on AVPlayerViewController. Control automatic activation and inline-to-PiP transitions:
let playerVC = AVPlayerViewController()
playerVC.player = player
// PiP enabled by default; set false to disable
playerVC.allowsPictureInPicturePlayback = true
// Auto-start PiP when app backgrounds (for inline/non-fullscreen players)
playerVC.canStartPictureInPictureAutomaticallyFromInline = trueRestoring the UI When PiP Stops
When the user taps the restore button in PiP, implement the delegate method to re-present your player. Call the completion handler with true to signal the system to finish the restore animation.
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
// Re-present or re-embed the player view controller
present(playerViewController, animated: false) {
completionHandler(true)
}
}Custom Player PiP
For custom player UIs, use AVPictureInPictureController with an AVPlayerLayer or sample buffer content source. Check device support before creating PiP UI, then check the controller's isPictureInPicturePossible before starting PiP in the current playback context. See references/avkit-patterns.md for full custom player and sample buffer PiP patterns.
More from dpearson2699
Use this skill in a project
Open any RiverX project, search the Skills panel for dpearson2699/swift-ios-skills/avkit, and install it in one click.
