Integrowanie funkcji Oglądaj dalej na Androidzie TV

book_path: /distribute/other-docs/_book.yaml project_path: /distribute/other-docs/_project.yaml

Z tego przewodnika dowiesz się, jak zintegrować funkcję Oglądaj dalej z aplikacją na Androida TV za pomocą pakietu Engage SDK.

Przygotowanie

Wykonaj instrukcje z sekcji Przygotowania w przewodniku dla początkujących.

Integracja

Tworzenie encji

Pakiet SDK ma zdefiniowane różne elementy reprezentujące każdy typ produktu. Klaster Continuation obsługuje te jednostki:

  1. MovieEntity
  2. TvEpisodeEntity
  3. LiveStreamingVideoEntity
  4. VideoClipEntity

Określ identyfikatory URI i obrazy plakatu dla tych elementów na poszczególnych platformach.

Utwórz też identyfikatory URI odtwarzania dla każdej platformy, np. Android TV, Android lub iOS, jeśli jeszcze tego nie zrobiono. Gdy użytkownik kontynuuje oglądanie na każdej platformie, aplikacja używa docelowego identyfikatora URI odtwarzania, aby odtworzyć treści wideo.

// Required. Set this when you want continue watching entities to show up on
// Google TV
val playbackUriTv = PlatformSpecificUri.Builder()
    .setPlatformType(PlatformType.TYPE_ANDROID_TV)
    .setActionUri(Uri.parse("https://www.example.com/entity_uri_for_tv"))
    .build()

// Required. Set this when you want continue watching entities to show up on
// Google TV Android app, Entertainment Space, Playstore Widget
val playbackUriAndroid = PlatformSpecificUri.Builder()
    .setPlatformType(PlatformType.TYPE_ANDROID_MOBILE)
    .setActionUri(Uri.parse("https://www.example.com/entity_uri_for_android"))
    .build()

// Optional. Set this when you want continue watching entities to show up on
// Google TV iOS app
val playbackUriIos = PlatformSpecificUri.Builder()
    .setPlatformType(PlatformType.TYPE_IOS)
    .setActionUri(Uri.parse("https://www.example.com/entity_uri_for_ios"))
    .build()

val platformSpecificPlaybackUris =
    Arrays.asList(playbackUriTv, playbackUriAndroid, playbackUriIos)

Obrazy plakatu wymagają identyfikatora URI i wymiarów w pikselach (wysokości i szerokości). Kieruj reklamy na różne urządzenia, przesyłając wiele obrazów plakatu, ale upewnij się, że wszystkie obrazy mają współczynnik proporcji 16:9 i minimalną wysokość 200 pikseli, aby prawidłowo wyświetlać element „Oglądaj dalej”, zwłaszcza w Entertainment Space od Google. Obrazy o wysokości mniejszej niż 200 pikseli mogą się nie wyświetlać.

val images = Arrays.asList(
    Image.Builder()
        .setImageUri(Uri.parse("http://www.example.com/entity_image1.png"))
        .setImageHeightInPixel(300)
        .setImageWidthInPixel(169)
        .build(),
    Image.Builder()
        .setImageUri(Uri.parse("http://www.example.com/entity_image2.png"))
        .setImageHeightInPixel(640)
        .setImageWidthInPixel(360)
        .build()
    // Consider adding other images for different form factors
)

MovieEntity

Ten przykład pokazuje, jak utworzyć MovieEntity ze wszystkimi wymaganymi polami:

val movieEntity = MovieEntity.Builder()
   .setWatchNextType(WatchNextType.TYPE_CONTINUE)
   .setName("Movie name")
   .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
   .addPosterImages(images)
   // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
   .setLastEngagementTimeMillis(1701388800000)
   // Suppose the duration is 2 hours, it is 72000000 in milliseconds
   .setDurationMills(72000000)
   // Suppose last playback offset is 1 hour, 36000000 in milliseconds
   .setLastPlayBackPositionTimeMillis(36000000)
   .build()

Podanie szczegółów, takich jak gatunki i oceny treści, umożliwia Google TV prezentowanie Twoich treści w bardziej dynamiczny sposób i łączenie ich z odpowiednimi widzami.

val genres = Arrays.asList("Action", "Science fiction")
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("PG-13").build()
val contentRatings = Arrays.asList(rating1)
val movieEntity = MovieEntity.Builder()
    ...
    .addGenres(genres)
    .addContentRatings(contentRatings)
    .build()

Jednostki pozostają automatycznie dostępne przez 60 dni, chyba że określisz krótszy czas wygaśnięcia. Niestandardowy okres ważności ustawiaj tylko wtedy, gdy chcesz, aby element został usunięty przed upływem domyślnego okresu.

// Set the expiration time to be now plus 30 days in milliseconds
val expirationTime = DisplayTimeWindow.Builder()
    .setEndTimestampMillis(now().toMillis()+2592000000).build()
val movieEntity = MovieEntity.Builder()
    ...
    .addAvailabilityTimeWindow(expirationTime)
    .build()

TvEpisodeEntity

