DRM-X 6.0 logo de la colombe et de la branche d'oliveDRM-X 6.0Documentation
◎ Français

SDK Android et Media3 natif

Téléchargez le Android lecteur avec des commandes vidéo, des listes de lecture dragables, un résumé shuffle/repeat sauvegardé et hors ligne. Intégrez la lecture protégée en utilisant DRM-X ou natif Media3.

Voir le MarkdownExemples en ligneActualisé 2026-09-14
Choisissez votre lecteur, gardez un service de licence.Utilisez le DRM-X 6.0 Android SDK pour une intégration guidée, ou gardez votre Media3 lecteur natif. Les deux se connectent à votre moteur authentifié et Widevine. Le Android SDK prend en charge le streaming et la persistance hors ligne VOD sur les appareils compatibles API 23+, y compris les téléphones, tablettes, téléviseurs et systèmes intégrés Android.

Essayez le Android lecteur#

Téléchargez, installez, appuyez sur Play.L'application d'évaluation gratuite utilise notre vidéo de démonstration publique et se connecte automatiquement. Vous n'avez pas besoin de construire un APK ou entrer DRM-X identifiants pour l'essayer.

Télécharger Android échantillon APK

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

  1. Ouvrez cette page sur votre téléphone Android et téléchargez le APK.
  2. Ouvrez le fichier téléchargé. Si Android demande, autorisez l'installation à partir du navigateur ou du gestionnaire de fichiers que vous avez utilisé, puis appuyez sur Install.
  3. Ouvrez DRM-X 6.0 Player, restez connecté et appuyez sur le bouton Play de la vidéo. L'application demande une licence de diffusion lorsque vous appuyez sur Play.
  4. Ouvrez Paramètres pour choisir la qualité, l'audio, les légendes ou la vitesse de lecture.
  5. Appuyez sur Téléchargement pour la vidéo actuelle ou Téléchargement playlist pour tous les articles VOD. Les téléchargements utilisent la plus haute version sous licence jusqu'à 1080p sur L1, ou 480p sur L3. Play offline ouvre la liste de lecture locale complétée avec le suivant/précédent, shuffle, répéte et autoplay; Allez en ligne retourne à la liste de lecture complète. Renouvelle renouvelle la licence sélectionnée lors de la connexion.

Si Android arrête l'application lors de la préparation des licences ou des pistes, rouvrez-la pendant qu'elle est connectée pour terminer la préparation des éléments restants. Les téléchargements existants sont conservés. La lecture hors ligne n'utilise que les médias mis en cache; les téléchargements incomplets ou expirés nécessitent l'achèvement ou le renouvellement.

Widevine des défaillances de fourniture (Media3 6002) utilisent maintenant un relais de serveur démo authentifié vers le service officiel de Google. Un fonctionnement L3 CDM peut recevoir SD des touches. Un périphérique sans fonctionnement Widevine implémentation a besoin d'un correctif de périphérique/firmware; une licence ne peut pas ajouter de support DRM manquant.

L'échantillon APK est public et signé pour l'évaluation. Le AAR et le SDK complet ci-dessous restent disponibles via les comptes Console éligibles. Gardez votre propre application de production de signature de clé et de connexion de moteur séparé de cette démo.

APK somme de contrôle et installation USB

SHA-256:

8fa044b82c0abab7ce2a987f349524fd7ad1e78f3c897771f4764cb2aa521180

Avec des outils de plate-forme Android et un dispositif autorisé USB:

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

Installez ce APK sur l'échantillon officiel existant sans le désinstaller. La même clé de signature et l'application ID préservent les téléchargements, les licences hors ligne, les positions sauvegardées et les préférences. Si votre propre build utilise une autre clé de signature, utilisez une application séparée ID pour conserver les deux applications et préserver les licences hors ligne de l'échantillon.

Quoi de neuf dans Android lecteur prévisualisation.12#

Sortie le 14 septembre 2026. Correction de la lecture téléchargée faisant une demande de licence inattendue lorsqu'une licence Widevine est expirée ou qu'il reste une minute ou moins. Cela pourrait apparaître sous la forme d'une erreur Media3 6004, d'une erreur HTTP lors d'une connexion ou d'une erreur DNS lors d'une déconnexion.

