Communitygithub.com

JordanCoin/ios-skills-collection

Crie experiências de reprodução de mídia usando AVKit. Use ao adicionar players de vídeo com AVPlayerViewController, ativar Picture-in-Picture, rotear mídia com AirPlay, usar visualizações SwiftUI VideoPlayer, configurar controles de transporte, exibir legendas e closed captions, ou integrar reprodução AVFoundation com a interface do sistema.

O que é ios-skills-collection?

Esta skill fornece um guia abrangente para implementar experiências de reprodução de mídia em iOS usando o framework AVKit da Apple. AVKit oferece componentes de alto nível para players de vídeo, Picture-in-Picture (PiP), roteamento AirPlay e controles de transporte, tudo construído sobre o AVFoundation. A skill cobre tanto UIKit (AVPlayerViewController) quanto SwiftUI (VideoPlayer), explicando como configurar a sessão de áudio, apresentar players em tela cheia ou incorporados, e gerenciar legendas e closed captions. É particularmente útil para desenvolvedores iOS que precisam adicionar recursos de reprodução de vídeo padrão do sistema, como PiP e AirPlay, com o mínimo de código personalizado, evitando erros comuns como subclassificar AVPlayerViewController ou esquecer a configuração da sessão de áudio. A documentação inclui exemplos de código detalhados, uma lista de verificação de revisão e referências a padrões avançados para cenários mais complexos.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/JordanCoin/ios-skills-collection/tree/HEAD/skills/dpearson2699--avkit

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

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

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.

  1. Adicione o modo de fundo audio a UIBackgroundModes no Info.plist
  2. 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

  1. Categoria da sessão de áudio definida como .playback (veja Configuração)
  2. Modo de fundo audio em UIBackgroundModes

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 .playback com mode: .moviePlayback
  • Modo de fundo audio adicionado a UIBackgroundModes no Info.plist
  • AVPlayerViewController não é subclassificado
  • Método delegado de restauração PiP implementado e chama completionHandler(true)
  • AVPlayer adiado para .task no SwiftUI (não criado antecipadamente)
  • canStartPictureInPictureAutomaticallyFromInline definido para players inline
  • requiresLinearPlayback alternado apenas durante segmentos obrigatórios de anúncios/legais
  • allowsExternalPlayback ativado em AVPlayer para suporte AirPlay
  • Restrições de idioma de legenda testadas com faixas de mídia reais
  • Gravidade do vídeo definida apropriadamente (.resizeAspect vs .resizeAspectFill)
  • isReadyForDisplay observado antes de mostrar a visualização do player
  • Tratamento de erros para conteúdo transmitido pela rede (falhas HLS, timeouts)

Referências

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

JordanCoin/ios-skills-collection

Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries. Use when the user asks about GitHub issues, pull requests, workflows, or wants to interact with GitHub repositories from the command line — including tasks like check CI status, create PR, list issues, or query the GitHub API.

JordanCoin/ios-skills-collection

Integrate and optimize Core ML models in iOS apps for on-device machine learning inference. Covers model loading (.mlmodelc, .mlpackage), predictions with auto-generated classes and MLFeatureProvider, compute unit configuration (CPU, GPU, Neural Engine), MLTensor, VNCoreMLRequest, MLComputePlan, multi-model pipelines, and deployment strategies. Use when loading Core ML models, making predictions, configuring compute units, or profiling model performance.

JordanCoin/ios-skills-collection

Implement, review, or improve maps and location features in iOS/macOS apps using MapKit and CoreLocation. Use when working with Map views, annotations, markers, polylines, user location tracking, geocoding, reverse geocoding, search/autocomplete, directions and routes, geofencing, region monitoring, CLLocationUpdate async streams, or location authorization flows. Also use when working with maps, coordinates, addresses, places, directions, distance calculations, or location-based features in Swift apps.

JordanCoin/ios-skills-collection

Display and manipulate PDF documents using PDFKit. Use when embedding PDFView to show PDF files, creating or modifying PDFDocument instances, adding annotations (highlights, notes, signatures), extracting text with PDFSelection, navigating pages, generating thumbnails, filling PDF forms, or wrapping PDFView in SwiftUI.

JordanCoin/ios-skills-collection

Implement, review, or improve in-app tips and onboarding using Apple's TipKit framework. Use when adding feature discovery tooltips, onboarding flows, contextual tips, first-run experiences, coach marks, or working with Tip protocol, TipView, popoverTip, tip rules, tip events, or feature education UI.

JordanCoin/ios-skills-collection

When the user wants to optimize their Google Play Store listing — title, short description, full description, keywords, ratings, or Play Store-specific features. Use when the user mentions "Google Play", "Android", "Play Store", "Play Console", "short description", "full description indexed", "Google Play ASO", or wants Google Play-specific keyword, creative, or ratings strategy. For iOS App Store optimization, see aso-audit and metadata-optimization.

JordanCoin/ios-skills-collection

When the user wants to implement, optimize, or use App Clips for app discovery and conversion. Use when the user mentions "App Clip", "app clip code", "mini app", "instant app", "App Clip card", "App Clip link", "no download required", "instant experience", or wants to understand how App Clips appear in App Store search. For general App Store discoverability, see aso-audit. For marketing campaigns, see ua-campaign.

JordanCoin/ios-skills-collection

When the user wants to plan a launch strategy for a new app or major update. Also use when the user mentions "app launch", "launch plan", "launch checklist", "pre-launch", "launch day", or "how to launch my app". For ongoing ASO after launch, see aso-audit. For paid acquisition during launch, see ua-campaign.

JordanCoin/ios-skills-collection

When the user wants to analyze their own app's actual performance data from App Store Connect — real downloads, revenue, IAP, subscriptions, trials, or country breakdowns synced via Appeeky Connect. Use when the user asks about "my downloads", "my revenue", "how is my app performing", "ASC data", "sales and trends", "my subscription numbers", "App Store Connect metrics", or wants to compare periods or top markets. For third-party app estimates, see app-analytics. For subscription analytics depth, see monetization-strategy.

JordanCoin/ios-skills-collection

When the user wants a full ASO health audit, review their App Store listing quality, or diagnose why their app isn't ranking. Also use when the user mentions "ASO audit", "ASO score", "why am I not ranking", "listing review", or "optimize my app store page". For keyword-specific research, see keyword-research. For metadata writing, see metadata-optimization.

JordanCoin/ios-skills-collection

Always use when working on any iOS, macOS, Swift, SwiftUI, Xcode, or Apple platform project. Routes to the correct specialized skills based on development phase and task context. This collection contains 210 skills from 28 authors covering the full iOS lifecycle.

Habilidades Relacionadas