DRM-X 6.0 logo de pomba e ramo de oliveiraDRM-X 6.0Documentação
◎ Português

SDK Android e Media3 nativo

Baixe o Android reprodutor com controles em vídeo, listas de reprodução arrastáveis, shuffle/repeat salvos e currículo offline. Integre reprodução protegida usando DRM-X ou nativo Media3.

Ver MarkdownExemplos onlineAtualizado em 2026-09-14
Escolha seu reprodutor, mantenha um serviço de licença.Utilizar o DRM-X 6.0 Android SDK para uma integração guiada, ou manter seu nativo Media3 reprodutor. Ambos se conectam à sua infraestrutura autenticada e Widevine. A Android SDK suporta streaming e off-line persistente VOD em compatível API 23+ dispositivos, incluindo telefones, tablets, TVs e incorporados Android sistemas.

Tente o Android reprodutor #

Baixe, instale, pressione Play.A aplicação de avaliação gratuita utiliza o nosso vídeo demo público e assina automaticamente. Não é necessário criar um APK ou inserir DRM-X credenciais para o experimentar.

Baixar a amostra Android APK

1.0.0-preview.12 · 7.02 MB · Android 6.0+ (API 23+) · DRM-X 6.0 Player · Atualizado 2026-09-14

  1. Abra esta página no seu telefone Android e baixe o APK.
  2. Abra o arquivo baixado. Se Android perguntar, permita a instalação do navegador ou gerenciador de arquivos que você usou, então toque em Instalar .
  3. Abrir DRM-X 6.0 player, mantenha-se ligado, e toque no vídeo Reproduzir botão. O aplicativo solicita uma licença de streaming quando você pressiona Play.
  4. Abrir Configurações para escolher a qualidade, áudio, legendas ou velocidade de reprodução. Rodar o telefone para continuar em tela cheia.
  5. Toque em Baixar para o vídeo atual ou Obter lista de reprodução para todos VOD itens. Os downloads usam a versão licenciada mais suportada até 1080p em L1, ou 480p em L3. Reproduzir offline abre a lista de reprodução local completa com próxima/anterior, embaralhamento, repetição e reprodução automática; Ir em linha retorna para a lista completa. Renovar renova a licença selecionada enquanto estiver conectado.

Os downloads de mídia já em fila de espera continuam em segundo plano. Se Android parar o aplicativo enquanto prepara licenças ou faixas, reabri-lo enquanto estiver conectado para terminar a preparação dos itens restantes. Os downloads existentes são retidos. A reprodução offline usa apenas mídia em cache; downloads incompletos ou expirados requerem conclusão ou renovação.

Widevine Falhas de provisionamento (Media3 6002) agora use um relé de demo-servidor autenticado para o serviço oficial do Google. L3 CDM pode receber SD chaves. Um dispositivo sem funcionamento Widevine a implementação necessita de um dispositivo/firmware fixo; uma licença não pode adicionar faltando DRM apoio.

A amostra APK é pública e assinada para avaliação. O AAR e o SDK completo abaixo permanecem disponíveis através de contas de Console elegíveis. Mantenha sua própria chave de assinatura de aplicativo de produção e login de infraestrutura separados desta demonstração.

APK checksum e USB instalação

SHA-256:

8fa044b82c0abab7ce2a987f349524fd7ad1e78f3c897771f4764cb2aa521180

Com ferramentas de plataforma Android e um dispositivo autorizado USB:

adb install -r drmx-android-player-1.0.0-preview.12.apk

Instale este APK sobre a amostra oficial existente sem desinstalá- lo. A mesma chave de assinatura e aplicação ID preservar downloads, licenças offline, posições salvas e preferências. Se o seu próprio build usar outra chave de assinatura, use um aplicativo separado ID para manter ambos os aplicativos e preservar as licenças offline da amostra.

O que há de novo em Android reprodutor preview.12#

Lançado em 14 de setembro de 2026. Corrige a reprodução transferida, fazendo uma solicitação de licença inesperada quando uma licença Widevine expirar ou tiver um minuto ou menos restante. Isto pode aparecer como Media3 erro 6004, um erro HTTP enquanto estiver conectado, ou um erro DNS enquanto estiver desconectado.

A reprodutor agora restaura a licença baixada localmente. As licenças válidas mantêm o tempo restante de reprodução; as licenças expiradas mostram Conectar e tocar em Renovar . As regras de validade e proteção da licença continuam a ser aplicadas pelo dispositivo. Os diagnósticos também incluem o status numérico HTTP quando uma operação de rede falha, sem expor cabeçalhos de requisição, URLs ou respostas de licença.

  1. Instale preview.12 sobre o aplicativo oficial existente. Mantenha seus dados e downloads atuais do aplicativo.
  2. Se WayMaker ou outro vídeo baixado precisar de renovação, conecte-se à internet, selecione esse vídeo e toque em Renew.
  3. Aguarde por Licença renovada. Pronto para jogar offline. , então escolha Jogue offline . O vídeo criptografado permanece baixado.

Esta versão mantém os controles de antevisão.11 e as funcionalidades da lista de reprodução. A aplicação de avaliação pública e a sua antevisão incorporada reprodutor.12; a Consola separada distribuída SDK permanece pré-visualização.10 / bundle 20260910.8.

O que há de novo em Android reprodutor preview.11#

Lançado em 14 de setembro de 2026. Este aplicativo de avaliação inclui os mais recentes controles reprodutor e melhorias na lista de reprodução, com um estilo de interação consistente entre os nossos Android e Apple reprodutores.

  • Controles dentro do vídeo: centralizado Reproduzir/Pausa, Anterior e Seguinte para playlists multi-vídeo, CC, Configurações e um botão de tela cheia. Controles escondem-se após dois segundos durante a reprodução; toque no vídeo para revelá- los novamente.
  • Capções e configurações de reprodução: use CC para mostrar ou esconder legendas disponíveis, e Configurações para escolher o idioma de legenda, áudio, velocidade de reprodução e qualidade permitida. As escolhas off-line usam apenas faixas incluídas no download.
  • Drag to reorder: arraste o punho de um item da lista de reprodução para alterar a sua posição. A ordem salva sobrevive a uma reiniciação de uma aplicação e é refletida na lista de reprodução baixada. A reordenação mantém o vídeo atual reproduzido. Toque na alça para as ações acessíveis Mover para cima / Descer.
  • Embaralhamento salvo e repetir: os modos seleccionados permanecem realçados e sobrevivem ao reiniciar na reprodução online e offline. Com o embaralhamento e a repetição de ambos, os vídeos seguem a ordem gravada e param após o item final. A acção "Play next" do menu da lista de reprodução foi removida.
  • Resuma onde você parou: a posição de cada vídeo salvo VOD é restaurada quando você retorna à reprodução de streaming ou baixado. O progresso é salvo neste dispositivo para o visualizador atual; ele não sincroniza entre dispositivos.