Le lecteur restaure maintenant la licence téléchargée localement. Les licences valides conservent leur temps de lecture restant; les licences expirées affichent Connect et tapent Renew. Les règles de validité et de protection de la licence restent appliquées par l'appareil. Les diagnostics incluent également l'état numérique HTTP lorsqu'une opération réseau échoue, sans exposer les en-têtes de requête, les URL ou les réponses de licence.

  1. Installez preview.12 sur l'application officielle existante. Gardez vos données et téléchargements d'applications en cours.
  2. Si WayMaker ou une autre vidéo téléchargée a besoin d'être renouvelée, connectez-vous à Internet, sélectionnez cette vidéo et appuyez sur Renouvellement.
  3. Attendez le License renouvelé. Prêt à jouer hors ligne. , puis choisissez Play offline. La vidéo chiffrée reste téléchargée.

Cette version conserve les commandes de prévisualisation 11 et les fonctionnalités de playlist. L'application d'évaluation publique et son lecteur intégré identifient prévisualisation 12 ; la console SDK distribuée séparément reste prévisualisation 10 / paquet 20260910,8.

Quoi de neuf dans Android lecteur preview.11#

Publié le 14 septembre 2026. Cette application d'évaluation comprend les dernières améliorations de contrôle et de liste de lecture lecteur, avec un style d'interaction cohérent entre nos Android et Apple lecteurs.

  • Contrôle à l'intérieur de la vidéo: centred Play/Pause, Previous and Next for multi-video playlists, CC, Paramètres et un bouton plein écran. Les commandes se cachent après deux secondes pendant la lecture; appuyez sur la vidéo pour les révéler à nouveau.
  • Paramètres de saisie et de lecture: utilisez CC pour afficher ou masquer les sous-titres disponibles, et Paramètres pour choisir le langage de légende, audio, vitesse de lecture et qualité autorisée.
  • Drag pour réorganiser: faites glisser la poignée d'un élément de liste de lecture pour changer sa position. L'ordre enregistré survit à un redémarrage de l'application et est reflété dans la liste de lecture téléchargée.
  • Enregistré shuffle et répéter: les modes sélectionnés restent en surbrillance et survivent aux redémarrages en lecture en ligne et hors ligne. Avec shuffle et répéter les deux off, les vidéos suivent l'ordre enregistré et s'arrêtent après l'élément final.
  • Resumez où vous avez arrêté: la position de chaque vidéo enregistrée VOD est restaurée lorsque vous retournez à la lecture en streaming ou téléchargée. Les progrès sont enregistrés sur ce périphérique pour le visionneur actuel; il ne se synchronise pas entre les périphériques.

Les modifications lecteur ont été vérifiées sur un Samsung S24 Ultra, y compris le glisser de playlist pendant la lecture, l'ordre enregistré après la relance, le CV de lecture et la lecture téléchargée avec Wi-Fi et données mobiles désactivés.

Cette version met à jour l'évaluation publique APK. La Console SDK distribuée séparément reste 1.0.0-preview.10, paquet 20260910.8; ses instructions d'intégration existantes ci-dessous se rapportent à ce paquet.

1. Choisissez un chemin d'intégration#

Téléchargez le SDK Android au format ZIP ou AAR dans Console → Integrations. Les organisations disposant d’un abonnement Professional ($499/mois) ou Enterprise actif peuvent le télécharger. Les comptes Trial et Standard ne peuvent pas télécharger le SDK. Cette documentation, y compris les exemples Media3 natifs, est publique ; la lecture nécessite un compte autorisé, un contenu publié et un appareil compatible.

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. Préparez votre contenu et votre moteur #

  1. Paquetez et publiez un titre compatible Widevine crypté DASH dans votre environnement DRM-X. Copiez son exact Publié Content ID.
  2. Configurez Environment ID, Site Key et Access Key de votre serveur. Utilisez l'intégration PHP téléchargeable pour un point de départ de travail.
  3. Implémentez votre login utilisateur et la vérification des droits. Votre application appelle votre backend avec son jeton utilisateur de courte durée; votre backend choisit le contenu, la politique et les URL de confiance.
  4. Exécutez la lecture en ligne d'abord sur un appareil physique compatible Widevine. Ajoutez l'acquisition hors ligne seulement après que le contrat de streaming fonctionne.