Ten przykład pokazuje, jak utworzyć element TvEpisodeEntity ze wszystkimi wymaganymi polami:

val tvEpisodeEntity = TvEpisodeEntity.Builder()
    .setWatchNextType(WatchNextType.TYPE_CONTINUE)
    .setName("Episode name")
    .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
    .addPosterImages(images)
    // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
    .setLastEngagementTimeMillis(1701388800000)
    .setDurationMills(72000000) // 2 hours in milliseconds
    // 45 minutes and 15 seconds in milliseconds is 2715000
    .setLastPlayBackPositionTimeMillis(2715000)
    .setEpisodeNumber("2")
    .setSeasonNumber("1")
    .setShowTitle("Title of the show")
    .build()

Ciąg znaków numeru odcinka (np. "2") i ciąg znaków numeru sezonu (np. "1") zostaną rozwinięte do odpowiedniej formy przed wyświetleniem na karcie „Kontynuuj oglądanie”. Pamiętaj, że powinny to być ciągi znaków numerycznych. Nie wpisuj „e2”, „episode 2”, „s1” ani „season 1”.

Jeśli dany serial telewizyjny ma tylko jeden sezon, ustaw numer sezonu na 1.

Aby zwiększyć szanse na to, że widzowie znajdą Twoje treści w Google TV, rozważ podanie dodatkowych danych, takich jak gatunki, oceny treści i okresy dostępności, ponieważ te szczegóły mogą ulepszyć wyświetlanie i opcje filtrowania.

val genres = Arrays.asList("Action", "Science fiction")
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("PG-13").build()
val contentRatings = Arrays.asList(rating1)
val tvEpisodeEntity = TvEpisodeEntity.Builder()
    ...
    .addGenres(genres)
    .addContentRatings(contentRatings)
    .setSeasonTitle("Season Title")
    .setShowTitle("Show Title")
    .build()

VideoClipEntity

Oto przykład tworzenia VideoClipEntity ze wszystkimi wymaganymi polami.

VideoClipEntity reprezentuje klip wygenerowany przez użytkownika, np. film w YouTube.

val videoClipEntity = VideoClipEntity.Builder()
    .setPlaybackUri(Uri.parse("https://www.example.com/uri_for_current_platform"))
    .setWatchNextType(WatchNextType.TYPE_CONTINUE)
    .setName("Video clip name")
    .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
    .addPosterImages(images)
    // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
    .setLastEngagementTimeMillis(1701388800000)
    .setDurationMills(600000) //10 minutes in milliseconds
    .setLastPlayBackPositionTimeMillis(300000) //5 minutes in milliseconds
    .addContentRating(contentRating)
    .build()

Możesz opcjonalnie ustawić twórcę, obraz twórcy, czas utworzenia w milisekundach lub okno czasowe dostępności .

LiveStreamingVideoEntity

Oto przykład tworzenia LiveStreamingVideoEntity ze wszystkimi wymaganymi polami.

val liveStreamingVideoEntity = LiveStreamingVideoEntity.Builder()
    .setPlaybackUri(Uri.parse("https://www.example.com/uri_for_current_platform"))
    .setWatchNextType(WatchNextType.TYPE_CONTINUE)
    .setName("Live streaming name")
    .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
    .addPosterImages(images)
    // Timestamp in millis for sample last engagement time 12/1/2023 00:00:00
    .setLastEngagementTimeMillis(1701388800000)
    .setDurationMills(72000000) //2 hours in milliseconds
    .setLastPlayBackPositionTimeMillis(36000000) //1 hour in milliseconds
    .addContentRating(contentRating)
    .build()

Opcjonalnie możesz ustawić czas rozpoczęcia, nadawcę, ikonę nadawcy lub przedział czasu dostępności dla elementu transmisji na żywo.

Szczegółowe informacje o atrybutach i wymaganiach znajdziesz w dokumentacji interfejsu API.

Podaj dane klastra kontynuacji

AppEngagePublishClient odpowiada za publikowanie klastra kontynuacji. Do publikowania obiektu publishContinuationCluste używasz metody ContinuationCluster.

Zainicjuj klienta i sprawdź dostępność usługi zgodnie z opisem w Przewodniku dla początkujących.

client.publishContinuationCluster(
    PublishContinuationClusterRequest
        .Builder()
        .setContinuationCluster(
            ContinuationCluster.Builder()
                .setAccountProfile(accountProfile)
                .addEntity(movieEntity1)
                .addEntity(movieEntity2)
                .addEntity(tvEpisodeEntity1)
                .addEntity(tvEpisodeEntity2)
                .setSyncAcrossDevices(true)
                .build()
        )
        .build()
)

Gdy usługa otrzyma żądanie, w ramach jednej transakcji zostaną wykonane te działania:

  • Istniejące dane ContinuationCluster od dewelopera zostaną usunięte.
  • Dane z żądania są analizowane i zapisywane w zaktualizowanym ContinuationCluster.

W przypadku błędu całe żądanie jest odrzucane, a dotychczasowy stan jest zachowywany.