As alterações reprodutor foram verificadas em um Samsung S24 Ultra, incluindo arrastar playlist durante a reprodução, salvar o pedido após o relançamento, retomar a reprodução e baixar a reprodução com Wi-Fi e dados móveis desativados. A visualização offline ainda requer um download completo e uma licença off-line utilizável e não expirada.

Esta versão atualiza a avaliação pública APK. O Console SDK distribuído separadamente permanece 1.0.0-preview.10, bundle 20260910.8; suas instruções de integração existentes abaixo referem-se a esse pacote.

1. Escolha um caminho de integração#

Transfira o ZIP ou AAR do SDK Android em Console → Integrations. As organizações com Professional ($499/mês) ou Enterprise ativos podem transferi-lo. As contas Trial e Standard não podem transferir o SDK. Esta documentação, incluindo exemplos Media3 nativos, é pública; a reprodução exige uma conta autorizada, conteúdo publicado e um dispositivo compatível.

Current preview: 1.0.0-preview.10 · customer bundle 20260910.8 · Media3 1.11.0. The ZIP contains a local Maven repository, Gradle wrapper, annotated README, phone/TV/native samples, an installable phone sample APK in apks/, and offline integration notes. It contains no customer credentials or protected movies.

2. Prepare seu conteúdo e infraestrutura #

  1. Empacote e publique um título de Widevine compatível com DASH no seu Ambiente DRM-X. Copie o valor exacto Publicado Content ID.
  2. Configurar o servidor Environment ID, Site Key e Access Key. Utilização o download possível PHP integração para um ponto de partida de trabalho.
  3. Implemente a verificação de login e direito do usuário. Seu aplicativo chama sua infraestrutura com seu token de usuário de curta duração; sua infraestrutura escolhe o conteúdo, política e URLs confiáveis.
  4. Execute a reprodução online primeiro em um dispositivo com capacidade física Widevine. Adicione a aquisição offline apenas após o contrato de streaming funcionar.
A aplicação Android autentica-se na infra- estrutura do cliente, que solicita uma sessão DRM-X usando apenas o servidor credenciais. A reprodutor descarrega separadamente os meios codificados e envia um desafio Widevine para o serviço de licença.
Entrega de mídia e entrega de licença são separadas. Somente a infraestrutura do cliente detém DRM-X servidor credenciais.
Alterar este valorOnde pertenceSignificado
ponto final da sessãoAndroidSeu endpoint de reprodução-sessão HTTPS, não o servidor de licença bruto URL.
offlineEndpointAndroid, apenas offlineO seu ponto final de autorização de aquisição/renovação/lançamento.
contentIdAndroid request; a infra- estrutura validaO visualizador tem o direito de acesso protegido pelo Published Content ID.
token de acesso ao clienteMemória da aplicação após o loginSeu token de usuário de curta duração, nunca um Site Key ou Access Key.
Environment ID, Site Key, Access KeyApenas configuração secreta do servidorDRM-X conta credenciaisNunca os envies numa nave. APK, HTML ou controlo da fonte.
Política e manifesto de confiança URLSua infra- estruturaDireito de negócio e mapeamento de pacotes. Não aceite estes a partir do aplicativo.

3. Instalar e executar o SDK#

Open the extracted ZIP's root folder in Android Studio. Use JDK 17, Android SDK 36 and Android Gradle Plugin 9.2.0; the included wrapper uses Gradle 9.4.1. Minimum device API is 23. Build dependencies require internet access. Select samples.phone and Run. Its initial values use the public demo backend and title; follow its sign-in and streaming controls before switching to your own backend.

# Windows
gradlew.bat :samples:phone:assembleDebug
# macOS / Linux
sh gradlew :samples:phone:assembleDebug

Para uma aplicação existente, copie a pasta ZIP maven/ na sua raiz do projecto. Em settings.gradle.kts:

dependencyResolutionManagement {
    repositories {
        maven { url = uri(rootDir.resolve("maven")) }
        google()
        mavenCentral()
    }
}

No módulo do seu aplicativo build.gradle.kts:

dependencies {
    implementation("com.haihaisoft.drmx:drmx-universal-player:1.0.0-preview.10")
}
Instalando o autônomo AAR em vez disso

Coloque o AAR no módulo do seu aplicativo libs/. Um plano AAR não tem resolução de dependência transitiva automática, então adicione as três dependências Media3 correspondentes. Não instale ambos os formulários.

implementation(files("libs/drmx-universal-player-1.0.0-preview.10.aar"))
implementation("androidx.media3:media3-exoplayer:1.11.0")
implementation("androidx.media3:media3-exoplayer-dash:1.11.0")
implementation("androidx.media3:media3-ui:1.11.0")

Em AndroidManifest.xml, permitir o acesso à Internet e desativar backups para esta amostra mínima. Em um aplicativo de produção que precisa de backups, especificamente excluir metadados de licença offline ligado ao dispositivo.

<uses-permission android:name="android.permission.INTERNET" />
<application android:allowBackup="false" android:usesCleartextTraffic="false" ... >

Procure o exemplo de telefone MainActivity.kt para drmx.sessionEndpoint, drmx.offlineEndpoint, drmx.contentId e customer.loginEndpoint. Altere as configurações de recuo marcadas, ou passe estes extras de Intenção de sua aplicação após o login. Passe customer.accessToken em tempo de execução. O ZIP README explica cada parâmetro e quais ganchos de demonstração para substituir.

Construir um teste APK usando o AAR #

Este exemplo usa o projeto de telefone executável a partir do SDK ZIP completo e explicitamente liga o autônomo AAR. A mesma abordagem funciona para uma aplicação Android existente.

  1. Download and extract the full Android SDK ZIP. Open its root folder in Android Studio.
  2. Keep libs/drmx-universal-player-1.0.0-preview.10.aar in the extracted root. Use JDK 17, Android SDK 36 and the included Gradle wrapper.
  3. Em samples/phone/build.gradle.kts, substitua a dependência DRM-X do Maven pelas seguintes entradas dentro dependencies. Mantenha o resto desse arquivo de compilação.
implementation(files(rootProject.file("libs/drmx-universal-player-1.0.0-preview.10.aar")))
implementation("androidx.media3:media3-exoplayer:1.11.0")
implementation("androidx.media3:media3-exoplayer-dash:1.11.0")
implementation("androidx.media3:media3-ui:1.11.0")

Remova implementation("com.haihaisoft.drmx:drmx-universal-player:1.0.0-preview.10") para que o mesmo SDK não seja incluído duas vezes. Um plano AAR precisa das três dependências Media3 mostradas acima.

  1. Para manter o demo baixado instalado ao lado do seu próprio test build, altere o módulo de telefone applicationId para com.example.drmxtest. Deixe seu espaço de nomes inalterado para esta amostra fornecida.
  2. Compilar o APK, em seguida, instalá-lo em um dispositivo USB- conectado Android com USB depuração autorizada.