L'application Android authentifie le moteur client, qui demande une session DRM-X en utilisant uniquement le serveur identifiants. Le lecteur télécharge séparément les supports chiffrés et envoie un défi Widevine au service de licence.
La livraison des médias et la livraison des licences sont séparées. Seul le client détient le serveur DRM-X identifiants.
Modifier cette valeurOù il appartientSignification
fin de sessionAndroidVotre paramètre de session de lecture HTTPS, pas le serveur de licence brut URL.
point d'arrivée hors ligneAndroid, hors ligne seulementVotre critère d'autorisation d'acquisition/renouvellement/libération.
ContenuIdAndroid requête; le moteur valideLe téléspectateur protégé Content ID publié a droit à l'accès.
jeton d'accès au clientMémoire de l'application après la connexionVotre jeton d'utilisateur de courte durée, jamais un Site Key ou Access Key.
Environment ID, Site Key, Access KeyConfiguration secrète du serveur seulementDRM-X compte identifiants. Ne jamais les expédier dans un APK, HTML ou un contrôle de source.
Politique et manifeste de confiance URLVotre moteurDroit d'entreprise et cartographie des paquets. N'acceptez pas ceux-ci de l'application.

3. Installez et exécutez le 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

Pour une application existante, copiez le dossier ZIP de maven/ dans votre racine de projet. Dans settings.gradle.kts :

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

Dans le build.gradle.kts de votre module d'application:

dependencies {
    implementation("com.haihaisoft.drmx:drmx-universal-player:1.0.0-preview.10")
}
Installer le standalone AAR à la place

Mettez le AAR dans le libs/ de votre module d'application. Un AAR plat n'a pas de résolution de dépendance transitive automatique, alors ajoutez les trois dépendances Media3 correspondantes vous-même. Ne pas installer les deux formulaires.

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")

Dans AndroidManifest.xml, autoriser l'accès à Internet et désactiver les sauvegardes pour cet échantillon minimal. Dans une application de production qui nécessite des sauvegardes, exclure spécifiquement les métadonnées de licence hors ligne liées aux appareils.

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

Effectuez une recherche sur l'échantillon téléphonique MainActivity.kt pour drmx.sessionEndpoint, drmx.offlineEndpoint, drmx.contentId et customer.loginEndpoint. Changez les paramètres de repli marqués, ou passez ces extras d'intention de votre application après l'ouverture de session. Passez customer.accessToken au moment de l'exécution. Le ZIP README explique chaque paramètre et quels crochets de démonstration sont à remplacer.

Construisez un test APK en utilisant le AAR#

Cet exemple utilise le projet de téléphone exécutable de la SDK ZIP complète et relie explicitement la AAR autonome. La même approche fonctionne pour une application Android existante.

  1. Télécharger et extraire le full Android SDK ZIP . Ouvrez son dossier racine dans 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. Dans samples/phone/build.gradle.kts, remplacez la dépendance DRM-X Maven par les entrées suivantes à l'intérieur de dependencies. Gardez le reste de ce fichier de compilation.
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")

Supprimer implementation("com.haihaisoft.drmx:drmx-universal-player:1.0.0-preview.10") de sorte que le même SDK n'est pas inclus deux fois. Un AAR plat a besoin des trois dépendances Media3 indiquées ci-dessus.

  1. Pour garder la démo téléchargée installée à côté de votre propre compilation de test, changez le applicationId du module téléphonique en com.example.drmxtest. Laissez son espace de noms inchangé pour cet échantillon fourni.
  2. Construisez le APK, puis installez-le sur un périphérique USB- connecté Android avec le débogage autorisé USB.
# 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

Ouvrez l'application de test et appuyez sur Play. La source de téléphone fournie utilise la même démo publique initialement. Pour tester votre propre titre, remplacez les paramètres marqués session/offline/login et Publié Content ID dans MainActivity.kt, et fournissez l'authentification courte durée de votre propre utilisateur à l'exécution. Votre serveur conserve les Site Key et Access Key.

Les commandes compactes proviennent de DrmXPlayerView dans le AAR. L'activité fournie démontre la fonction Play-to-autoriser, la rotation réactive, la propriété de téléchargement, la lecture hors ligne et le renouvellement. Voir l'exemple d'intégration de contrôle ci-dessous lors de l'ajout de cette vue à votre propre application.

4. Requête du serveur et politique par défaut#

