Wstawianie reklam

ExoPlayer może być używany do wstawiania reklam zarówno 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 odtwarzania treści do reklam. Informacje o reklamach są wczytywane oddzielnie od multimediów, np. z tagu reklamy XML VAST lub VMAP. Mogą one obejmować pozycje sygnałów reklamowych względem początku treści, rzeczywiste identyfikatory URI multimediów reklamowych i metadane, np. informację o tym, czy daną reklamę można pominąć.

Gdy używasz 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 reklam i zmieniać swoje działanie w zależności od tego, czy reklama jest odtwarzana.
  • Wewnętrznie odtwarzacz może utrzymywać spójny bufor podczas przejść między reklamami a treściami.

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

Podczas przygotowywania filmów z treściami i tagów reklam do użycia z wstawianiem reklam po stronie klienta reklamy powinny być umieszczane w próbkach synchronizacji (kluczowych klatkach) w filmie z treściami, aby odtwarzacz mógł płynnie wznowić odtwarzanie treści.

Obsługa reklam deklaratywnych

Identyfikator 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 włączyć obsługę elementów multimedialnych, które określają tagi reklam, odtwarzacz musi zawierać utworzony i wstawiony obiekt DefaultMediaSourceFactory skonfigurowany za pomocą obiektów AdsLoader.ProviderAdViewProvider:

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 opakuje źródło treści w tag AdsMediaSource. AdsMediaSource uzyska AdsLoaderAdsLoader.Provider i użyje go do wstawiania reklam zgodnie z tagiem reklamy elementu multimedialnego.

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

Playlisty z reklamami

Podczas odtwarzania playlisty z wieloma elementami multimedialnymi domyślnie wysyłane jest żądanie tagu reklamy, a stan odtwarzania reklamy jest zapisywany 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 przy każdym elemencie multimedialnym z reklamami, który ma odrębny identyfikator multimediów lub adres URI treści, nawet jeśli adresy URI tagów reklam są takie same. Jeśli element multimedialny jest powtarzany, użytkownik zobaczy odpowiednie reklamy tylko raz (stan odtwarzania reklam przechowuje informacje o tym, czy reklamy zostały odtworzone, więc są pomijane po pierwszym wystąpieniu).

Możesz dostosować to działanie, przekazując nieprzejrzysty identyfikator reklamy, z którym jest powiązany stan odtwarzania reklamy w przypadku danego elementu multimedialnego, na podstawie równości obiektów. Oto przykład, w którym stan odtwarzania reklamy jest powiązany tylko z identyfikatorem URI tagu reklamy, a nie z połączeniem identyfikatora multimediów i identyfikatora URI tagu reklamy. W tym celu identyfikator URI tagu reklamy jest przekazywany jako identyfikator reklam. W efekcie reklamy będą wczytywane tylko raz, a użytkownik nie zobaczy reklam przy drugim elemencie, gdy będzie odtwarzać playlistę 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 sterowane przez serwer

ExoPlayer ma HlsInterstitialsAdsLoader, który obsługuje reklamy zdefiniowane na playliście HLS i umożliwia ich automatyczne wstawianie po stronie klienta. Więcej informacji znajdziesz w sekcji dotyczącej HlsInterstitialsAdsLoader na stronie HLS.

Biblioteka ExoPlayer IMA

Biblioteka ExoPlayer IMA udostępnia ImaAdsLoader, co ułatwia zintegrowanie wstawiania reklam po stronie klienta z aplikacją. Zawiera funkcje pakietu IMA SDK po stronie klienta, aby obsługiwać wstawianie reklam VAST/VMAP. Instrukcje korzystania z biblioteki, w tym informacje o obsłudze działania w tle i wznawiania odtwarzania, znajdziesz w pliku README.

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

Wskazówki dotyczące interfejsu

PlayerView domyślnie ukrywa elementy sterujące odtwarzaniem podczas wyświetlania reklam, ale aplikacje mogą przełączać to zachowanie, wywołując setControllerHideDuringAds. Podczas odtwarzania reklamy pakiet IMA SDK będzie wyświetlać dodatkowe widoki nad odtwarzaczem (np. link „więcej informacji” i przycisk pomijania, jeśli ma to zastosowanie).