# Windows, from the extracted SDK root
gradlew.bat :samples:phone:assembleDebug
adb install -r samples/phone/build/outputs/apk/debug/phone-debug.apk

# macOS / Linux
sh gradlew :samples:phone:assembleDebug
adb install -r samples/phone/build/outputs/apk/debug/phone-debug.apk

Abre a aplicação de teste e toque em Reproduzir. A fonte de telefone fornecida usa a mesma demonstração pública inicialmente. Para testar o seu próprio título, substitua os parâmetros de sessão/offline/login marcados e Published Content ID em MainActivity.kt, e forneça a autenticação de curta duração do seu próprio utilizador em tempo de execução. O seu servidor mantém o Site Key e Access Key.

Os controles compactos vêm de DrmXPlayerView no AAR. A Atividade fornecida demonstra a reprodução para autorização, rotação responsiva, propriedade de download, reprodução e renovação offline. Veja o exemplo de integração de controle abaixo ao adicionar esta visualização à sua própria aplicação.

4. Requisição do servidor e política padrão#

A aplicação Android pede à sua infra- estrutura uma sessão de reprodução. A sua infra- estrutura autentica o utilizador, verifica o direito, os mapas Content ID para os media publicados e as chamadas DRM-X. Veja Reproduzir sessão API para o contrato de transmissão completo.

{
  "contentId": "YOUR-PUBLISHED-CONTENT-ID",
  "contentType": "vod",
  "drmSystem": "widevine",
  "playbackMode": "streaming",
  "platformCapabilities": {
    "clientPlatform": "android",
    "drmSystems": ["widevine"], "manifestTypes": ["dash"],
    "maximumHeight": 1080, "secureDecoder": false, "persistentState": false
  }
}

As capacidades conservadoras acima não afirmam Widevine L1. Use o auxiliar de capacidade do SDK, ou sua própria avaliação de dispositivo, para dispositivos reais. As capacidades do cliente ajudam a seleção de compatibilidade; eles nunca concedem direito de qualidade.

A amostra PHP é por omissão multi-tier-standard para reprodução online. Seleccione a sua política de uma chave única documentada quando o seu pacote usar uma chave. A sua política deverá corresponder ao modelo da chave do pacote e aos direitos do visualizador. Mude a configuração do servidor ou a sua configuração do ambiente DRMX_LICENSE_POLICY_TEMPLATE, não um parâmetro de consulta no reprodutor. Veja a política de licenciamento .

Offline precisa de sua própria política persistente.Definir playback_policy.persistent A referência usa 7 dias / 3 dias / 48 horas / 7 dias, respectivamente; estas são regras de exemplo de negócios, não aprovação de estúdio ou um padrão de plataforma. Devolva os metadados correspondentes. A licença Widevine permanece autorizada.

5. Caminho A: jogar através do DrmXPlayer#

Dentro de sua Atividade, crie um PlayerView, use uma janela segura e chame prepare após o login. A embalagem troca a sessão, configura Widevine, aplica a altura máxima retornada e libera a reserva de streaming quando parada. As importações vêm de com.haihaisoft.drmx.player e AndroidX Media3.

val view = PlayerView(this)
setContentView(view)
DrmXPlayer.protectWindow(window)
val player = DrmXPlayer(this, view)
val capabilities = WidevineCapabilities.playbackCapabilities(
    clientPlatform = "android",
    displayMetrics = resources.displayMetrics,
    applicationVersion = "1.0",
)
player.prepare(
    endpoint = "https://customer.example/api/drmx/playback-session",
    contentId = "YOUR-PUBLISHED-CONTENT-ID",
    contentType = "vod", // use live only for a published live title
    capabilities = capabilities,
    customerAuthenticationHeaders = mapOf("Authorization" to "Bearer $userToken"),
)
// Keep player as an Activity/Fragment-owned field in your actual application.
// Stop when your playback lifecycle ends; close when the owner is destroyed.
// player.stop()
// player.close()

Registre-se DrmXPlayerListener para autorizar, preparar, reproduzir e erro UI. Mostre códigos de erro seguros em vez de despejar tokens de licença ou corpos de resposta. Use a amostra de telefone incluída para o ciclo de vida completo, controles de tela cheia e fila de download.

Controles do player e rotação ininterrupta#

Toque em Reproduzir no vídeo para iniciar a autorização. Abrir a tela ou Configurações não adquire uma licença de streaming. Pause/resumir, alterando as configurações e girando o telefone preservar a sessão atual.

DRM-X Android reprodutor Configurações em um Samsung S24 Ultra, mostrando qualidade, faixa de áudio, legendas/CC, Velocidade de reprodução e Temporizador de Sono.
Configurações reais em um Samsung S24 Ultra. Toque em uma linha para ver suas opções disponíveis; o submenu de áudio mostra nomes completos de idioma. Qualidade disponível e idiomas dependem do conteúdo, licença e dispositivo.
ControloO que os clientes podem fazer
QualidadeEscolha Auto ou uma resolução suportada e licenciada no manifesto. Opções indisponível explicam a restrição de licença ou dispositivo/DRM. Auto obedece às mesmas restrições.
Faixa de áudioEscolha qualquer idioma de áudio suportado fornecido pelo pacote.
LegendasCCEscolha um idioma de legenda ou Desligado. O botão CC aparece quando existem legendas suportadas e as ativa diretamente.
Aparência da legendaAjuste a fonte, a cor e o tamanho do texto, as cores de fundo/janela e opacidade. As preferências são salvas no dispositivo.
Velocidade de reprodução / temporizador de sonoReproduzir em 0,25-2× velocidade ou pausa automaticamente após um intervalo escolhido.
Procurar / tela cheiaEsfregue a linha do tempo, procure 10 segundos ou toque duas vezes em ambos os lados. Rodar para a paisagem sem reiniciar a reprodução.

As três ações compactas abaixo da imagem são Download (para uso offline), Jogar offline e Renovar (a licença offline). A amostra baixa uma versão de vídeo permitida e as faixas de áudio/subtítulo suportadas; menus offline expõem apenas mídia baixada. A renovação requer conectividade.

O log de cópia ao lado do rodapé da informação copia erros recentes como texto, para que você possa enviar suporte aos detalhes sem uma captura de tela. Os relatórios contêm um relatório ID, operação, SDK/Android/versão do dispositivo, erros numéricos CDM/Media3, quadros de pilha selecionados, conexão/download/estado de reprodução e uma contagem repetida. Excluem credenciais, URLs de mídia, chaves, IDs de chaves, dados de licença e despejos CDM completos.

