AVKit
Interface de reprodução de mídia de alto nível construída sobre AVFoundation. Fornece players de vídeo padrão do sistema, Picture-in-Picture, roteamento AirPlay, controles de transporte e exibição de legendas/closed captions. Destinado a Swift 6.3 / iOS 26+.
Conteúdo
- Configuração
- AVPlayerViewController
- SwiftUI VideoPlayer
- Picture-in-Picture
- AirPlay
- Controles de Transporte e Velocidade de Reprodução
- Legendas e Closed Captions
- Erros Comuns
- Lista de Verificação de Revisão
- Referências
Configuração
Configuração da Sessão de Áudio
Configure a sessão de áudio e os modos de fundo antes de qualquer reprodução. Sem isso, o PiP e o áudio em segundo plano falham silenciosamente.
- Adicione o modo de fundo
audioaUIBackgroundModesno Info.plist - Defina a categoria da sessão de áudio como
.playback
import AVFoundation
func configureAudioSession() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playback, mode: .moviePlayback)
try session.setActive(true)
} catch {
print("Falha na configuração da sessão de áudio: \(error)")
}
}
Imports
import AVKit // AVPlayerViewController, VideoPlayer, PiP
import AVFoundation // AVPlayer, AVPlayerItem, AVAsset
AVPlayerViewController
AVPlayerViewController é o player UIKit padrão. Ele fornece controles de reprodução do sistema, PiP, AirPlay, legendas e análise de quadros prontos para uso. Não o subclassifique.
Apresentação Básica (Tela Cheia)
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()
}
}
Reprodução Inline (Embutida)
Adicione AVPlayerViewController como um controlador filho para reprodução inline. Chame addChild, adicione a view com constraints e, em seguida, chame 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)
}
Propriedades Principais
playerVC.showsPlaybackControls = true // Mostrar/ocultar controles do sistema
playerVC.videoGravity = .resizeAspect // .resizeAspectFill para recortar
playerVC.entersFullScreenWhenPlaybackBegins = false
playerVC.exitsFullScreenWhenPlaybackEnds = true
playerVC.updatesNowPlayingInfoCenter = true // Atualiza automaticamente o MPNowPlayingInfoCenter
Use contentOverlayView para adicionar visualizações não interativas (marcas d'água, logotipos) entre o vídeo e os controles de transporte.
Delegado
Adote AVPlayerViewControllerDelegate para responder a transições de tela cheia, eventos do ciclo de vida do PiP, reprodução de intersticiais e alterações na seleção de mídia. Use o coordenador de transição animate(alongsideTransition:completion:) para sincronizar sua UI com animações de tela cheia.
Prontidão para Exibição
Observe isReadyForDisplay antes de mostrar o player para evitar um flash preto:
let observation = playerVC.observe(\.isReadyForDisplay) { observed, _ in
if observed.isReadyForDisplay {
// Seguro para mostrar a view do player
}
}
SwiftUI VideoPlayer
A visualização SwiftUI VideoPlayer encapsula a UI de reprodução do AVKit.
Uso Básico
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)
}
}
}
Sobreposição de Vídeo
Adicione uma sobreposição SwiftUI não interativa sobre o conteúdo do vídeo.
VideoPlayer(player: player) {
VStack {
Spacer()
HStack {
Image("logo")
.resizable()
.frame(width: 40, height: 40)
.padding()
Spacer()
}
}
}
Hospedagem UIKit para Controle Avançado
VideoPlayer não expõe todas as propriedades de AVPlayerViewController. Para configuração de PiP, callbacks de delegado ou controle de velocidade de reprodução, encapsule AVPlayerViewController em um UIViewControllerRepresentable. Veja o padrão completo em references/avkit-patterns.md.
Picture-in-Picture
PiP permite que os usuários assistam a vídeos em uma janela flutuante enquanto usam outros aplicativos. AVPlayerViewController suporta PiP automaticamente assim que a sessão de áudio é configurada. Para UIs de player personalizadas, use AVPictureInPictureController diretamente.
Pré-requisitos
- Categoria da sessão de áudio definida como
.playback(veja Configuração) - Modo de fundo
audioemUIBackgroundModes
PiP com Player Padrão
PiP é ativado por padrão em AVPlayerViewController. Controle a ativação automática e transições inline para PiP:
let playerVC = AVPlayerViewController()
playerVC.player = player
// PiP ativado por padrão; defina false para desativar
playerVC.allowsPictureInPicturePlayback = true
// Iniciar PiP automaticamente quando o app for para segundo plano (para players inline/não tela cheia)
playerVC.canStartPictureInPictureAutomaticallyFromInline = true
Restaurando a UI Quando o PiP Para
Quando o usuário tocar no botão de restaurar no PiP, implemente o método do delegado para reapresentar seu player. Chame o bloco de conclusão com true para sinalizar ao sistema que finalize a animação de restauração.
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
// Reapresente ou reembuta o controlador de visualização do player
present(playerViewController, animated: false) {
completionHandler(true)
}
}
PiP com Player Personalizado
Para UIs de player personalizadas, use AVPictureInPictureController com um AVPlayerLayer ou fonte de conteúdo de buffer de amostra. Verifique isPictureInPictureSupported() primeiro. Veja references/avkit-patterns.md para padrões completos de PiP com player personalizado e buffer de amostra.
guard AVPictureInPictureController.isPictureInPictureSupported() else { return }
let pipController = AVPictureInPictureController(playerLayer: playerLayer)
pipController.delegate = self
pipController.canStartPictureInPictureAutomaticallyFromInline = true
Reprodução Linear Durante Anúncios
Impeça a busca durante anúncios ou avisos legais alternando requiresLinearPlayback:
// Durante um anúncio
playerVC.requiresLinearPlayback = true
// Após a conclusão do anúncio
playerVC.requiresLinearPlayback = false
AirPlay
AVPlayerViewController suporta AirPlay automaticamente. Nenhum código adicional é necessário ao usar o player padrão. O sistema exibe o botão AirPlay nos controles de transporte quando dispositivos compatíveis com AirPlay estão disponíveis.
AVRoutePickerView
Adicione um botão seletor de rota AirPlay independente fora da UI do player:
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 // Mostra primeiro rotas com capacidade de vídeo
containerView.addSubview(routePicker)
}
Ativando Reprodução Externa
Garanta que AVPlayer permita reprodução externa (ativada por padrão):
player.allowsExternalPlayback = true
player.usesExternalPlaybackWhileExternalScreenIsActive = true
Controles de Transporte e Velocidade de Reprodução
Velocidades de Reprodução Personalizadas
Forneça velocidades de reprodução selecionáveis pelo usuário na UI do player:
let playerVC = AVPlayerViewController()
playerVC.speeds = [
AVPlaybackSpeed(rate: 0.5, localizedName: "Meia Velocidade"),
AVPlaybackSpeed(rate: 1.0, localizedName: "Normal"),
AVPlaybackSpeed(rate: 1.5, localizedName: "1.5x"),
AVPlaybackSpeed(rate: 2.0, localizedName: "Velocidade Dupla")
]
Use AVPlaybackSpeed.systemDefaultSpeeds para restaurar as opções de velocidade padrão.
Comportamento de Avanço/Retrocesso
Configure os controles de avanço/retrocesso:
playerVC.isSkipForwardEnabled = true
playerVC.isSkipBackwardEnabled = true
Integração com Agora Tocando
AVPlayerViewController atualiza MPNowPlayingInfoCenter automaticamente por padrão. Desative isso se você gerenciar as informações de "Agora Tocando" manualmente:
playerVC.updatesNowPlayingInfoCenter = false
Legendas e Closed Captions
AVKit gerencia a exibição de legendas e closed captions automaticamente quando a mídia contém as faixas de texto apropriadas. Os usuários controlam as preferências de legendas em Ajustes > Acessibilidade > Legendas e Closed Captions.
Restringindo Idiomas de Legendas
// Mostrar apenas opções de legenda em inglês e espanhol
playerVC.allowedSubtitleOptionLanguages = ["en", "es"]
Exigindo Legendas
Force que as legendas sejam sempre exibidas (o usuário não pode desativá-las):
playerVC.requiresFullSubtitles = true
Seleção de Mídia (Delegado)
Responda à alteração da seleção de faixa de legenda ou áudio pelo usuário:
func playerViewController(
_ playerViewController: AVPlayerViewController,
didSelect mediaSelectionOption: AVMediaSelectionOption?,
in mediaSelectionGroup: AVMediaSelectionGroup
) {
if let option = mediaSelectionOption {
print("Selecionado: \(option.displayName)")
}
}
Fornecendo Faixas de Legenda em HLS
Legendas e closed captions são incorporados em manifestos HLS. AVKit os lê de AVMediaSelectionGroup no AVAsset. Para arquivos locais, use AVMutableComposition para adicionar faixas AVMediaCharacteristic.legible.
Erros Comuns
NÃO: Subclassificar AVPlayerViewController
A Apple afirma explicitamente que isso não é suportado. Pode causar comportamento indefinido ou falha em versões futuras do sistema.
// ERRADO
class MyPlayerVC: AVPlayerViewController { } // Não suportado
// CORRETO: Use composição com delegação
let playerVC = AVPlayerViewController()
playerVC.delegate = coordinator
NÃO: Pular a configuração da sessão de áudio para PiP
PiP falha silenciosamente se a sessão de áudio não estiver definida como .playback. O áudio em segundo plano também para de funcionar.
// ERRADO: Sessão de áudio padrão
let playerVC = AVPlayerViewController()
playerVC.player = player // PiP não funcionará
// CORRETO: Configure a sessão de áudio primeiro
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
try AVAudioSession.sharedInstance().setActive(true)
let playerVC = AVPlayerViewController()
playerVC.player = player
NÃO: Esquecer o delegado de restauração do PiP ou seu bloco de conclusão
Sem restoreUserInterfaceForPictureInPictureStopWithCompletionHandler, o sistema não pode retornar o usuário ao seu player. Deixar de chamar completionHandler(true) deixa o sistema em um estado inconsistente.
// ERRADO: Sem método delegado ou chamada de completionHandler ausente
// O usuário toca em restaurar no PiP -> nada acontece ou a animação trava
// CORRETO
func playerViewController(
_ playerViewController: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
present(playerViewController, animated: false) {
completionHandler(true)
}
}
NÃO: Criar AVPlayer no init de uma visualização SwiftUI
Criar o player antecipadamente causa problemas de desempenho. O SwiftUI pode recriar a visualização várias vezes.
// ERRADO: Criado em cada init de visualização
struct PlayerView: View {
let player = AVPlayer(url: videoURL) // Recriado em cada avaliação da visualização
var body: some View { VideoPlayer(player: player) }
}
// CORRETO: Use `@State` e adie a criação
struct PlayerView: View {
@State private var player: AVPlayer?
var body: some View {
VideoPlayer(player: player)
.task { player = AVPlayer(url: videoURL) }
}
}
Lista de Verificação de Revisão
- Categoria da sessão de áudio definida como
.playbackcommode: .moviePlayback - Modo de fundo
audioadicionado aUIBackgroundModesno Info.plist -
AVPlayerViewControllernão é subclassificado - Método delegado de restauração PiP implementado e chama
completionHandler(true) -
AVPlayeradiado para.taskno SwiftUI (não criado antecipadamente) -
canStartPictureInPictureAutomaticallyFromInlinedefinido para players inline -
requiresLinearPlaybackalternado apenas durante segmentos obrigatórios de anúncios/legais -
allowsExternalPlaybackativado emAVPlayerpara suporte AirPlay - Restrições de idioma de legenda testadas com faixas de mídia reais
- Gravidade do vídeo definida apropriadamente (
.resizeAspectvs.resizeAspectFill) -
isReadyForDisplayobservado antes de mostrar a visualização do player - Tratamento de erros para conteúdo transmitido pela rede (falhas HLS, timeouts)
Referências
- Padrões avançados (UI de player personalizada, intersticiais, reprodução em segundo plano, tratamento de erros): references/avkit-patterns.md
- Framework AVKit
- AVPlayerViewController
- VideoPlayer (SwiftUI)