ExoPlayer kann sowohl für die clientseitige als auch für die serverseitige Anzeigenbereitstellung verwendet werden.
Clientseitige Anzeigenbereitstellung
Bei der clientseitigen Anzeigenbereitstellung wechselt der Player beim Übergang zwischen der Wiedergabe von Inhalten und Anzeigen zwischen dem Laden von Medien aus verschiedenen URLs. Informationen zu Anzeigen werden getrennt von den Medien geladen, z. B. aus einem XML-Anzeigen-Tag vom Typ VAST oder VMAP. Dazu gehören die Positionen der Anzeigen-Cues relativ zum Beginn des Inhalts, die tatsächlichen URIs der Anzeigenmedien und Metadaten wie etwa, ob eine bestimmte Anzeige überspringbar ist.
Wenn du die AdsMediaSource
von ExoPlayer für die clientseitige Anzeigenbereitstellung verwendest, hat der Player Informationen zu den wiederzugebenden Anzeigen. Das hat mehrere Vorteile:
- Der Player kann über seine API Metadaten und Funktionen im Zusammenhang mit Anzeigen freigeben.
- ExoPlayer-UI-Komponenten können Markierungen für Anzeigenpositionen automatisch anzeigen und ihr Verhalten ändern, je nachdem, ob eine Anzeige wiedergegeben wird.
- Intern kann der Player bei Übergängen zwischen Anzeigen und Inhalten einen konstanten Puffer beibehalten.
Bei dieser Konfiguration kümmert sich der Player um den Wechsel zwischen Anzeigen und Inhalten. Das bedeutet, dass Apps nicht mehrere separate Player für Hintergrund-/Vordergrundanzeigen und Inhalte steuern müssen.
Wenn du Videoinhalte und Anzeigen-Tags für die clientseitige Anzeigenbereitstellung vorbereitest, sollten Anzeigen idealerweise an Synchronisierungsproben (Keyframes) im Videoinhalt platziert werden, damit die Wiedergabe des Inhalts nahtlos fortgesetzt werden kann.
Unterstützung für deklarative Anzeigen
Ein Anzeigen-Tag-URI kann beim Erstellen eines MediaItem
angegeben werden:
Kotlin
val mediaItem = MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build()
Java
MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build();
Wenn du die Player-Unterstützung für Medienelemente mit Anzeigen-Tags aktivieren möchtest, musst du beim Erstellen des Players ein DefaultMediaSourceFactory
mit einem AdsLoader.Provider
und einem AdViewProvider
erstellen und einfügen:
Kotlin
val mediaSourceFactory: MediaSource.Factory = DefaultMediaSourceFactory(context).setLocalAdInsertionComponents(adsLoaderProvider, playerView) val player = ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build()
Java
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(context) .setLocalAdInsertionComponents(adsLoaderProvider, /* adViewProvider= */ playerView); ExoPlayer player = new ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build();
Intern umschließt DefaultMediaSourceFactory
die Content-Medienquelle in einem AdsMediaSource
. Die AdsMediaSource
ruft eine AdsLoader
von der AdsLoader.Provider
ab und verwendet sie, um Anzeigen einzufügen, wie im Anzeigen-Tag des Medienelements definiert.
PlayerView
von ExoPlayer implementiert AdViewProvider
. Die ExoPlayer IMA-Bibliothek bietet eine nutzerfreundliche AdsLoader
, wie unten beschrieben.
Playlists mit Werbung
Wenn eine Playlist mit mehreren Medienelementen wiedergegeben wird, wird standardmäßig das Anzeigen-Tag angefordert und der Wiedergabestatus der Anzeige einmal für jede Kombination aus Medien-ID, Inhalts-URI und Anzeigen-Tag-URI gespeichert. Das bedeutet, dass Nutzern Anzeigen für jedes Medienelement mit Anzeigen mit einer eindeutigen Medien-ID oder einem eindeutigen Inhalts-URI präsentiert werden, auch wenn die URIs der Anzeigen-Tags übereinstimmen. Wenn ein Medienelement wiederholt wird, sieht der Nutzer die entsprechenden Anzeigen nur einmal. Im Wiedergabestatus der Anzeigen wird gespeichert, ob Anzeigen bereits wiedergegeben wurden. Sie werden also nach dem ersten Vorkommen übersprungen.
Du kannst dieses Verhalten anpassen, indem du eine opake Anzeigen-ID übergibst, die mit dem Wiedergabestatus der Anzeige für ein bestimmtes Medienelement verknüpft ist, basierend auf der Objektgleichheit. Hier ein Beispiel, in dem der Wiedergabestatus der Anzeige nur mit dem Anzeigen-Tag-URI verknüpft ist, nicht mit der Kombination aus Medien-ID und Anzeigen-Tag-URI. Dazu wird der Anzeigen-Tag-URI als Anzeigen-ID übergeben. Das hat zur Folge, dass Anzeigen nur einmal geladen werden und der Nutzer beim Abspielen der Playlist von Anfang bis Ende keine Anzeigen für den zweiten Titel sieht.
Kotlin
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. val firstItem = MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() val secondItem = MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() player.addMediaItem(firstItem) player.addMediaItem(secondItem)
Java
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. MediaItem firstItem = new MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); MediaItem secondItem = new MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); player.addMediaItem(firstItem); player.addMediaItem(secondItem);
Servergestützte clientseitige Anzeigenbereitstellung
ExoPlayer enthält HlsInterstitialsAdsLoader
, das Anzeigen unterstützt, die in der HLS-Playlist definiert sind und automatisch auf der Clientseite eingefügt werden. Weitere Informationen findest du im Abschnitt zu HlsInterstitialsAdsLoader
auf der HLS-Seite.
ExoPlayer IMA-Bibliothek
Die ExoPlayer IMA-Bibliothek bietet ImaAdsLoader
, wodurch die clientseitige Anzeigenbereitstellung in Ihre App ganz einfach eingebunden werden kann. Sie umschließt die Funktionen des clientseitigen IMA SDK, um die Einbindung von VAST-/VMAP-Anzeigen zu unterstützen. Eine Anleitung zur Verwendung der Bibliothek, einschließlich der Wiedergabe im Hintergrund und der Wiederaufnahme der Wiedergabe, findest du in der README-Datei.
Die Demoanwendung verwendet die IMA-Bibliothek und enthält mehrere Beispiel-VAST-/VMAP-Anzeigen-Tags in der Beispielliste.
Hinweise zur Benutzeroberfläche
PlayerView
blendet seine Transportsteuerungen während der Wiedergabe von Anzeigen standardmäßig aus. Apps können dieses Verhalten jedoch durch Aufrufen von setControllerHideDuringAds
umschalten. Das IMA SDK zeigt während der Wiedergabe einer Anzeige zusätzliche Ansichten über dem Player an, z. B. einen Link „Weitere Informationen“ und gegebenenfalls eine Schaltfläche zum Überspringen.
Das IMA SDK kann melden, ob Anzeigen von vom App-Anbieter bereitgestellten Ansichten verdeckt werden, die über dem Player gerendert werden. In Apps, in denen Ansichten eingeblendet werden müssen, die für die Wiedergabesteuerung unerlässlich sind, müssen diese Ansichten im IMA SDK registriert werden, damit sie bei der Sichtbarkeitsberechnung nicht berücksichtigt werden. Wenn Sie PlayerView
als AdViewProvider
verwenden, werden die Steuerelement-Overlays automatisch registriert. Apps, die eine benutzerdefinierte Player-Benutzeroberfläche verwenden, müssen Overlay-Ansichten registrieren, indem sie sie von AdViewProvider.getAdOverlayInfos
zurückgeben.
Weitere Informationen zu Overlay-Ansichten finden Sie unter Open Measurement im IMA SDK.
Companion-Anzeigen
Einige Anzeigen-Tags enthalten zusätzliche Companion-Anzeigen, die in „Slots“ in der App-Benutzeroberfläche ausgeliefert werden können. Diese Slots können über ImaAdsLoader.Builder.setCompanionAdSlots(slots)
übergeben werden. Weitere Informationen finden Sie unter Komplementaranzeigen hinzufügen.
Eigenständige Anzeigen
Das IMA SDK ist zum Einfügen von Anzeigen in Mediacontent gedacht, nicht zum eigenständigen Abspielen von Anzeigen. Daher wird die Wiedergabe von eigenständigen Anzeigen von der IMA-Bibliothek nicht unterstützt. Für diesen Anwendungsfall empfehlen wir stattdessen das Google Mobile Ads SDK.
Anzeigen-SDK eines Drittanbieters verwenden
Wenn Sie Anzeigen über ein Anzeigen-SDK eines Drittanbieters laden müssen, sollten Sie prüfen, ob es bereits eine ExoPlayer-Integration bietet. Andernfalls wird empfohlen, eine benutzerdefinierte AdsLoader
zu implementieren, die das SDK für Drittanbieteranzeigen umschließt. Sie bietet die oben beschriebenen Vorteile von AdsMediaSource
.
ImaAdsLoader
dient als Beispielimplementierung.
Alternativ kannst du die Playlist-Unterstützung von ExoPlayer verwenden, um eine Abfolge von Anzeigen und Inhaltsclips zu erstellen:
Kotlin
// A pre-roll ad. val preRollAd = MediaItem.fromUri(preRollAdUri) // The start of the content. val contentStart = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(ClippingConfiguration.Builder().setEndPositionMs(120000).build()) .build() // A mid-roll ad. val midRollAd = MediaItem.fromUri(midRollAdUri) // The rest of the content val contentEnd = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(ClippingConfiguration.Builder().setStartPositionMs(120000).build()) .build() // Build the playlist. player.addMediaItem(preRollAd) player.addMediaItem(contentStart) player.addMediaItem(midRollAd) player.addMediaItem(contentEnd)
Java
// A pre-roll ad. MediaItem preRollAd = MediaItem.fromUri(preRollAdUri); // The start of the content. MediaItem contentStart = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new ClippingConfiguration.Builder().setEndPositionMs(120_000).build()) .build(); // A mid-roll ad. MediaItem midRollAd = MediaItem.fromUri(midRollAdUri); // The rest of the content MediaItem contentEnd = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new ClippingConfiguration.Builder().setStartPositionMs(120_000).build()) .build(); // Build the playlist. player.addMediaItem(preRollAd); player.addMediaItem(contentStart); player.addMediaItem(midRollAd); player.addMediaItem(contentEnd);
Serverseitige Anzeigenbereitstellung
Bei der serverseitigen Anzeigenbereitstellung (auch dynamische Anzeigenbereitstellung, DAI) enthält der Mediastream sowohl Anzeigen als auch Inhalte. Ein DASH-Manifest kann sowohl auf Inhalts- als auch auf Anzeigensegmente verweisen, möglicherweise in separaten Zeiträumen. Informationen zu HLS findest du in der Apple-Dokumentation zum Einfügen von Anzeigen in eine Playlist.
Bei der serverseitigen Anzeigenbereitstellung muss der Client möglicherweise die Medien-URL dynamisch auflösen, um den zusammengefügten Stream abzurufen. Außerdem muss er möglicherweise Anzeigen-Overlays in der Benutzeroberfläche anzeigen oder Ereignisse an ein Anzeigen-SDK oder einen Anzeigenserver melden.
Die DefaultMediaSourceFactory
von ExoPlayer kann alle diese Aufgaben an eine serverseitige Anzeigenbereitstellung MediaSource
für URIs mit dem ssai://
-Schema delegieren:
Kotlin
val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setServerSideAdInsertionMediaSourceFactory(ssaiFactory) ) .build()
Java
Player player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setServerSideAdInsertionMediaSourceFactory(ssaiFactory)) .build();
ExoPlayer IMA-Bibliothek
Die ExoPlayer IMA-Bibliothek bietet ImaServerSideAdInsertionMediaSource
, sodass sich die serverseitig eingefügten Anzeigenstreams von IMA ganz einfach in deine App einbinden lassen. Sie umschließt die Funktionen des IMA DAI SDK für Android und integriert die bereitgestellten Anzeigenmetadaten vollständig in den Player. So kannst du beispielsweise Methoden wie Player.isPlayingAd()
verwenden, Übergänge zwischen Inhalten und Anzeigen überwachen und den Player die Logik für die Anzeigenwiedergabe steuern lassen, z. B. das Überspringen bereits wiedergegebener Anzeigen.
Wenn du diese Klasse verwenden möchtest, musst du ImaServerSideAdInsertionMediaSource.AdsLoader
und ImaServerSideAdInsertionMediaSource.Factory
einrichten und mit dem Player verbinden:
Kotlin
// MediaSource.Factory to load the actual media stream. val defaultMediaSourceFactory = DefaultMediaSourceFactory(context) // AdsLoader that can be reused for multiple playbacks. val adsLoader = ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build() // MediaSource.Factory to create the ad sources for the current player. val adsMediaSourceFactory = ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory) // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory) // Set the MediaSource.Factory on the Player. val player = ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build() // Set the player on the AdsLoader adsLoader.setPlayer(player)
Java
// MediaSource.Factory to load the actual media stream. DefaultMediaSourceFactory defaultMediaSourceFactory = new DefaultMediaSourceFactory(context); // AdsLoader that can be reused for multiple playbacks. ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader = new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build(); // MediaSource.Factory to create the ad sources for the current player. ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory = new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory); // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory); // Set the MediaSource.Factory on the Player. Player player = new ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build(); // Set the player on the AdsLoader adsLoader.setPlayer(player);
Lade deinen IMA-Asset-Schlüssel oder die Content-Quell-ID und die Video-ID, indem du eine URL mit ImaServerSideAdInsertionUriBuilder
erstellst:
Kotlin
val ssaiUri = ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build() player.setMediaItem(MediaItem.fromUri(ssaiUri))
Java
Uri ssaiUri = new ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build(); player.setMediaItem(MediaItem.fromUri(ssaiUri));
Entfernen Sie den Anzeigen-Lademechanismus, sobald er nicht mehr verwendet wird:
Kotlin
adsLoader.release()
Java
adsLoader.release();
Hinweise zur Benutzeroberfläche
Für die serverseitige Anzeigenbereitstellung gelten dieselben Überlegungen zur Benutzeroberfläche wie bei der clientseitigen Anzeigenbereitstellung.
Companion-Anzeigen
Einige Anzeigen-Tags enthalten zusätzliche Companion-Anzeigen, die in „Slots“ in der App-Benutzeroberfläche ausgeliefert werden können. Diese Slots können über ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots)
übergeben werden.
Weitere Informationen finden Sie unter Komplementaranzeigen hinzufügen.
Anzeigen-SDK eines Drittanbieters verwenden
Wenn du Anzeigen über ein Anzeigen-SDK eines Drittanbieters laden musst, solltest du prüfen, ob es bereits eine ExoPlayer-Integration bietet. Andernfalls sollten Sie eine benutzerdefinierte MediaSource
angeben, die URIs mit dem ssai://
-Schema akzeptiert, ähnlich wie ImaServerSideAdInsertionMediaSource
.
Die eigentliche Logik zum Erstellen der Anzeigenstruktur kann an den allgemeinen Zweck ServerSideAdInsertionMediaSource
delegiert werden, der einen Stream MediaSource
umschließt und es dem Nutzer ermöglicht, die AdPlaybackState
festzulegen und zu aktualisieren, die die Anzeigenmetadaten darstellen.
Serverseitig eingefügte Anzeigenstreams enthalten häufig zeitgesteuerte Ereignisse, um den Player über Anzeigenmetadaten zu informieren. Informationen zu den von ExoPlayer unterstützten Zeitmetadatenformaten findest du unter Unterstützte Formate. Bei MediaSource
-Implementierungen des Custom Ads SDK kann mit Player.Listener.onMetadata
auf zeitgesteuerte Metadatenereignisse vom Player gewartet werden.