A amostra mantém até 32 relatórios locais (64 KB) durante cinco horas. Quando conectado e conectado, ele envia erros pendentes para a infraestrutura configurada do cliente, no máximo uma vez por 30 segundos. O servidor público de demonstração mantém avisos/ erros por cinco horas, combina eventos repetidos, fecha o arquivo em 512 KB e poda a cada minuto. O progresso rotineiro e a reprodução bem- sucedida não são registrados. As integrações personalizadas devem fornecer explicitamente a sua própria origem drmx.diagnosticsEndpoint; erros de diagnóstico nunca interrompem a reprodução.

A licença off-line já está em uso?Preview.5 corrige o caso S24 que reportou CDM 368 com “Licença carregada em sessão diferente.” Pressionar Play offline novamente retoma o reprodutor existente. Renovar primeiro libera sua sessão DRM, em seguida, renova a licença armazenada. A licença de download e persistente são preservadas; não é necessária redefinição de dados de aplicativos.
val player = DrmXPlayer(this)
val controls = DrmXPlayerView(this)
controls.bind(player) // Does not acquire a session or license.
controls.onPlayRequested = {
    player.prepare(endpoint = sessionEndpoint, contentId = contentId,
        capabilities = capabilities, customerAuthenticationHeaders = userHeaders)
}
controls.onFullScreenRequested = { /* resize the existing player view */ }
player.listener = object : DrmXPlayerListener {
    override fun onAuthorizing(contentId: String) { controls.setPreparing(true) }
    override fun onReady(info: DrmXPlaybackInfo) { controls.setPreparing(false) }
    override fun onError(error: PlaybackSessionException) { controls.setPreparing(false) }
}
// Keep protectWindow(window) and the secure video surface.
// At final owner destruction: controls.unbind(); player.close()

O manifesto do telefone fornecido manipula as mudanças de orientação e tamanho do ecrã; o seu onConfigurationChanged redimensiona a mesma Actividade e reprodutor. Mantenha ambas as partes ao adaptá- la. Uma máquina que recria as Actividades deverá manter o seu proprietário de reprodução e religar a visualização. A morte do processo é diferente da rotação e necessita de uma restauração normal do estado. As opções 4K/8K requerem o mesmo conteúdo, direito à licença e suporte ao dispositivo/DRM; o CDM continua a ser autoritário.

Para uma licença personalizada reprodutores, pare e solte a sessão ativa offline DRM antes de verificar, renovar ou liberar a mesma licença persistente. A SDK player.stopForOfflineLicenseOperation { /* call manager here */ } espera que a fila de reprodução Media3 libere a mídia. As filas simples stop() que funcionam assíncronas. Não execute uma checkLicense() separada enquanto a mesma licença estiver a ser reproduzida; a reprodução em si valida o seu estado CDM. A amostra fornecida mostra o handoff completo e desactiva as ações sobrepostas durante a renovação.

6. Adquira uma licença e baixe a mídia#

Enquanto estiver conectado, adquira uma licença persistente Widevine e baixe faixas criptografadas selecionadas. Apenas uma licença válida mais mídia completa produz reprodução off-line-ready. Enquanto desconectada, leia cache privado e restaure a licença local CDM.
Pronto off-line = mídia criptografada completa + uma licença válida ligada ao dispositivo. Nenhum dos dois substitui o outro.
val offlineManager = DrmXOfflineManager(applicationContext)
val capabilities = WidevineCapabilities.offlinePlaybackCapabilities(
    clientPlatform = "android", // android-tv or android-automotive where applicable
    displayMetrics = resources.displayMetrics,
    applicationVersion = "1.0",
)
offlineManager.acquireLicense(
    endpoint = offlineEndpoint,
    contentId = contentId,
    capabilities = capabilities,
    customerAuthenticationHeaders = customerHeaders,
) { result ->
    result.onSuccess { stored ->
        // Next: select tracks <= stored.maximumHeight and queue their download.
        // Acquisition alone does not download the video.
    }.onFailure { /* show a safe retry/error state */ }
}

O SDK salva o conjunto de teclas Widevine opaco ID e metadados não secretos. O CDM detém a licença. Não persiste DRM License Tokens, chaves brutas, desafios ou bytes de resposta de licença. Excluir com.haihaisoft.drmx.offline.licenses.v1.xml das cópias de segurança.

Criar uma aplicação Media3 SimpleCache, gerenciador de download e banco de dados. Use DownloadHelper com o MediaItem licenciado e selecione vídeo dentro maximumHeight. In Media3 1.11 o callback preparado é onPrepared(helper, tracksInfoUpdated)A amostra do telefone. enqueueDownload e OfflineTestRuntime mostrar a implementação executável.

// Inside DownloadHelper's prepared callback, after selecting licensed video:
helper.addAudioLanguagesToSelection("en", "zh-Hans", "zh")
helper.addTextLanguagesToSelection(true, "en", "zh-Hans", "zh")
val selected = helper.getDownloadRequest(offlineLicenseId, byteArrayOf())
val request = offlineManager.createDownloadRequest(contentId, selected.streamKeys)
downloadManager.addDownload(request)
helper.release()

Baixe cada idioma que você pretende expor offline. Chamando createDownloadRequest sem chaves de transmissão baixa todas as faixas, que geralmente é um desperdício para o vídeo adaptativo. Mostre o progresso do download e aguarde por Download.STATE_COMPLETED. Para transferências de fundo de produção, integre Media3 DownloadService, limites de armazenamento e Android requisitos de primeiro plano/notificação; a fila de demonstração é executada em processo.

Conteúdo off-line de várias teclas:Media3 restaura uma chave ID para um item de reprodução. Sua licença persistente deve conter todas as chaves necessárias para as faixas criptografadas de vídeo, áudio e outras. Teste isso com seu pacote real e política de servidor; habilitando várias sessões não combina licenças offline independentes.

7. Caminho B: restaurar com seu existente Media3 reprodutor #

Leia a transferência completa e use as suas teclas de transmissão exatas. A pilha de transferência e reprodução deverá partilhar a mesma localização da 'cache' e o mapeamento de chaves. Este exemplo desactiva deliberadamente o acesso a montante para uma reprodução off- line estrita:

val cacheOnly = CacheDataSource.Factory()
    .setCache(downloadCache)
    .setUpstreamDataSourceFactory(null)
val mediaSourceFactory = DefaultMediaSourceFactory(this)
    .setDataSourceFactory(cacheOnly)
val nativePlayer = ExoPlayer.Builder(this)
    .setMediaSourceFactory(mediaSourceFactory)
    .build()
val completed = downloadIndex.getDownload(offlineLicenseId)
require(completed?.state == Download.STATE_COMPLETED)
val playback = offlineManager.createPlayback(contentId, streamKeys = completed!!.request.streamKeys)
nativePlayer.setMediaItem(playback.mediaItem)
nativePlayer.prepare()
nativePlayer.play()
// Release nativePlayer when the owner is destroyed.

