Wstawianie reklam

ExoPlayer może być używany zarówno do wstawiania reklam po stronie klienta, jak i po stronie serwera.

Wstawianie reklam po stronie klienta

W przypadku wstawiania reklam po stronie klienta odtwarzacz przełącza się między wczytywaniem multimediów z różnych adresów URL podczas przechodzenia od treści do reklam i z powrotem. Informacje o reklamach są ładowane oddzielnie od multimediów, np. z tagu reklamy XML VAST lub VMAP. Może to obejmować pozycje sygnałów reklamy względem początku treści, rzeczywiste URI multimediów reklamy i metadane, takie jak informacja o tym, czy dana reklama jest możliwa do pominięcia.

Gdy używasz funkcji AdsMediaSource ExoPlayera do wstawiania reklam po stronie klienta, odtwarzacz ma informacje o reklamach, które mają być odtwarzane. Daje to kilka korzyści:

  • Odtwarzacz może udostępniać metadane i funkcje związane z reklamami za pomocą interfejsu API.
  • Komponenty interfejsu ExoPlayera mogą automatycznie wyświetlać znaczniki pozycji reklamy i zmieniać swoje zachowanie w zależności od tego, czy reklama jest odtwarzana.
  • Odtwarzacz może utrzymywać stały bufor podczas przejść między reklamami a treściami.

W takim przypadku odtwarzacz zajmuje się przełączaniem między reklamami a treściami, co oznacza, że aplikacje nie muszą kontrolować wielu odrębnych odtwarzaczy reklam i treści w tle lub na pierwszym planie.

Przygotowując filmy z treściami i tagi reklam do użycia z wstawianiem reklam po stronie klienta, reklamy powinny być umieszczone w punktach synchronizacji (kluczowych klatkach) w filmie z treściami, aby odtwarzacz mógł płynnie wznowić odtwarzanie treści.

Deklaratywna obsługa reklam

Adres URI tagu reklamy można określić podczas tworzenia MediaItem:

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

Aby umożliwić obsługę odtwarzacza w przypadku elementów multimedialnych, które określają tagi reklam, podczas tworzenia odtwarzacza musisz utworzyć i wstrzyknąć DefaultMediaSourceFactory skonfigurowany za pomocą AdsLoader.Provider i AdViewProvider:

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

Wewnętrznie DefaultMediaSourceFactory owija źródło multimediów treści w element AdsMediaSource. AdsMediaSource pobiera AdsLoader z AdsLoader.Provider i używa go do wstawiania reklam zgodnie z tagiem reklamy elementu multimedialnego.

PlayerView w ExoPlayer implementuje AdViewProvider. Biblioteka ExoPlayer IMA udostępnia łatwy w użyciu AdsLoader, jak opisano poniżej.

Playlisty z reklamami

Podczas odtwarzania playlisty zawierającej wiele elementów multimedialnych domyślnie wysyłane jest żądanie tagu reklamy i stan odtwarzania reklamy jest przechowywany raz dla każdej kombinacji identyfikatora multimediów, identyfikatora URI treści i identyfikatora URI tagu reklamy. Oznacza to, że użytkownicy będą widzieć reklamy dla każdego elementu multimedialnego z reklamami, który ma odrębny identyfikator multimediów lub adres URI treści, nawet jeśli adresy URI tagów reklamy będą się pokrywać. Jeśli element multimediów jest powtarzany, użytkownik zobaczy odpowiadające mu reklamy tylko raz (stan odtwarzania reklam przechowuje informacje o tym, czy reklamy zostały odtworzone, więc są one pomijane po pierwszym wystąpieniu).

To zachowanie można dostosować, przekazując nieprzezroczysty identyfikator reklamy, z którym stan odtwarzania reklamy dla danego elementu multimedialnego jest powiązany na podstawie równości obiektów. Oto przykład, w którym stan odtwarzania reklamy jest powiązany tylko z adresem URL tagu reklamy, a nie z kombinacją identyfikatora multimediów i adresu URL tagu reklamy. Adres URL tagu reklamy jest przekazywany jako identyfikator reklamy. W efekcie reklamy będą wczytywane tylko raz, a użytkownik nie zobaczy reklamy w przypadku drugiego elementu podczas odtwarzania playlisty od początku do końca.

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

