AVKit
Interface de lecture multimédia haut niveau basée sur AVFoundation. Fournit des lecteurs vidéo standard du système, le Picture-in-Picture, le routage AirPlay, les contrôles de transport et l'affichage des sous-titres/légendes. Cible Swift 6.3 / iOS 26+.
Sommaire
- Configuration
- AVPlayerViewController
- SwiftUI VideoPlayer
- Picture-in-Picture
- AirPlay
- Contrôles de transport et vitesse de lecture
- Sous-titres et légendes
- Erreurs courantes
- Checklist de revue
- Références
Configuration
Configuration de la session audio
Configurez la session audio et les modes d'arrière-plan avant toute lecture. Sans cela, le PiP et l'audio en arrière-plan échouent silencieusement.
- Ajoutez le mode d'arrière-plan
audioàUIBackgroundModesdans Info.plist - Définissez la catégorie de la session audio sur
.playback
import AVFoundation
func configureAudioSession() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playback, mode: .moviePlayback)
try session.setActive(true)
} catch {
print("La configuration de la session audio a échoué : \(error)")
}
}
Imports
import AVKit // AVPlayerViewController, VideoPlayer, PiP
import AVFoundation // AVPlayer, AVPlayerItem, AVAsset
AVPlayerViewController
AVPlayerViewController est le lecteur standard UIKit. Il fournit les contrôles de lecture système, le PiP, AirPlay, les sous-titres et l'analyse d'image prêts à l'emploi. Ne le sous-classez pas.
Présentation de base (plein écran)
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()
}
}
Lecture intégrée (inline)
Ajoutez AVPlayerViewController comme contrôleur enfant pour une lecture intégrée. Appelez addChild, ajoutez la vue avec des contraintes, puis appelez 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)
}
Propriétés clés
playerVC.showsPlaybackControls = true // Afficher/masquer les contrôles système
playerVC.videoGravity = .resizeAspect // .resizeAspectFill pour recadrer
playerVC.entersFullScreenWhenPlaybackBegins = false
playerVC.exitsFullScreenWhenPlaybackEnds = true
playerVC.updatesNowPlayingInfoCenter = true // Met à jour automatiquement MPNowPlayingInfoCenter
Utilisez contentOverlayView pour ajouter des vues non interactives (filigranes, logos) entre la vidéo et les contrôles de transport.
Délégué
Adoptez AVPlayerViewControllerDelegate pour répondre aux transitions plein écran, aux événements du cycle de vie PiP, à la lecture interstitielle et aux changements de sélection de média. Utilisez le coordinateur de transition animate(alongsideTransition:completion:) pour synchroniser votre interface utilisateur avec les animations plein écran.
État d'affichage prêt
Observez isReadyForDisplay avant d'afficher le lecteur pour éviter un flash noir :
let observation = playerVC.observe(\.isReadyForDisplay) { observed, _ in
if observed.isReadyForDisplay {
// Sécurisé pour afficher la vue du lecteur
}
}
SwiftUI VideoPlayer
La vue SwiftUI VideoPlayer encapsule l'interface de lecture d'AVKit.
Utilisation de base
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)
}
}
}
Superposition vidéo
Ajoutez une superposition SwiftUI non interactive sur le contenu vidéo.
VideoPlayer(player: player) {
VStack {
Spacer()
HStack {
Image("logo")
.resizable()
.frame(width: 40, height: 40)
.padding()
Spacer()
}
}
}
Hébergement UIKit pour un contrôle avancé
VideoPlayer n'expose pas toutes les propriétés de AVPlayerViewController. Pour la configuration PiP, les callbacks délégués ou le contrôle de la vitesse de lecture, encapsulez AVPlayerViewController dans un UIViewControllerRepresentable. Voir le modèle complet dans references/avkit-patterns.md.
Picture-in-Picture
Le PiP permet aux utilisateurs de regarder une vidéo dans une fenêtre flottante tout en utilisant d'autres applications. AVPlayerViewController prend en charge le PiP automatiquement une fois la session audio configurée. Pour les interfaces utilisateur personnalisées, utilisez directement AVPictureInPictureController.
Prérequis
- Catégorie de session audio définie sur
.playback(voir Configuration) - Mode d'arrière-plan
audiodansUIBackgroundModes
PiP du lecteur standard
Le PiP est activé par défaut sur AVPlayerViewController. Contrôlez l'activation automatique et les transitions inline-vers-PiP :
let playerVC = AVPlayerViewController()
playerVC.player = player
// PiP activé par défaut ; définir false pour désactiver
playerVC.allowsPictureInPicturePlayback = true
// Démarrer automatiquement le PiP lorsque l'application passe en arrière-plan (pour les lecteurs inline/non plein écran)
playerVC.canStartPictureInPictureAutomaticallyFromInline = true
Restaurer l'interface utilisateur lorsque le PiP s'arrête
Lorsque l'utilisateur appuie sur le bouton de restauration dans PiP, implémentez la méthode déléguée pour représenter votre lecteur. Appelez le gestionnaire d'achèvement avec true pour signaler au système de terminer l'animation de restauration.
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
// Ré-afficher ou ré-intégrer le contrôleur de vue du lecteur
present(playerViewController, animated: false) {
completionHandler(true)
}
}
PiP du lecteur personnalisé
Pour les interfaces utilisateur personnalisées, utilisez AVPictureInPictureController avec un AVPlayerLayer ou une source de contenu basée sur un échantillon tampon. Vérifiez d'abord isPictureInPictureSupported(). Voir references/avkit-patterns.md pour les modèles complets de lecteur personnalisé et de PiP basé sur un échantillon tampon.
guard AVPictureInPictureController.isPictureInPictureSupported() else { return }
let pipController = AVPictureInPictureController(playerLayer: playerLayer)
pipController.delegate = self
pipController.canStartPictureInPictureAutomaticallyFromInline = true
Lecture linéaire pendant les publicités
Empêchez la recherche pendant les publicités ou les avis légaux en basculant requiresLinearPlayback :
// Pendant une publicité
playerVC.requiresLinearPlayback = true
// Une fois la publicité terminée
playerVC.requiresLinearPlayback = false
AirPlay
AVPlayerViewController prend en charge AirPlay automatiquement. Aucun code supplémentaire n'est nécessaire lors de l'utilisation du lecteur standard. Le système affiche le bouton AirPlay dans les contrôles de transport lorsque des appareils compatibles AirPlay sont disponibles.
AVRoutePickerView
Ajoutez un bouton de sélecteur d'itinéraire AirPlay autonome en dehors de l'interface du lecteur :
import AVKit
func addRoutePicker(to containerView: UIView) {
let routePicker = AVRoutePickerView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
routePicker.activeTintColor = .systemBlue
routePicker.prioritizesVideoDevices = true // Afficher d'abord les itinéraires vidéo compatibles
containerView.addSubview(routePicker)
}
Activation de la lecture externe
Assurez-vous que AVPlayer permet la lecture externe (activée par défaut) :
player.allowsExternalPlayback = true
player.usesExternalPlaybackWhileExternalScreenIsActive = true
Contrôles de transport et vitesse de lecture
Vitesses de lecture personnalisées
Fournissez des vitesses de lecture sélectionnables par l'utilisateur dans l'interface du lecteur :
let playerVC = AVPlayerViewController()
playerVC.speeds = [
AVPlaybackSpeed(rate: 0.5, localizedName: "Demi-vitesse"),
AVPlaybackSpeed(rate: 1.0, localizedName: "Normale"),
AVPlaybackSpeed(rate: 1.5, localizedName: "1.5x"),
AVPlaybackSpeed(rate: 2.0, localizedName: "Double vitesse")
]
Utilisez AVPlaybackSpeed.systemDefaultSpeeds pour restaurer les options de vitesse par défaut.
Comportement de saut
Configurez les commandes de saut avant/arrière :
playerVC.isSkipForwardEnabled = true
playerVC.isSkipBackwardEnabled = true
Intégration Now Playing
AVPlayerViewController met à jour MPNowPlayingInfoCenter automatiquement par défaut. Désactivez cette option si vous gérez manuellement les informations Now Playing :
playerVC.updatesNowPlayingInfoCenter = false
Sous-titres et légendes
AVKit gère automatiquement l'affichage des sous-titres et des légendes lorsque le média contient des pistes de texte appropriées. Les utilisateurs contrôlent les préférences de sous-titres dans Réglages > Accessibilité > Sous-titres et légendage.
Restreindre les langues des sous-titres
// Afficher uniquement les options de sous-titres en anglais et en espagnol
playerVC.allowedSubtitleOptionLanguages = ["en", "es"]
Exiger les sous-titres
Forcer l'affichage permanent des sous-titres (l'utilisateur ne peut pas les désactiver) :
playerVC.requiresFullSubtitles = true
Sélection de média (délégué)
Réagissez au changement de sélection de piste de sous-titres ou audio par l'utilisateur :
func playerViewController(
_ playerViewController: AVPlayerViewController,
didSelect mediaSelectionOption: AVMediaSelectionOption?,
in mediaSelectionGroup: AVMediaSelectionGroup
) {
if let option = mediaSelectionOption {
print("Sélectionné : \(option.displayName)")
}
}
Fournir des pistes de sous-titres dans HLS
Les sous-titres et légendes sont intégrés dans les manifests HLS. AVKit les lit à partir de AVMediaSelectionGroup sur l'AVAsset. Pour les fichiers locaux, utilisez AVMutableComposition pour ajouter des pistes AVMediaCharacteristic.legible.
Erreurs courantes
NE PAS : Sous-classer AVPlayerViewController
Apple déclare explicitement que cela n'est pas pris en charge. Cela peut provoquer un comportement indéfini ou un crash sur les futures versions du système d'exploitation.
// FAUX
class MyPlayerVC: AVPlayerViewController { } // Non pris en charge
// CORRECT : Utiliser la composition avec délégation
let playerVC = AVPlayerViewController()
playerVC.delegate = coordinator
NE PAS : Ignorer la configuration de la session audio pour PiP
Le PiP échoue silencieusement si la session audio n'est pas définie sur .playback. L'audio en arrière-plan cesse également de fonctionner.
// FAUX : Session audio par défaut
let playerVC = AVPlayerViewController()
playerVC.player = player // PiP ne fonctionnera pas
// CORRECT : Configurer d'abord la session audio
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
try AVAudioSession.sharedInstance().setActive(true)
let playerVC = AVPlayerViewController()
playerVC.player = player
NE PAS : Oublier le délégué de restauration PiP ou son gestionnaire d'achèvement
Sans restoreUserInterfaceForPictureInPictureStopWithCompletionHandler, le système ne peut pas ramener l'utilisateur à votre lecteur. Ne pas appeler completionHandler(true) laisse le système dans un état incohérent.
// FAUX : Pas de méthode déléguée ou appel manquant à completionHandler
// L'utilisateur appuie sur restaurer dans PiP -> rien ne se passe ou l'animation se bloque
// CORRECT
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
present(playerViewController, animated: false) {
completionHandler(true)
}
}
NE PAS : Créer AVPlayer dans l'initialiseur d'une vue SwiftUI
Créer le lecteur avec empressement provoque des problèmes de performances. SwiftUI peut recréer la vue plusieurs fois.
// FAUX : Créé à chaque initialisation de vue
struct PlayerView: View {
let player = AVPlayer(url: videoURL) // Recréé à chaque évaluation de vue
var body: some View { VideoPlayer(player: player) }
}
// CORRECT : Utiliser @State et différer la création
struct PlayerView: View {
@State private var player: AVPlayer?
var body: some View {
VideoPlayer(player: player)
.task { player = AVPlayer(url: videoURL) }
}
}
Checklist de revue
- Catégorie de session audio définie sur
.playbackavecmode: .moviePlayback - Mode d'arrière-plan
audioajouté àUIBackgroundModesdans Info.plist -
AVPlayerViewControllern'est pas sous-classé - Méthode déléguée de restauration PiP implémentée et appelle
completionHandler(true) -
AVPlayerdifféré avec.taskdans SwiftUI (pas créé avec empressement) -
canStartPictureInPictureAutomaticallyFromInlinedéfini pour les lecteurs intégrés -
requiresLinearPlaybackbasculé uniquement pendant les segments publicitaires/légaux requis -
allowsExternalPlaybackactivé surAVPlayerpour la prise en charge AirPlay - Restrictions de langue des sous-titres testées avec des pistes média réelles
- Gravité vidéo définie de manière appropriée (
.resizeAspectvs.resizeAspectFill) -
isReadyForDisplayobservé avant d'afficher la vue du lecteur - Gestion des erreurs pour le contenu diffusé en réseau (échecs HLS, timeouts)
Références
- Modèles avancés (interface utilisateur de lecteur personnalisée, interstitiels, lecture en arrière-plan, gestion des erreurs) : references/avkit-patterns.md
- Framework AVKit
- AVPlayerViewController
- VideoPlayer (SwiftUI)