Para usar o mesmo fluxo offline com o Caminho A, construa DrmXPlayer com este mediaSourceFactory e chame player.prepareOffline(playback). A restauração ordinária usa a licença local CDM sem solicitar uma nova. Um item de cache ausente deve produzir um erro durante a aceitação desconectada, não mudar silenciosamente para a internet.

8. Caminho C: nativo Media3, no DRM-X AAR #

Você não é obrigado a usar o DrmXPlayer ou o DrmXOfflineManager. Adicione as três dependências Media3 do passo 3 e implemente o mesmo contrato de infraestrutura do cliente. Use session.manifestUrl (não session.manifest.url), a licença retornada URL e os cabeçalhos de autorização limitados. Aplique a altura máxima retornada e lide com a liberação da sessão de streaming na parada, substituição, fim, falha e destruição.

A Atividade nativa completa abaixo é compilada como samples:native ao lado desta versão SDK. Ela lida com HTTPS, leituras de resposta limitadas, autorização de fundo, respostas antigas e liberação de reservas. Substitua o endpoint/ Content ID marcado e forneça seu próprio token de login. O exemplo é um ponto de partida; adicione seu ciclo de vida de atualização de produção, mudança de conta e navegação de aplicativos.

Atividade completa de transmissão nativa (Kotlin, nenhuma dependência DRM-X)
package com.haihaisoft.drmx.samples.nativeplayer

import android.app.Activity
import android.os.Bundle
import android.view.WindowManager
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
import org.json.JSONObject
import java.net.HttpURLConnection
import java.net.URI
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean

/** Complete native streaming example. No DRM-X AAR or server credentials. */
@UnstableApi
class MainActivity : Activity() {
    private lateinit var player: ExoPlayer
    private lateinit var status: TextView
    private val worker = Executors.newSingleThreadExecutor()
    private val closed = AtomicBoolean(false)
    private var activeSession: JSONObject? = null
    private var requesting = false
    private var generation = 0
    // CUSTOMIZE: use YOUR authenticated customer backend and Published Content ID.
    // The sample can receive these after your application's login via Intent extras.
    // Never replace the app login token with a DRM-X Site Key or Access Key.
    private val endpoint get() = intent.getStringExtra("drmx.sessionEndpoint")
        ?: "https://customer.example/api/drmx/playback-session"
    private val contentId get() = intent.getStringExtra("drmx.contentId") ?: "YOUR-PUBLISHED-CONTENT-ID"
    private val customerToken get() = intent.getStringExtra("customer.accessToken").orEmpty()

    override fun onCreate(state: Bundle?) {
        super.onCreate(state)
        window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
        val root = LinearLayout(this).apply { orientation = LinearLayout.VERTICAL; fitsSystemWindows = true; setPadding(24, 24, 24, 24) }
        status = TextView(this).apply { text = "Native Media3 · connect your backend, then Play"; textSize = 16f }
        val view = PlayerView(this)
        player = ExoPlayer.Builder(this).build(); view.player = player
        root.addView(status)
        root.addView(view, LinearLayout.LayoutParams(-1, 0, 1f))
        root.addView(Button(this).apply { text = "Play protected video"; setOnClickListener { startPlayback() } })
        root.addView(Button(this).apply { text = "Stop & release session"; setOnClickListener { stopPlayback() } })
        setContentView(root)
        player.addListener(object : Player.Listener {
            override fun onPlayerError(error: PlaybackException) { status.text = "Playback error: ${error.errorCodeName}"; releaseSession() }
            override fun onPlaybackStateChanged(state: Int) { if (state == Player.STATE_ENDED) releaseSession() }
        })
    }

    private fun startPlayback() {
        if (requesting) return
        stopPlayback(); requesting = true; status.text = "Authorizing…"
        val attempt = generation
        val request = JSONObject().put("contentId", contentId).put("contentType", "vod")
            .put("drmSystem", "widevine").put("playbackMode", "streaming")
            .put("platformCapabilities", JSONObject().put("clientPlatform", "android")
                .put("drmSystems", org.json.JSONArray(listOf("widevine")))
                .put("manifestTypes", org.json.JSONArray(listOf("dash")))
                .put("maximumHeight", 1080).put("secureDecoder", false).put("persistentState", false))
        val headers = if (customerToken.isBlank()) emptyMap() else mapOf("Authorization" to "Bearer $customerToken")
        worker.execute {
            val result = runCatching { JSONObject(post(endpoint, request.toString(), headers)) }
            runOnUiThread {
                requesting = false
                result.onSuccess { session ->
                    if (closed.get() || attempt != generation) { workerRelease(session); return@onSuccess }
                    // Keep release information even if contract validation fails.
                    activeSession = session
                    runCatching {
                        require(session.getInt("contractVersion") == 1 && session.getString("contentId") == contentId)
                        require(session.getString("drmSystem") == "widevine" && session.getString("playbackMode") == "streaming")
                        val drm = session.getJSONObject("drm")
                        require(drm.getString("system") == "widevine")
                        val maximumHeight = session.getJSONObject("policy").getInt("maximumHeight")
                        require(maximumHeight in 1..4320)
                        val mediaItem = MediaItem.Builder().setUri(https(session.getString("manifestUrl")))
                            .setMimeType("application/dash+xml")
                            .setDrmConfiguration(MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
                                .setLicenseUri(https(drm.getString("licenseServerUrl")))
                                .setForceDefaultLicenseUri(true).setLicenseRequestHeaders(authorization(drm))
                                .setMultiSession(false).build()).build()
                        player.trackSelectionParameters = player.trackSelectionParameters.buildUpon()
                            .setMaxVideoSize(Int.MAX_VALUE, maximumHeight).setPreferredAudioLanguages("en")
                            .setTrackTypeDisabled(C.TRACK_TYPE_TEXT, true).build()
                        player.setMediaItem(mediaItem); player.prepare(); player.play()
                        status.text = "Native Media3 · protected playback"
                    }.onFailure { status.text = "Invalid session contract. Check your backend."; releaseSession() }
                }.onFailure { if (!closed.get()) status.text = "Authorization failed. Check login, Content ID, policy, and network." }
            }
        }
    }

    private fun releaseSession() { activeSession?.let(::workerRelease); activeSession = null }
    private fun workerRelease(session: JSONObject) {
        // A bounded release may finish after Activity destruction, including a
        // session response that arrived after the user left the screen.
        Thread({ runCatching {
            val release = session.getJSONObject("release")
            val headers = if (release.has("authorization")) authorization(release)
                else authorization(session.getJSONObject("drm"))
            post(release.getString("url"), "", headers)
        } }, "drmx-native-release").start()
    }
    private fun stopPlayback() { generation++; player.stop(); player.clearMediaItems(); releaseSession() }
    override fun onStop() { stopPlayback(); super.onStop() }
    override fun onDestroy() { closed.set(true); stopPlayback(); player.release(); worker.shutdown(); super.onDestroy() }