L'application Android demande à votre backend une session de lecture. Votre backend authentifie l'utilisateur, vérifie le droit, les cartes Content ID vers les médias publiés et les appels DRM-X. Voir Playback Session API pour le contrat de diffusion complet.

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

Les capacités conservatrices ci-dessus n'affirment pas Widevine L1. Utilisez l'aide de capacité du SDK, ou votre propre évaluation d'appareil, pour les appareils réels.

L'échantillon PHP par défaut est multi-tier-standard pour la lecture en ligne. Sélectionnez sa politique documentée à clé unique lorsque votre paquet utilise une clé. Votre politique doit correspondre au modèle de la clé du paquet et aux droits du spectateur. Changez la configuration du serveur ou son environnement DRMX_LICENSE_POLICY_TEMPLATE, pas un paramètre de requête dans le lecteur. Voir politiques de licence.

Offline a besoin de sa propre politique persistante.Jeu playback_policy.persistent à true dans la politique émise par le serveur et choisissez les durées de licence, de location, de lecture et de renouvellement. La référence utilise respectivement 7 jours / 3 jours / 48 heures / 7 jours; ce sont des règles d'affaires exemple, pas l'approbation de studio ou une plate-forme par défaut. Retourner des métadonnées correspondantes. La licence Widevine reste faisant autorité.

5. Chemin A: jouer à travers DrmXPlayer#

À l'intérieur de votre activité, créez un PlayerView, utilisez une fenêtre sécurisée et appelez prepare après l'ouverture de session. L'emballage échange la session, configure Widevine, applique la hauteur maximale retournée et libère la réservation en streaming lorsqu'elle est arrêtée. Les importations proviennent de com.haihaisoft.drmx.player et 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()

Inscrivez DrmXPlayerListener pour autoriser, préparer, jouer et erreur UI. Affichez des codes d'erreur sûrs plutôt que de jeter des jetons de licence ou des corps de réponse. Utilisez l'échantillon de téléphone inclus pour le cycle de vie complet, les contrôles à écran complet et la file d'attente de téléchargement.

Commandes du lecteur et rotation ininterrompue#

Appuyez sur Play sur la vidéo pour commencer l'autorisation. L'ouverture de l'écran ou des paramètres n'acquiert pas de licence de streaming.

DRM-X Android lecteur Paramètres sur un Samsung S24 Ultra, montrant Qualité, piste audio, Sous-titres/CC, Vitesse de lecture et minuterie Sleep.
Paramètres réels sur un Samsung S24 Ultra. Appuyez sur une ligne pour voir ses options disponibles; le sous-menu audio affiche les noms complets de la langue. La qualité et les langues disponibles dépendent du contenu, de la licence et de l'appareil.
ContrôleCe que les clients peuvent faire
QualitéChoisissez Auto ou une résolution sous licence prise en charge à partir du manifeste. Les options non disponibles expliquent la licence ou la restriction de l'appareil/DRM. Auto obéit aux mêmes restrictions.
Piste audioChoisissez n'importe quelle langue audio prise en charge fournie par le paquet.
Sous-titres/CCChoisissez un langage de sous-titre ou désactivez. Le bouton CC s'affiche lorsque les sous-titres pris en charge existent et les bascule directement.
Apparence de captionRéglez la police, la couleur et la taille du texte, les couleurs de fond/fenêtre et l'opacité. Les préférences sont enregistrées sur l'appareil.
Vitesse de lecture / minuterie de sommeilJouer à 0,25–2× vitesse ou pause automatiquement après un intervalle choisi.
Rechercher / plein écranFrottez la timeline, cherchez 10 secondes, ou double-tap de chaque côté. Rotation vers le paysage sans redémarrer la lecture.

Les trois actions compactes ci-dessous sont Download (pour une utilisation hors ligne), Play offline et Renouvelle (la licence hors ligne). L'échantillon télécharge un rendu vidéo autorisé et les pistes audio/sous-titrées prises en charge; les menus hors ligne exposent uniquement les médias téléchargés. Le renouvellement nécessite une connectivité.

Copier le journal à côté du pied de page d'information copie les erreurs récentes comme texte, de sorte que vous pouvez envoyer support les détails sans capture d'écran. ID, fonctionnement, SDK/Android/ version d'appareil, numérique CDM/Media3 les erreurs, les cadres de piles sélectionnés, l'état de connexion/téléchargement/playback et le nombre de répétitions. identifiants, URLs multimédias, clés, IDs de jeu de clés, données de licence et complet CDM Des ordures.