Wstawianie reklam po stronie klienta z użyciem sygnałów po stronie serwera

ExoPlayer jest dostarczany z funkcją HlsInterstitialsAdsLoader, która obsługuje automatyczne wstawianie reklam zdefiniowanych w playliście HLS po stronie klienta. Zapoznaj się z sekcją HlsInterstitialsAdsLoader na stronie HLS.

Biblioteka ExoPlayer IMA

Biblioteka IMA ExoPlayera zapewnia ImaAdsLoader, co ułatwia integrację wstawiania reklam po stronie klienta w aplikacji. Opisuje ona funkcjonalność pakietu IMA SDK po stronie klienta, aby obsługiwać wstawianie reklam VAST/VMAP. Instrukcje dotyczące korzystania z biblioteki, w tym informacje o odtwarzaniu w tle i wznawianiu odtwarzania, znajdziesz w pliku README.

Aplikacja demonstracyjna korzysta z biblioteki IMA i zawiera na liście przykładów kilka przykładowych tagów reklam VAST/VMAP.

Interfejs użytkownika

PlayerView domyślnie ukrywa elementy sterujące podczas odtwarzania reklam, ale aplikacje mogą przełączać to zachowanie, wywołując setControllerHideDuringAds. Podczas odtwarzania reklamy IMA SDK wyświetla dodatkowe widoki u góry odtwarzacza (np. link „Więcej informacji” i przycisk pomijania, jeśli jest dostępny).

Pakiet IMA SDK może zgłaszać, czy reklamy są zasłonięte przez widoki aplikacji renderowane na górze odtwarzacza. Aplikacje, które muszą nakładać widoki, które są niezbędne do sterowania odtwarzaniem, muszą zarejestrować je w pakiecie IMA SDK, aby można było pominąć je podczas obliczania widoczności. Gdy używasz PlayerView jako AdViewProvider, automatycznie rejestruje nakładki sterowania. Aplikacje, które korzystają z niestandardowego interfejsu odtwarzacza, muszą rejestrować widoki nakładki, zwracając je z funkcji AdViewProvider.getAdOverlayInfos.

Więcej informacji o widokach nakładki znajdziesz w artykule Open Measurement w SDK IMA.

Reklamy towarzyszące

Niektóre tagi reklam zawierają dodatkowe reklamy towarzyszące, które mogą się wyświetlać w „miejscach” w interfejsie aplikacji. Te sloty można przekazać za pomocą funkcji ImaAdsLoader.Builder.setCompanionAdSlots(slots). Więcej informacji znajdziesz w artykule Dodawanie reklam towarzyszących.

Reklamy samodzielne

Pakiet IMA SDK służy do wstawiania reklam do treści multimedialnych, a nie do samodzielnego odtwarzania reklam. Biblioteka IMA nie obsługuje odtwarzania reklam samodzielnych. W tym przypadku zalecamy użycie pakietu SDK do reklam mobilnych Google.

Korzystanie z zewnętrznego pakietu SDK reklam

Jeśli musisz wczytywać reklamy za pomocą pakietu SDK reklam innej firmy, sprawdź, czy zawiera on już integrację z ExoPlayerem. Jeśli nie, zalecamy wdrożenie niestandardowego pakietu AdsLoader, który otacza zewnętrzny pakiet SDK reklam, ponieważ zapewnia korzyści AdsMediaSource opisane powyżej. ImaAdsLoader jest przykładową implementacją.

Możesz też użyć obsługi playlisty w ExoPlayerze, aby utworzyć sekwencję reklam i klipów treści:

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

Wstawianie reklam po stronie serwera