    companion object {
        fun https(url: String): String {
            val uri = URI(url); require(uri.scheme == "https" && uri.host != null && uri.userInfo == null)
            return url
        }
        fun authorization(drm: JSONObject): Map<String, String> {
            val auth = drm.optJSONObject("authorization")
            val name = auth?.getString("headerName") ?: "Authorization"
            val scheme = auth?.getString("scheme") ?: drm.optString("tokenType", "Bearer")
            val value = auth?.getString("value") ?: drm.getString("drmLicenseToken")
            require(name.matches(Regex("^[A-Za-z0-9-]{1,64}$")) && scheme.matches(Regex("^[A-Za-z][A-Za-z0-9._-]{0,31}$")))
            require(value.isNotBlank() && !value.contains('\r') && !value.contains('\n'))
            return mapOf(name to "$scheme $value")
        }
        fun post(url: String, body: String, headers: Map<String, String>): String {
            val connection = URI(https(url)).toURL().openConnection() as HttpURLConnection
            try {
                connection.requestMethod = "POST"; connection.instanceFollowRedirects = false
                connection.connectTimeout = 5000; connection.readTimeout = 15000; connection.doOutput = true
                connection.setRequestProperty("Content-Type", "application/json")
                headers.forEach { (name, value) -> connection.setRequestProperty(name, value) }
                connection.outputStream.use { it.write(body.toByteArray(Charsets.UTF_8)) }
                require(connection.responseCode in 200..299) { "Customer request rejected" }
                return connection.inputStream.use { stream ->
                    val output = java.io.ByteArrayOutputStream(); val buffer = ByteArray(8192)
                    while (true) {
                        val count = stream.read(buffer); if (count < 0) break
                        require(output.size() + count <= 1_048_576); output.write(buffer, 0, count)
                    }
                    output.toString("UTF-8")
                }
            } finally { connection.disconnect() }
        }
    }
}

Para licenciamento off-line nativo, use OfflineLicenseHelper.downloadLicense, persista no seu conjunto de chaves opaco ID em privado e restaure com MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID).setKeySetId(id). O seguinte helper compilado cobre a aquisição, verificação de duração, renovação, lançamento e itens de download/reprodução. É não um aplicativo de download completo : você ainda possui o cache, serviço de download, progresso, metadados, vinculação de usuário/dispositivo e autorização de operação confiável.

Ajudante nativo de licença persistente (Kotlin, sem dependência DRM-X)
package com.haihaisoft.drmx.samples.nativeplayer

import android.content.Context
import android.util.Base64
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.StreamKey
import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.DefaultHttpDataSource
import androidx.media3.exoplayer.dash.DashUtil
import androidx.media3.exoplayer.drm.DrmSessionEventListener
import androidx.media3.exoplayer.drm.OfflineLicenseHelper
import androidx.media3.exoplayer.offline.DownloadRequest
import org.json.JSONObject

/** Native Media3 alternative: no DRM-X AAR. Call blocking operations on a worker.
 * Application owns downloads/cache, user/device entitlement, progress and lifecycle.
 * Never persist the session, request headers, tokens, challenges or license bytes.
 */
@UnstableApi
class NativeOfflineLicense(context: Context) {
    private val storage = context.getSharedPreferences("native.offline.keysets", Context.MODE_PRIVATE)
    private val upstream = DefaultHttpDataSource.Factory().setConnectTimeoutMs(10000).setReadTimeoutMs(20000)

    // session is the validated response from YOUR offline-license-session endpoint.
    fun acquire(session: JSONObject): ByteArray {
        validate(session)
        val contentId = session.getString("contentId")
        require(!storage.contains(contentId)) { "Renew or release the stored license before acquiring again" }
        val source = upstream.createDataSource()
        val manifest = DashUtil.loadManifest(source, android.net.Uri.parse(MainActivity.https(session.getString("manifestUrl"))))
        val format = DashUtil.loadFormatWithDrmInitData(upstream.createDataSource(), manifest.getPeriod(0))
            ?: error("Missing Widevine initialization data")
        val helper = helper(session)
        try {
            val id = helper.downloadLicense(format)
            save(contentId, id)
            return id
        } finally { helper.release() }
    }

    fun renew(contentId: String, freshSession: JSONObject) {
        validate(freshSession); require(freshSession.getString("contentId") == contentId)
        val helper = helper(freshSession)
        try { save(contentId, helper.renewLicense(keySet(contentId))) } finally { helper.release() }
    }

    // Local CDM check only. No token or network license URI is used.
    fun remainingSeconds(contentId: String): Pair<Long, Long> {
        val config = MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID).build()
        val helper = OfflineLicenseHelper.newWidevineInstance(config, upstream, DrmSessionEventListener.EventDispatcher())
        try {
            val remaining = helper.getLicenseDurationRemainingSec(keySet(contentId))
            return Pair(remaining.first, remaining.second)
        } finally { helper.release() }
    }

    fun release(contentId: String, freshSession: JSONObject) {
        validate(freshSession); require(freshSession.getString("contentId") == contentId)
        val helper = helper(freshSession)
        try {
            helper.releaseLicense(keySet(contentId))
            check(storage.edit().remove(contentId).commit())
        } finally { helper.release() }
    }

    fun downloadRequest(contentId: String, downloadId: String, manifestUrl: String, streamKeys: List<StreamKey>): DownloadRequest {
        require(streamKeys.isNotEmpty()) { "Select policy-compliant video, audio and subtitle tracks first" }
        return DownloadRequest.Builder(downloadId, android.net.Uri.parse(MainActivity.https(manifestUrl)))
            .setMimeType("application/dash+xml").setStreamKeys(streamKeys).setKeySetId(keySet(contentId)).build()
    }

    fun mediaItem(contentId: String, manifestUrl: String, streamKeys: List<StreamKey>): MediaItem = MediaItem.Builder()
        .setUri(MainActivity.https(manifestUrl)).setMimeType("application/dash+xml").setStreamKeys(streamKeys)
        .setDrmConfiguration(MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID).setKeySetId(keySet(contentId)).build()).build()

    private fun helper(session: JSONObject): OfflineLicenseHelper {
        val drm = session.getJSONObject("drm")
        // Use HTTP license headers, NOT Widevine optional key-request parameters.
        val config = MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
            .setLicenseUri(MainActivity.https(drm.getString("licenseServerUrl")))
            .setForceDefaultLicenseUri(true).setLicenseRequestHeaders(MainActivity.authorization(drm)).build()
        return OfflineLicenseHelper.newWidevineInstance(config, upstream, DrmSessionEventListener.EventDispatcher())
    }
    private fun validate(session: JSONObject) {
        require(session.getInt("contractVersion") == 1 && session.getString("playbackMode") == "offline")
        require(session.getString("drmSystem") == "widevine" && session.getString("contentType") == "vod")
        require(session.getJSONObject("policy").getBoolean("persistent"))
    }
    private fun keySet(contentId: String): ByteArray = Base64.decode(storage.getString(contentId, null)
        ?: error("No device-bound license for this content"), Base64.NO_WRAP)
    private fun save(contentId: String, id: ByteArray) {
        check(storage.edit().putString(contentId, Base64.encodeToString(id, Base64.NO_WRAP)).commit())
    }
}