L'échantillon conserve jusqu'à 32 rapports locaux (64 KB) pendant cinq heures. Lorsqu'il est connecté et connecté, il télécharge les erreurs en attente au serveur client configuré, au plus une fois par 30 secondes. Le serveur de démo public conserve les avertissements/erreurs pendant cinq heures, combine des événements répétés, capte le fichier à 512 KB et prune chaque minute. La progression courante et la lecture réussie ne sont pas enregistrées. Les intégrations personnalisées doivent fournir explicitement leur propre source drmx.diagnosticsEndpoint ; les erreurs de diagnostic n'interrompent jamais la lecture.

Licence hors ligne déjà utilisée ?Preview.5 corrige la S24 Cas signalé CDM 368 avec license chargé dans différentes sessions. lecteur. Renouveler la première fois DRM session, puis renouvelle la licence stockée. Le téléchargement et la licence persistante sont conservés; aucune réinitialisation des données de l'application n'est nécessaire.
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()

Le manifeste du téléphone fourni gère les changements d'orientation et de taille d'écran; onConfigurationChanged redimensionne la même activité et lecteur. Gardez les deux parties lors de l'adaptation. Un hôte qui recrée les activités devrait conserver son propriétaire de lecture et réattacher la vue. Procéder à la mort est différent de la rotation et nécessite une restauration de l'état normal.DRM l'appui; CDM demeure faisant autorité.

Pour personnaliser lecteurs, arrêtez et relâchez la session active hors ligne DRM avant de vérifier, renouveler ou libérer la même licence persistante. La SDK de player.stopForOfflineLicenseOperation { /* call manager here */ } attend que la file d'attente de lecture Media3 relâche les médias. Les files d'attente de Plaine stop() fonctionnent asynchronement. Ne pas effectuer une autre checkLicense() pendant que la même licence est en cours de lecture; la lecture valide elle-même son état CDM. L'échantillon fourni montre la sortie complète et désactive les actions qui se chevauchent pendant le renouvellement.

6. Acquérir une licence et télécharger le média#

Tout en étant connecté, acquérir une Widevine licence et télécharger des pistes cryptées sélectionnées. Seule une licence valide plus un support complet produit la lecture déconnectée. CDM licence.
Prêt hors ligne = support chiffré complet + une licence valide liée à l'appareil. Ni l'un ne remplace l'autre.
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 */ }
}

Les SDK sauve l'opaque Widevine jeu de clés ID et des métadonnées non secrètes. CDM détient la licence. Il ne persiste pas DRM License Tokens, clés brutes, défis ou octets de réponse de licence. Exclure com.haihaisoft.drmx.offline.licenses.v1.xml des renforts.

Créez une application appartenant à Media3 SimpleCache, gestionnaire de téléchargement et base de données. Utilisez DownloadHelper avec le MediaItem sous licence et sélectionnez la vidéo dans maximumHeight. Dans Media3 1.11 le callback préparé est onPrepared(helper, tracksInfoUpdated). L'échantillon de téléphone enqueueDownload et OfflineTestRuntime montrent l'implémentation exécutable.

// 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()

Télécharger chaque langue que vous avez l'intention d'exposer hors ligne. Appeler createDownloadRequest sans clés de flux télécharge toutes les pistes, ce qui est généralement gaspillé pour la vidéo adaptative. Afficher la progression du téléchargement et attendre Download.STATE_COMPLETED. Pour les transferts de fond de production, intégrer Media3 DownloadService, les limites de stockage et Android les exigences de premier plan de service/notification; la file de démonstration fonctionne en cours de processus.

Contenu hors ligne multi-clés & #160;:Media3 restaure un jeu de clés ID pour un élément de lecture. Sa licence persistante doit contenir toutes les clés nécessaires pour les pistes vidéo, audio et autres cryptées sélectionnées. Testez ceci avec votre paquet réel et la politique du serveur; activer plusieurs sessions ne combine pas les licences indépendantes hors ligne.

7. Chemin B: restaurer avec votre Media3 lecteur#

Lire le téléchargement terminé et utiliser ses touches de flux exacts. La pile de téléchargement et de lecture doit partager le même emplacement de cache et la cartographie des touches. Cet exemple désactive délibérément l'accès en amont pour une lecture hors ligne stricte:

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.