Interfejsy API publikowania to interfejsy API typu upsert, które zastępują istniejące treści. Jeśli chcesz zaktualizować konkretny element w klastrze kontynuacji, musisz ponownie opublikować wszystkie elementy.

Dane klastra kontynuacji powinny być podawane tylko w przypadku kont osób dorosłych. Publikuj tylko wtedy, gdy profil konta należy do osoby dorosłej.

Synchronizacja na różnych urządzeniach

Flaga SyncAcrossDevices określa, czy dane ContinuationCluster użytkownika są synchronizowane na różnych urządzeniach, takich jak telewizor, telefon, tablet itp. Synchronizacja na różnych urządzeniach jest domyślnie wyłączona.

Wartości:

  • true: dane klastra kontynuacji są udostępniane na wszystkich urządzeniach użytkownika, aby zapewnić płynne oglądanie. Zdecydowanie zalecamy tę opcję, aby zapewnić jak najlepsze wrażenia na różnych urządzeniach.
  • false: dane klastra kontynuacji są ograniczone do bieżącego urządzenia.

Aplikacja multimedialna musi zawierać wyraźne ustawienie umożliwiające włączanie i wyłączanie synchronizacji na różnych urządzeniach. Wyjaśnij użytkownikowi korzyści i zapisz jego preferencje, aby zastosować je w publishContinuationCluster.

// Example to allow cross device syncing.
client.publishContinuationCluster(
    PublishContinuationClusterRequest
        .Builder()
        .setContinuationCluster(
            ContinuationCluster.Builder()
                .setAccountProfile(accountProfile)
                .setSyncAcrossDevices(true)
                .build()
        )
        .build()
)

Aby w pełni korzystać z funkcji dotyczącej różnych urządzeń, sprawdź, czy aplikacja uzyskuje zgodę użytkownika, i włącz SyncAcrossDevices, aby true. Dzięki temu treści mogą być płynnie synchronizowane na różnych urządzeniach, co zwiększa wygodę użytkowników i ich zaangażowanie. Na przykład partner, który wdrożył tę funkcję, odnotował wzrost liczby kliknięć „Oglądaj dalej” o 40% dzięki temu, że jego treści były wyświetlane na wielu urządzeniach.

Usuwanie danych dotyczących reklam wideo Discovery

Aby ręcznie usunąć dane użytkownika z serwera Google TV przed upływem standardowego 60-dniowego okresu przechowywania, użyj metody deleteClusters. Po otrzymaniu prośby usługa usunie wszystkie dotychczasowe dane dotyczące odkrywania filmów w profilu konta lub na całym koncie.

Wyliczenie DeleteReason określa przyczynę usunięcia danych. Poniższy kod usuwa dane „Oglądaj dalej” po wylogowaniu.


// If the user logs out from your media app, you must make the following call
// to remove continue watching data from the current google TV device,
// otherwise, the continue watching data will persist on the current
// google TV device until 60 days later.
client.deleteClusters(
    DeleteClustersRequest.Builder()
        .setAccountProfile(AccountProfile())
        .setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
        .setSyncAcrossDevices(true)
        .build()
)

Testowanie

Użyj aplikacji weryfikacyjnej, aby sprawdzić, czy integracja pakietu Engage SDK działa prawidłowo.

Po wywołaniu interfejsu API publikowania sprawdź w aplikacji weryfikacyjnej, czy dane są prawidłowo publikowane. Klaster kontynuacji powinien być wyświetlany jako osobny wiersz w interfejsie aplikacji.

  • Przetestuj te działania w aplikacji:
    • Zaloguj się.
    • Przełącz się między profilami(jeśli to możliwe).
    • Rozpocznij, a następnie wstrzymaj odtwarzanie filmu lub wróć na stronę główną.
    • Zamknij aplikację podczas odtwarzania filmu.
    • Usuń element z wiersza „Oglądaj dalej” (jeśli jest to obsługiwane).
  • Po każdej czynności sprawdź, czy aplikacja wywołała interfejs publishContinuationClustersAPI i czy dane są prawidłowo wyświetlane w aplikacji weryfikacyjnej.
  • W przypadku prawidłowo wdrożonych podmiotów aplikacja weryfikacyjna wyświetla zielony znacznik wyboru „Wszystko w porządku”.

    Zrzut ekranu z informacją o pomyślnej weryfikacji w aplikacji weryfikacyjnej
    Rysunek 1. Sukces aplikacji weryfikacyjnej
  • Aplikacja weryfikacyjna oznaczy wszystkie problematyczne elementy.

    Zrzut ekranu z błędem aplikacji do weryfikacji
    Rysunek 2. Błąd aplikacji weryfikacyjnej
  • Aby rozwiązać problemy z elementami, użyj pilota do telewizora, aby wybrać i kliknąć element w aplikacji weryfikacyjnej. Konkretne problemy zostaną wyświetlone i wyróżnione na czerwono (patrz przykład poniżej).

    Szczegóły błędu aplikacji do weryfikacji
    Rysunek 3. Szczegóły błędu aplikacji weryfikacyjnej