Antes de chamar este helper de baixo nível, valide que a resposta nova da infra- estrutura corresponde ao Content ID solicitado, operação, período de validade do usuário/dispositivo e autorização assinado. Persista em um estável offlineLicenseId e metadados de manifesto/pista confiáveis ao lado do conjunto de chaves ID, nunca o token. Execute chamadas de helper de bloqueio em um tópico de worker. Para a licença, os cabeçalhos HTTP usam setLicenseRequestHeaders na configuração DRM; Widevine parâmetros de pedido de chaves opcionais são um mapa diferente.

Novas integrações devem ser utilizadas AndroidX Media3 DRM apoioLegado com.google.android.exoplayer2 os projectos devem seguir o guia oficial de migração; não misture legado e AndroidClasses X ou assumir que a amostra compila inalterada contra versões mais antigas.

9. Verifique, renove, release and switch languages#

Estas são ações separadas. Execute uma de cada vez após a sessão offline ativa DRM ter sido lançada: use player.stopForOfflineLicenseOperation { /* one operation below */ } com o DrmXPlayer, ou libere primeiro o nativo Media3 reprodutor existente. Não verifique uma licença enquanto estiver em reprodução. Uma verificação é opcional para exibição de durações; não deve impedir a renovação de uma licença expirada.

offlineManager.checkLicense(contentId) { result ->
    result.onSuccess { license ->
        if (license.state == DrmXOfflineLicenseState.EXPIRED) {
            // Require renewal online before offering offline playback.
        }
    }
}
offlineManager.renewLicense(offlineEndpoint, contentId, capabilities, customerHeaders) {
    /* update duration and UI after success; show retry on failure */
}
// Only when the customer requests deletion/release:
offlineManager.releaseLicense(offlineEndpoint, contentId, capabilities, customerHeaders) {
    /* after success, remove the corresponding encrypted download */
}

getStoredLicense lê metadados; checkLicense consultas de duração local autorizada CDM. Renovar/lançar requerem conectividade e uma nova autorização específica de operação da sua infra- estrutura. A exclusão de mídia não libera a licença. Quando desconectada, a liberação da fila para a próxima conexão em vez de informar que o servidor a confirmou. Feche o gerenciador quando seu proprietário for destruído.

// Use player.media3Player for the DRM-X wrapper; nativePlayer for plain Media3.
nativePlayer.trackSelectionParameters = nativePlayer.trackSelectionParameters
    .buildUpon()
    .setPreferredAudioLanguages("en") // Chinese: "zh-Hans", "zh"
    .setPreferredTextLanguages("en")  // choose a packaged/downloaded language
    .setTrackTypeDisabled(C.TRACK_TYPE_TEXT, false) // true = subtitles Off
    .build()

Constrói as opções das faixas disponíveis e desactiva as opções indisponíveis. Uma preferência não pode criar uma faixa inglesa ausente do pacote. Os utilizadores offline só podem seleccionar as línguas transferidas. Preservar a licença/estado de cache através da rotação da tela; a tela cheia é uma mudança de visualização/janela, não uma razão para adquirir outra licença.

10. Implementar o endpoint de autorização offline#

As mensagens da aplicação contentId, contentType: "vod", drmSystem: "widevine", playbackMode: "offline", operation: "acquire" | "renew" | "release", offlineLicenseId (null para aquisição inicial) e verdadeiro platformCapabilities. Verifique se os IDs de renovação/lançamento pertencem ao utilizador, dispositivo e conteúdo autenticados. Selecione o lado do servidor de políticas, emita um DRM License Token novo e devolva o contrato correspondente:

{
  "contractVersion": 1, "playbackMode": "offline",
  "offlineLicenseId": "YOUR-STABLE-USER-DEVICE-CONTENT-RECORD",
  "contentId": "YOUR-PUBLISHED-CONTENT-ID", "contentType": "vod",
  "drmSystem": "widevine",
  "manifestUrl": "https://media.customer.example/title/manifest.mpd",
  "authorizationExpiresAt": "YOUR-FRESH-UTC-EXPIRY",
  "drm": {
    "system": "widevine",
    "licenseServerUrl": "https://license6.drm-x.com/v1/licenses/widevine",
    "integrationMode": "direct-token",
    "drmLicenseToken": "SHORT-LIVED-OPERATION-AUTHORIZATION",
    "tokenType": "Bearer"
  },
  "policy": {
    "persistent": true, "renewAllowed": true, "maximumHeight": 1080,
    "allowedTrackTypes": ["AUDIO", "SD", "HD"],
    "licenseDurationSeconds": 604800, "rentalDurationSeconds": 259200,
    "playbackDurationSeconds": 172800, "renewalDurationSeconds": 604800
  }
}

Estes são placeholders explicativos, não uma resposta de licença reutilizável. Devolva novos valores da operação real. SDK também suporta integrationMode: "token-proxy" com um limite drm.authorization descritor. Return Cache-Control: no-store; nunca registrar corpos de autorização bem sucedidos. Veja o download possível SDK's OFFLINE_INTEGRATION.md e PHP Endpoint off-line da amostra para o manuseio de pedidos de concreto.

11. Teste seus dispositivos e solução de problemas #

Widevine provisionamento e testes de rede da China

O provimento obtém o certificado do dispositivo antes da aquisição da licença de conteúdo.A partir da pré-visualização.9 a demonstração do telefone envia o pedido assinado do CDM através do seu relé autenticado do cliente HTTPS para o Google. A resposta assinada retorna inalterada. Isto ajuda quando o telefone não consegue alcançar diretamente o serviço de provisionamento do Google; o relé do cliente ainda deve ser acessível.

O Provisioning 2.0 utiliza uma chave de fábrica. O Provisioning 4.0 utiliza um modelo de credencial de dispositivo diferente. L1/L3 níveis de segurança, e reprodutor não os muda. L3 O telefone pode jogar enquanto outro telefone espera pelo provisionamento de dispositivos. As fontes oficiais públicas revisadas aqui não estabelecem que a China suporta apenas 2.0. NXPGuia de integração do dispositivo e AndroidAplicação do provisionamento.