Pour utiliser le même flux hors ligne avec le chemin A, construire DrmXPlayer avec ce mediaSourceFactory et appeler player.prepareOffline(playback). La restauration ordinaire utilise la licence locale CDM sans en demander une nouvelle. Une entrée de cache manquante devrait produire une erreur lors de l'acceptation déconnectée, ne pas basculer silencieusement vers Internet.

8. Chemin C: natif Media3, non DRM-X AAR #

Vous n'êtes pas tenu d'utiliser DrmXPlayer ou DrmXOfflineManager. Ajoutez les trois dépendances Media3 de l'étape 3 et implémentez le même contrat client. Utilisez session.manifestUrl (pas session.manifest.url), la licence retournée URL et les en-têtes d'autorisation limités. Appliquez la hauteur maximale retournée et manipulez la version de session en streaming sur stop, remplacement, fin, défaillance et destruction.

L'activité native complète ci-dessous est compilée sous la forme samples:native à côté de cette version SDK. Elle gère HTTPS, la lecture de la réponse limitée, l'autorisation de l'arrière-plan, les réponses statiques et la version de réservation. Remplacez le paramètre marqué/Content ID et fournissez votre propre jeton de connexion. L'exemple est un point de départ; ajoutez votre cycle de vie de mise à jour de production, de commutation de compte et d'application-navigation.

Activité de streaming native complète (Kotlin, aucune dépendance 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() }
        }
    }
}

Pour licence native hors ligne, utiliser OfflineLicenseHelper.downloadLicense, persistent son ensemble de clés opaques ID en privé et restaurer avec MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID).setKeySetId(id). L'aide compilée suivante couvre l'acquisition, les vérifications de durée, le renouvellement, la publication et le téléchargement / playback des éléments. pas une application de téléchargement complète: vous possédez toujours le cache, le service de téléchargement, le progrès, les métadonnées, l'utilisateur/dispositif et l'autorisation d'exploitation fiable.

Aide à la délivrance de licences persistantes (Kotlin, aucune dépendance 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())
    }
}

Avant d'appeler cet helper de bas niveau, validez que la nouvelle réponse du moteur correspond à la réponse demandée Content ID, fonctionnement, utilisateur/dispositif signé et période de validité de l'autorisation. Persistez un stable offlineLicenseId et des métadonnées manifeste/track de confiance à côté de l'ensemble de clés ID, jamais le jeton . Exécuter le blocage aide appelle sur un fil de travail . HTTP en-têtes utilisés setLicenseRequestHeaders sur la DRM la configuration; Widevine Les paramètres optionnels de la demande de clé sont une carte différente.

De nouvelles intégrations devraient être utilisées AndroidX Media3 DRM appui. Héritage com.google.android.exoplayer2 les projets devraient suivre Guide officiel des migrations; ne mélangez pas le legs et AndroidX classes ou supposent que l'échantillon compile inchangé par rapport aux anciennes versions.

9. Vérifier, renouveler, libérer et changer de langage #

Il s'agit d'actions séparées. Exécutez une à la fois après la sortie de la session active hors ligne DRM : utilisez player.stopForOfflineLicenseOperation { /* one operation below */ } avec DrmXPlayer, ou relâchez d'abord le natif existant Media3 lecteur. Ne vérifiez pas une licence pendant qu'elle est en cours de lecture. Une vérification est facultative pour afficher les durées; elle ne doit pas empêcher le renouvellement d'une licence expirée.

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 lit les métadonnées; checkLicense interroge les durées locales autorisées CDM. Le renouvellement/release nécessite une connectivité et une nouvelle autorisation spécifique à l'opération de votre moteur. La suppression des médias ne libère pas la licence. Lorsqu'elle est déconnectée, la sortie de file d'attente pour la prochaine connexion plutôt que de signaler que le serveur l'a confirmée. Fermer le gestionnaire lorsque son propriétaire est détruit.

// 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()

Une préférence ne peut pas créer une piste anglaise absente du paquet. Les utilisateurs hors ligne ne peuvent sélectionner que les langues téléchargées. Préserver license/cache état à travers la rotation de l'écran; plein écran est un changement de vue/fenêtre, pas une raison d'acquérir une autre licence.

10. Mettre en œuvre le paramètre d'autorisation hors ligne#