Pakiet IMA SDK może zgłaszać, czy reklamy są zasłonięte przez widoki dostarczone przez aplikację, które są renderowane na odtwarzaczu. Aplikacje, które muszą nakładać widoki niezbędne do sterowania odtwarzaniem, muszą zarejestrować je w pakiecie IMA SDK, aby można było je pominąć w obliczeniach widoczności. Gdy używasz PlayerView jako AdViewProvider, automatycznie rejestruje on nakładki sterujące. 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 pakiecie IMA SDK.

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 przekazywać za pomocą parametru ImaAdsLoader.Builder.setCompanionAdSlots(slots). Więcej informacji znajdziesz w artykule Dodawanie reklam towarzyszących.

Reklamy samodzielne

Pakiet IMA SDK jest przeznaczony do wstawiania reklam do treści multimedialnych, a nie do odtwarzania samodzielnych reklam. Dlatego biblioteka IMA nie obsługuje odtwarzania samodzielnych reklam. W tym przypadku zalecamy używanie pakietu SDK do reklam mobilnych Google.

Korzystanie z pakietu SDK do reklam firmy zewnętrznej

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

Możesz też skorzystać z obsługi playlist w ExoPlayerze, aby utworzyć sekwencję reklam i klipów z treściami:

Kotlin

// A pre-roll ad.
val preRollAd = MediaItem.fromUri(preRollAdUri)
// The start of the content.
val contentStart =
  MediaItem.Builder()
    .setUri(contentUri)
    .setClippingConfiguration(MediaItem.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(MediaItem.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 MediaItem.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 MediaItem.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 lub DAI) strumień multimediów zawiera zarówno reklamy, jak i treści. Plik manifestu DASH może wskazywać zarówno segmenty treści, jak i segmenty reklam, być może w oddzielnych przedziałach czasu. W przypadku HLS zapoznaj się z dokumentacją Apple na temat umieszczania reklam na playliście.

W przypadku wstawiania reklam po stronie serwera klient może potrzebować dynamicznego rozwiązania adresu URL multimediów, aby uzyskać połączony strumień, może potrzebować wyświetlania nakładek reklam w interfejsie lub może potrzebować zgłaszania zdarzeń do pakietu SDK do reklam lub serwera reklam.

DefaultMediaSourceFactory może delegować wszystkie te zadania do MediaSource po stronie serwera w przypadku identyfikatorów URI korzystających ze 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 ExoPlayer IMA udostępnia ImaServerSideAdInsertionMediaSource, co ułatwia integrację z wstawianymi po stronie serwera strumieniami reklam IMA w aplikacji. Zawiera funkcje pakietu IMA DAI SDK na Androida i w pełni integruje dostarczone metadane reklam z odtwarzaczem. Umożliwia to na przykład korzystanie z metod takich jak Player.isPlayingAd(), nasłuchiwanie przejść między treściami a reklamami oraz umożliwienie odtwarzaczowi obsługi logiki odtwarzania reklam, np. pomijania już wyświetlonych reklam.

Aby używać 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 parametrem 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 moduł wczytywania reklam, gdy nie będzie już używany:

Kotlin

adsLoader.release()

Java

adsLoader.release();

Wskazówki dotyczące interfejsu

W przypadku wstawiania reklam po stronie serwera obowiązują te same zasady dotyczące interfejsu 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 przekazywać za pomocą parametru ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots). Więcej informacji znajdziesz w artykule Dodawanie reklam towarzyszących.

Korzystanie z pakietu SDK do reklam firmy zewnętrznej

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

Rzeczywistą logikę tworzenia struktury reklamy można przekazać do ogólnego ServerSideAdInsertionMediaSource, który opakowuje strumień MediaSource i umożliwia użytkownikowi ustawianie i aktualizowanie AdPlaybackState reprezentującego metadane reklamy.

Strumienie reklam wstawianych po stronie serwera często zawierają zdarzenia czasowe, które informują odtwarzacz o metadanych reklamy. Informacje o formatach metadanych czasowych obsługiwanych przez ExoPlayer znajdziesz w sekcji Obsługiwane formaty. Implementacje pakietu SDK do reklam niestandardowych MediaSource mogą nasłuchiwać zdarzeń metadanych z odpowiednim czasem odtwarzacza za pomocą Player.Listener.onMetadata.