Preview.10 relatórios de erro distinguem transporte direto ou relé, tempo limite/DNS/TLS/HTTP falha, HTTP estado e tempo decorrido. provisioningModel: BootCertificateChain indica a AOSP Modelo 4.0; unknown ou other não estabelece 2.0. PHP logs distinguem entradas rejeitadas de falhas no Google a montante. Relatórios excluem cargas de pagamento assinadas, URLs, credenciais e identificadores únicos do dispositivo.

Atualizar o APK no local, repetir o streaming e um download na rede afetada, em seguida, reter o log de cópia e o tempo aproximado. Os downloads e licenças existentes são retidos. Um relé não pode reparar não disponível Widevine ou credenciais rejeitado pelo dispositivo/Google. A aceitação real no telefone afetado é necessária.

Da antevisão.8, nativo L2/L3 ou nível desconhecido Widevine a reprodução está limitada a SD (até 576p) antes da descodificação. Android capacidades através da sua infra- estrutura: a sessão API reduz o software Widevine Licenças multi- chave para áudio/SD Chaves. PHP amostra preserva estes campos e também caps pedidos offline. SD rendition e uma política que permite software DRM são necessárias; as regras de segurança únicas e uniformes de uma única chave permanecem inalteradas. As configurações usam um painel translúcido sem escurecimento do vídeo. Numeric cryptoErrorCode está incluído em relatórios de erro seguros.

Teste / sintomaComportamento esperado / próxima verificação
A transferência SDK devolve 403Selecione uma organização com uma assinatura ativa Professional ou Enterprise. Uma atualização planejada após a avaliação não desbloqueia o SDK.
Sessão 401 / 403Verificar login, direito, Ambiente, Publicado Content ID e política. Nunca ignorar a autenticação.
Falha off-line, mas funciona onlineVerifique as durações CDM, o download completo, a localização do cache, as chaves de fluxo e todas as chaves licenciadas necessárias.
Inglês / Chinês em faltaVerifique os metadados da linguagem do pacote, as faixas reais e a seleção do idioma offline.
L1, HDCP ou falha no descodificadorVerifique os requisitos de hardware físico, provisionamento, codec e saída. Uma string de capacidade não é certificação.
Reiniciar, rodar, atualizarLicença persistente e cache sobrevivem às mudanças suportadas no ciclo de vida sem aquisição duplicada. Os backups não devem migrar licenças para um novo dispositivo.
Modo aviãoDesativar Wi-Fi e dados móveis também; reinicie o aplicativo, jogue localmente e mude cada idioma prometido.
Expiração, pressão de armazenamento, interruptor de contaMostrar um estado indisponível/renovar claro, recuperar mídia incompleta e forçar o acesso usuário/dispositivo sem vazar o catálogo offline de outro usuário.

Qualifique cada telefone, tablet, Android TV/Google TV, Fire TV ou modelo Android suportado para Widevine, decodificação segura, codec/resolução, HDCP, monitores externos, mudanças de relógio e desconexão longa. Nem todos os dispositivos Android têm as mesmas capacidades DRM. O conteúdo de Hollywood requer os requisitos de proteção e dispositivo do titular dos direitos, não apenas descodificação bem sucedida.

Não há oportunidade de adquirir antes da desconexão?Esta é uma implantação diferente: uma licença de serviço de licença de bordo qualificada emite licenças através da rede local durante a viagem. Ela não está habilitada apenas usando este SDK. DRM-X pode trabalhar com você em uma implantação personalizada cobrindo permissões de provedor, provisionamento, proteção de chaves e um teste de aceitação totalmente desconectado. Veja a bordo DRM para aeronaves, autocarros, comboios e navios.

Universal Player listas de reprodução e controles compartilhados #

A Android preview.11 e mais tarde aplicativos de avaliação e atual Android/Apple fontes de desenvolvimento compartilhar em vídeo Anterior/Play-Pause/Next, CC, Configurações e controles de tela cheia com dois segundos de ocultação durante a reprodução. AndroidO menu da lista de reprodução já não inclui “Reproduzir o próximo”. As configurações selecionadas do shuffle/repeat permanecem destacadas e persistem ao longo dos reinícios. Com ambos desligados, a reprodução segue a ordem da lista de reprodução gravada e pára no vídeo final. Arraste os comandos para reordenar os itens sem reiniciar o vídeo atual; a ordem salva também se aplica à lista de reprodução baixada. Estas APIs de origem mais recentes ainda não estão incluídas na antevisão do Console. 10 SDK Um pacote.

Forneça o mesmo cliente/visualizador storageNamespace para DrmXPlayer e playerView.storageNamespace antes de configurar a lista de reprodução. O progresso VOD é gravado periodicamente e em pausa/paragem, sendo então restaurado para esse Content ID em transmissão ou reprodução transferida. A reprodução ao vivo não usa uma posição VOD gravada. Os downloads completados mantêm o mesmo comportamento de shuffle/repeat/resume sem uma fonte de mídia de rede. Este estado local do dispositivo não sincroniza o progresso entre dispositivos.

As edições Web e Android usam um painel de configurações escuras consistente com controles azuis compactos. As listas de reprodução suportam próximo/anterior, embaralhe, repita um/todos e cancelável avanço automático. Cada item usa uma nova solicitação de reprodução autorizada. Os metadados de capítulo e transcrição vêm do seu catálogo de conteúdo.

Velocidade de reprodução, temporizador de sono, legendas, qualidade permitida, idiomas de áudio, marcadores de sessão e looping A–B estão disponíveis. Web adiciona atalhos de teclado, currículo local visualizador opcional, pesquisa de transcrição e navegador compatível PiP. Android mantém downloads e renovação nativas Widevine offline. O progresso de carcaça e dispositivo cruzado requer integrações de aplicativos separadas.

Configurações de logotipo profissional e empresarial

Branding fica fora da superfície do vídeo. Configurações abertas → Sobre reprodutor para o logotipo autorizado, informações do produto e versão reprodutor. Web também oferece esta informação no botão direito do mouse. A demonstração do telefone público inclui WayMaker, Bondade de Deus, Óleo Fresco e Vídeo de Teste 4K; cada seleção recebe sua própria autorização.

Configure playerBranding na sua infra- estrutura de confiança para {"mode":"hidden"} ou {"mode":"custom","logoUrl":"https://your-site.example/logo.png","label":"Your brand"}. A plataforma verifica a subscrição activa do Professional ou Enterprise. Outros planos usam {"mode":"default"}; requisições personalizadas/ ocultas não autorizadas devolvem 403. Isto é separado das marcas de água de segurança.

O download PHP inclui a configuração da lista de reprodução editável e da marca. O cliente Android ZIP inclui o exemplo de chamada da lista de reprodução. Mantenha a autorização da lista de reprodução na sua infra- estrutura; nunca incorpore API cliente credenciais em qualquer um dos reprodutor.