L'application affiche contentId, contentType: "vod", drmSystem: "widevine", playbackMode: "offline", operation: "acquire" | "renew" | "release", offlineLicenseId (null pour l'acquisition initiale) et véridique platformCapabilities. Vérifiez que les identifiants de renouvellement/release appartiennent à l'utilisateur, au périphérique et au contenu authentifiés. Sélectionnez le côté serveur de la politique, publiez un nouveau DRM License Token et retournez le contrat correspondant:

{
  "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
  }
}

Ce sont des détenteurs de place explicatifs, pas une réponse réutilisable de licence. Retourner des valeurs fraîches de l'opération réelle. SDK soutient également integrationMode: "token-proxy" avec une limite drm.authorization Descripteur. Retour Cache-Control: no-store; ne jamais enregistrer les organismes d'autorisation réussis. SDK's OFFLINE_INTEGRATION.md et PHP le paramètre hors ligne de l'échantillon pour la gestion des demandes concrètes.

11. Testez vos appareils et dépannage #

Widevine fourniture et essais en réseau en Chine

Provisionnement obtient le certificat de périphérique avant l'acquisition de licence de contenu. De prévisualisation.9 la démo du téléphone envoie la demande signée de CDM par son client authentifié HTTPS relais à Google. La réponse signée retourne inchangée. Cela aide lorsque le téléphone ne peut pas atteindre le service de fourniture de Google directement; le relais client doit toujours être accessible.

Provisioning 2.0 utilise une boîte à clés d'usine. Provisioning 4.0 utilise un autre modèle de justificatif de périphérique. Ces versions sont séparées des niveaux de sécurité L1/L3, et le lecteur ne les commute pas. Un téléphone déjà fourni L3 peut jouer pendant qu'un autre téléphone attend la fourniture d'appareils. Les sources officielles publiques examinées ici n'établissent pas que la Chine supporte seulement 2.0. Voir NXP's device integration guide and Android's provisioning implementation.

Prévisualiser.10 rapports d'erreur distinguent le transport direct ou relais, timeout/DNS/TLS/HTTP défaillance, HTTP le statut et le temps écoulé. provisioningModel: BootCertificateChain indique que AOSP le modèle 4.0; unknown ou other n'établit pas 2.0. PHP les journaux distinguent les entrées rejetées des échecs Google en amont. identifiants et des identifiants uniques de l'appareil.

Mettre à jour le APK en place, réessayer le streaming et un téléchargement sur le réseau affecté, puis conserver le journal de copie et l'heure approximative. Les téléchargements et licences existants sont conservés. Un relais ne peut pas réparer non disponible Widevine ou identifiants rejeté par l'appareil/Google. Une acceptation réelle sur le téléphone affecté est nécessaire.

De l'aperçu.8, natif L2/L3 ou à un niveau inconnu Widevine la lecture est limitée à SD (jusqu'à 576p) avant le décodage. Android capacités par l'intermédiaire de votre moteur : la session API restreint le logiciel Widevine licences multi-clés pour audio/SD les clés. PHP l'échantillon conserve ces champs et capte également les demandes hors ligne. SD la restitution et une politique permettant le logiciel DRM sont nécessaires; les règles de sécurité uniques et uniformes du matériel restent inchangées. Les paramètres utilisent un panneau translucide sans diminuer la vidéo. cryptoErrorCode est inclus dans les rapports d'erreur sûrs.

Test/symptômeComportement attendu / prochaine vérification
SDK le téléchargement retourne 403Sélectionnez une organisation avec un abonnement professionnel ou Enterprise actif. Une mise à jour prévue après l'essai ne déverrouille pas le SDK.
Séance 401/403Vérifier la connexion, le droit, l'environnement, publié Content ID et la politique. Ne jamais contourner l'authentification.
Hors ligne échoue mais fonctionne en ligneVérifiez CDM durées, téléchargement terminé, emplacement du cache, clés de flux et toutes les clés sous licence requises.
Français / Chinois manquantVérifiez les métadonnées de la langue du paquet, les pistes réelles et la sélection hors ligne de la langue.
L1, HDCP ou défaillance du décodeurVérifiez le matériel physique, la fourniture, le codec et les exigences de sortie. Une chaîne de capacité n'est pas une certification.
Redémarrage, rotation, mise à niveauLicence et cache persistants survivent aux changements de cycle de vie supportés sans acquisition dupliquée. Les sauvegardes ne doivent pas migrer les licences vers un nouvel appareil.
Mode avionDésactiver aussi le Wi-Fi et les données mobiles; redémarrer l'application, jouer localement et changer chaque langue promise.
Expiration, pression de stockage, interrupteur de compteAfficher un état clair non disponible/renouveller, récupérer des médias incomplets, et faire appliquer l'accès utilisateur/appareil sans fuite du catalogue hors ligne d'un autre utilisateur.