W przypadku wstawiania reklam po stronie serwera (zwanego też dynamicznym wstawianiem reklam, czyli DAI) strumień multimediów zawiera zarówno reklamy, jak i treści. Plik manifestu DASH może wskazywać zarówno treści, jak i segmenty reklam, prawdopodobnie w osobnych przedziałach czasu. W przypadku HLS zapoznaj się z dokumentacją Apple dotyczącą włączania reklam do playlisty.

Jeśli korzystasz z wstawiania reklam po stronie serwera, klient może potrzebować dynamicznego rozwiązywania adresu URL multimediów, aby uzyskać zszyty strumień. Może też potrzebować wyświetlania nakładek reklamowych w interfejsie lub zgłaszania zdarzeń do pakietu SDK reklam lub serwera reklam.

DefaultMediaSourceFactory ExoPlayera może delegować wszystkie te zadania do wstawiania reklam po stronie serwera MediaSource w przypadku URI z użyciem schematu ssai://:

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

Biblioteka ExoPlayer IMA

Biblioteka IMA ExoPlayer zapewnia ImaServerSideAdInsertionMediaSource, co ułatwia integrację z reklamami wstawianymi po stronie serwera IMA w Twojej aplikacji. Zawiera ona funkcjonalność interfejsu IMA DAI SDK na Androida i pełną integrację dostarczonych metadanych reklam z odtwarzaczem. Dzięki temu możesz na przykład używać metod takich jak Player.isPlayingAd(), wykrywać przejścia między treściami a reklamami oraz pozwolić odtwarzaczowi obsługiwać logikę odtwarzania reklam, np. pomijanie już odtworzonych reklam.

Aby korzystać z tej klasy, musisz skonfigurować ImaServerSideAdInsertionMediaSource.AdsLoader i ImaServerSideAdInsertionMediaSource.Factory oraz połączyć je z odtwarzaczem:

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

Załaduj klucz zasobu IMA lub identyfikator źródła treści i identyfikator filmu, tworząc adres URL z: ImaServerSideAdInsertionUriBuilder:

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

Na koniec zwolnij ładowarkę reklam, gdy nie jest już używana:

Kotlin

adsLoader.release()

Java

adsLoader.release();

Interfejs użytkownika

W przypadku wstawiania reklam po stronie serwera obowiązują te same założenia dotyczące interfejsu użytkownika, co w przypadku wstawiania reklam po stronie klienta.

Reklamy towarzyszące

Niektóre tagi reklam zawierają dodatkowe reklamy towarzyszące, które mogą się wyświetlać w „miejscach” w interfejsie aplikacji. Te sloty można przekazać za pomocą funkcji ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots). Więcej informacji znajdziesz w artykule Dodawanie reklam towarzyszących.

Korzystanie z zewnętrznego pakietu SDK reklam

Jeśli musisz wczytywać reklamy za pomocą pakietu SDK reklam innej firmy, sprawdź, czy zawiera on już integrację z ExoPlayerem. W przeciwnym razie zalecamy podanie niestandardowego parametru MediaSource, który akceptuje identyfikatory URI o schemacie ssai:// podobnym do ImaServerSideAdInsertionMediaSource.

Rzeczywista logika tworzenia struktury reklamy może zostać powierzona ogólnemu elementowi ServerSideAdInsertionMediaSource, który otacza strumień MediaSource i umożliwia użytkownikowi ustawianie i aktualizowanie wartości AdPlaybackState reprezentujących metadane reklamy.

Strumienie reklam wstawiane po stronie serwera często zawierają zdarzenia czasowe, które informują odtwarzacz o metadanych reklamy. Informacje o tym, jakie formaty metadanych synchronizowanych obsługuje ExoPlayer, znajdziesz w sekcji Obsługiwane formaty. Implementacje niestandardowych pakietów SDK do reklamMediaSource mogą nasłuchiwać zdarzeń metadanych z odmierzanym czasem z odtwarzacza za pomocą funkcji Player.Listener.onMetadata.