Qualifier chaque téléphone, tablette, Android TV/Google TV, Fire TV ou modèle Android intégré pour Widevine, décodage sécurisé, codec/résolution, HDCP, affichages externes, changements d'horloge et longue déconnexion. Tous les appareils Android n'ont pas les mêmes capacités DRM.

Aucune occasion d'acquérir avant la déconnexion?C'est un déploiement différent : un service de licence embarqué qualifié délivre des licences sur le réseau local pendant le trajet. Il n'est pas activé simplement en utilisant ce SDK. DRM-X peut travailler avec vous sur un déploiement personnalisé couvrant les permissions du fournisseur, la fourniture, la protection des clés et un test d'acceptation complètement déconnecté. Voir à bord DRM pour aéronefs, autobus, trains et navires.

Universal Player listes de lecture et contrôles partagés #

L'aperçu Android.11 et les applications d'évaluation ultérieures et les sources de développement actuelles Android/Apple partagent dans la vidéo Précédent/Play-Pause/Next, CC, Paramètres et commandes en plein écran avec deux secondes de cache pendant la lecture. Le menu playlist de Android n'inclut plus le menu Play next. Les réglages sélectionnés shuffle/repeat restent surlignés et persistent lors des redémarrages. Avec les deux versions, la lecture suit l'ordre de la playlist sauvegardée et s'arrête à la vidéo finale. Drag gère les réordres sans redémarrer la vidéo actuelle; l'ordre sauvegardé s'applique également à la playlist téléchargée. Ces dernières APIs sources ne sont pas encore incluses dans l'aperçu de la console.10 SDK paquet.

Fournissez le même client/spectateur storageNamespace à DrmXPlayer et playerView.storageNamespace avant de définir la liste de lecture. VOD progrès est enregistré périodiquement et sur pause/arrêt, puis restauré pour cela Content ID dans la lecture en streaming ou téléchargée. Lecture en direct n'utilise pas une position enregistrée VOD. Les téléchargements complétés conservent le même comportement shuffle/repeat/resume sans source de médias réseau. Cet état périphérique-local ne synchronise pas les progrès entre les appareils.

Les éditions Web et Android utilisent un panneau de paramètres sombres cohérent avec des commandes bleues compactes. Les listes de lecture prennent en charge l'avance automatique suivante/précédente, shuffle, répétez un/tout et cancellable. Chaque élément utilise une nouvelle demande de lecture autorisée.

La vitesse de lecture, la minuterie de sommeil, les légendes, la qualité autorisée, les langues audio, les signets de session et la boucle A–B sont disponibles. Web ajoute des raccourcis clavier, le CV local visionné en option, la recherche de transcription et le navigateur pris en charge PiP. Android conserve natif Widevine téléchargements hors ligne et le renouvellement.

Paramètres du logo professionnel et d'entreprise

Open Settings → A propos de lecteur pour le logo autorisé, l'information sur le produit et la version lecteur. Web offre également cette information en un clic droit. La démo du téléphone public comprend WayMaker, Goodness of God, Fresh Oil et 4K Test Video; chaque sélection reçoit sa propre autorisation.

Définissez playerBranding dans votre moteur de confiance vers {"mode":"hidden"} ou {"mode":"custom","logoUrl":"https://your-site.example/logo.png","label":"Your brand"}. La plate-forme vérifie l'abonnement professionnel actif ou Enterprise. D'autres plans utilisent {"mode":"default"}; des requêtes non autorisées personnalisées/cachées retournent 403. Ceci est séparé des filigranes de sécurité.

Les PHP le téléchargement inclut la configuration de playlist modifiable et de marque. Android client ZIP inclut l'exemple de callback de liste de lecture. Gardez l'autorisation de liste de lecture dans votre backend; ne jamais intégrer API client identifiants dans les deux lecteur.