SDK de Engage para recomendaciones de videos

Esta guía contiene instrucciones para que los desarrolladores integren su contenido de video recomendado con el SDK de Engage para propagar experiencias de recomendaciones en las plataformas de Google, como TV, dispositivos móviles y tablets.

La función Recommendation aprovecha el clúster de Recommendation para mostrar películas y programas de TV de varias apps en una sola agrupación de IU. Cada socio desarrollador puede transmitir un máximo de 25 entidades en cada clúster de recomendaciones, y puede haber un máximo de 7 clústeres de recomendaciones por solicitud.

Trabajo previo

Completa las instrucciones de trabajo previo en la guía de introducción.

  1. Ejecuta la publicación en un servicio en primer plano.
  2. Publica datos de recomendaciones una vez al día como máximo, activados por cualquiera de los siguientes:
    • El primer acceso del usuario del día (o)
    • Cuando el usuario comienza a interactuar con la aplicación

Integración

AppEngagePublishClient publica el clúster de Recommendation. Usa el método publishRecommendationClusters para publicar un objeto de recomendaciones.

Asegúrate de inicializar el cliente y verificar la disponibilidad del servicio como se describe en la guía de introducción.

client.publishRecommendationClusters(recommendationRequest)

Cómo insertar o actualizar clústeres de Recommendation

Los clústeres son agrupaciones lógicas de las entidades. En los siguientes ejemplos de código, se explica cómo compilar los clústeres según tus preferencias y cómo crear una solicitud de publicación y cómo insertar o actualizar todos los clústeres.

The RecommendationClusterType determina cómo se mostrará el clúster.

// cluster for popular movies
val recommendationCluster1 = RecommendationCluster
  .Builder()
  .addEntity(movie1)
  .addEntity(movie2)
  .addEntity(movie3)
  .addEntity(movie4)
  .addEntity(tvShow)
  // This cluster is meant to be used as an individual provider row
  .setRecommendationClusterType(TYPE_PROVIDER_ROW)
  .setTitle("Popular Movies")
  .build()

// cluster for live TV programs
val recommendationCluster2 = RecommendationCluster
  .Builder()
  .addEntity(liveTvProgramEntity1)
  .addEntity(liveTvProgramEntity2)
  .addEntity(liveTvProgramEntity3)
  .addEntity(liveTvProgramEntity4)
  .addEntity(liveTvProgramEntity5)
 // This cluster is meant to be used as an individual provider row
  .setRecommendationClusterType(TYPE_PROVIDER_ROW)
  .setTitle("Popular Live TV Programs")
  .build()

// creating a publishing request
val recommendationRequest = PublishRecommendationClustersRequest
  .Builder()
  .setSyncAcrossDevices(true)
  .setAccountProfile(accountProfile)
  .addRecommendationCluster(recommendationCluster1)
  .addRecommendationCluster(recommendationCluster2)
  .build()

Cuando el servicio recibe la solicitud, se realizan las siguientes acciones en una transacción:

  • Se quitan los datos existentes de RecommendationsCluster del socio desarrollador.
  • Los datos de la solicitud se analizan y se almacenan en el RecommendationsCluster actualizado. En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

Sincronización entre dispositivos

La marca SyncAcrossDevices controla si los datos del clúster de recomendaciones de un usuario se comparten con Google TV y están disponibles en sus dispositivos, como TVs, teléfonos y tablets. Para que la recomendación funcione, debe establecerse en true.

La aplicación de contenido multimedia debe proporcionar una configuración clara para habilitar o inhabilitar la sincronización entre dispositivos. Explica los beneficios al usuario, almacena su preferencia una vez y aplícala en la solicitud publishRecommendations según corresponda. Para aprovechar al máximo la función entre dispositivos, verifica que la app obtenga el consentimiento del usuario y habilite SyncAcrossDevices en true.

Borra los datos de Video Discovery

Para borrar manualmente los datos de un usuario del servidor de Google TV antes del período de retención estándar de 60 días, usa el método client.deleteClusters(). Cuando recibe la solicitud, el servicio borra todos los datos de Video Discovery existentes para el perfil de la cuenta o para toda la cuenta.

La enumeración DeleteReason define el motivo de la eliminación de datos. El siguiente código quita las recomendaciones al cerrar la sesión.

// If the user logs out from your media app, you must make the following call
// to remove recommendations data from the current Google TV device, otherwise,
// the recommendations data persists on the current Google TV device until 60
// days later.
client.deleteClusters(
  new DeleteClustersRequest.Builder()
    .setAccountProfile(AccountProfile())
    .setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
    .build()
)

// If the user revokes the consent to share data with Google TV, you must make
// the following call to remove recommendations data from all current Google TV
// devices. Otherwise, the recommendations data persists until 60 days later.
client.deleteClusters(
  new DeleteClustersRequest.Builder()
    .setAccountProfile(AccountProfile())
    .setReason(DeleteReason.DELETE_REASON_LOSS_OF_CONSENT)
    .build()
)

Crea entidades

El SDK definió distintas entidades para representar cada tipo de elemento. Se admiten las siguientes entidades para el clúster de Recommendation:

  1. MediaActionFeedEntity
  2. MovieEntity
  3. TvShowEntity
  4. LiveTvChannelEntity
  5. LiveTvProgramEntity

Proporciona descripciones

Proporciona una breve descripción para cada entidad. Esta descripción se mostrará cuando los usuarios coloquen el cursor sobre la entidad, lo que les proporcionará detalles adicionales.

Texto de llamado a la acción

Proporciona un texto de llamado a la acción opcional para cada entidad. Este texto se mostrará al usuario para fomentar la participación.

Etiquetas

De manera opcional, proporciona una lista de etiquetas para cada entidad. Las etiquetas se pueden usar para la categorización y el filtrado.

URIs de reproducción específicos de la plataforma

Crea URIs de reproducción para cada plataforma compatible: Android TV, Android o iOS. Esto permite que el sistema seleccione el URI adecuado para la reproducción de video en la plataforma respectiva.

En el caso poco frecuente en el que los URIs de reproducción sean idénticos para todas las plataformas, repítelos para cada una.

// Required. Set this when you want recommended 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()

// Optional. Set this when you want recommended entities to show up on
// Google TV Android app
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 recommended 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)

// Provide appropriate rating for the system.
val contentRating = new RatingSystem
  .Builder()
  .setAgencyName("MPAA")
  .setRating("PG-13")
  .build()

Imágenes de pósteres

Las imágenes de pósteres requieren un URI y dimensiones en píxeles (altura y ancho). Segmenta diferentes factores de forma proporcionando varias imágenes de pósteres, pero verifica que todas las imágenes mantengan una relación de aspecto de 16:9 y una altura mínima de 200 píxeles para que la entidad "Recommendations" se muestre correctamente, en especial, dentro de Entertainment Space de Google. Es posible que no se muestren las imágenes con una altura inferior a 200 píxeles.

Image image1 = new Image.Builder()
  .setImageUri(Uri.parse("http://www.example.com/entity_image1.png");)
  .setImageHeightInPixel(300)
  .setImageWidthInPixel(169)
  .build()

Image image2 = new Image.Builder()
  .setImageUri(Uri.parse("http://www.example.com/entity_image2.png");)
  .setImageHeightInPixel(640)
  .setImageWidthInPixel(360)
  .build()

// And other images for different form factors.
val images = Arrays.asList(image1, image2)

Motivo de la recomendación

De manera opcional, proporciona un motivo de la recomendación que Google TV puede usar para explicar por qué sugerir una película o un programa de TV específico al usuario.

//Allows us to construct reason: "Because it is top 10 on your Channel"
val topOnPartner = RecommendationReasonTopOnPartner
  .Builder()
  .setNum(10) //any valid integer value
  .build()

//Allows us to construct reason: "Because it is popular on your Channel"
val popularOnPartner = RecommendationReasonPopularOnPartner
  .Builder()
  .build()

//Allows us to construct reason: "New to your channel, or Just added"
val newOnPartner = RecommendationReasonNewOnPartner
  .Builder()
  .build()

//Allows us to construct reason: "Because you watched Star Wars"
val watchedSimilarTitles = RecommendationReasonWatchedSimilarTitles
  .addSimilarWatchedTitleName("Movie or TV Show Title")
  .addSimilarWatchedTitleName("Movie or TV Show Title")
  .Builder()
  .build()

//Allows us to construct reason: "Recommended for you by ChannelName"
val recommendedForUser = RecommendationReasonRecommendedForUser
  .Builder()
  .build()

val watchAgain = RecommendationReasonWatchAgain
  .Builder()
  .build()

val fromUserWatchList = RecommendationReasonFromUserWatchlist
  .Builder()
  .build()

val userLikedOnPartner = RecommendationReasonUserLikedOnPartner
  .Builder()
  .setTitleName("Movie or TV Show Title")
  .build()

val generic = RecommendationReasonGeneric.Builder().build()

Período de visualización

Si una entidad solo debe estar disponible por un tiempo limitado, establece un tiempo de vencimiento personalizado. Sin un tiempo de vencimiento explícito, las entidades vencerán y se borrarán automáticamente después de 60 días. Por lo tanto, establece un tiempo de vencimiento solo cuando las entidades deban vencer antes. Especifica varios períodos de disponibilidad.

val window1 = DisplayTimeWindow
  .Builder()
  .setStartTimeStampMillis(now()+ 1.days.toMillis())
  .setEndTimeStampMillis(now()+ 30.days.toMillis())

val window2 = DisplayTimeWindow
  .Builder()
  .setEndTimeStampMillis(now()+ 30.days.toMillis())

val availabilityTimeWindows: List<DisplayTimeWindow> = listof(window1,window2)

DataFeedElementId

Si integraste tu catálogo de contenido multimedia o tu feed de acciones multimedia con Google TV, no necesitas crear entidades independientes para películas o programas de TV. En su lugar, puedes crear una MediaActionFeedEntity que incluya el campo obligatorio DataFeedElementId. Este ID debe ser único y coincidir con el ID del feed de acciones multimedia, ya que ayuda a identificar el contenido del feed incorporado y a realizar búsquedas de contenido multimedia.

val id = "dataFeedElementId"

MovieEntity

El siguiente es un ejemplo de cómo crear una MovieEntity con todos los campos obligatorios:

val movieEntity = MovieEntity.Builder()
  .setName("Movie name")
  .setDescription("A sentence describing movie.")
  .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
  .addPosterImages(images)
  // Suppose the duration is 2 hours, it is 72000000 in milliseconds
  .setDurationMills(72000000)
  .setCallToActionText("Watch Now")
  .addTag("Action")
  .build()

Puedes proporcionar datos adicionales, como géneros, clasificaciones de contenido, fecha de lanzamiento, motivo de la recomendación y períodos de disponibilidad, que Google TV puede usar para mejorar las visualizaciones o para fines de filtrado.

val genres = Arrays.asList("Action", "Science fiction");
val rating1 = RatingSystem.Builder().setAgencyName("MPAA").setRating("pg-13").build();
val contentRatings = Arrays.asList(rating1);
//Suppose release date is 11-02-2025
val releaseDate  = 1739233800000L
val movieEntity = MovieEntity.Builder()
  ...
  .addGenres(genres)
  .setReleaseDateEpochMillis(releaseDate)
  .addContentRatings(contentRatings)
  .setRecommendationReason(topOnPartner or watchedSimilarTitles)
  .addAllAvailabilityTimeWindows(availabilityTimeWindows)
  .build()

TvShowEntity

El siguiente es un ejemplo de cómo crear una TvShowEntity con todos los campos obligatorios:

val tvShowEntity = TvShowEntity.Builder()
  .setName("Show title")
  .setDescription("A sentence describing TV Show.")
  .addPlatformSpecificPlaybackUri(platformSpecificPlaybackUris)
  .addPosterImages(images)
  .setCallToActionText("Watch Now")
  .addTag("Drama")
  .build();

De manera opcional, proporciona datos adicionales, como géneros, clasificaciones de contenido, motivo de la recomendación, precio de la oferta, cantidad de temporadas o período de disponibilidad, que Google TV puede usar para mejorar las visualizaciones o para fines de filtrado.

val genres = Arrays.asList("Action", "Science fiction");
val rating1 = RatingSystem.Builder()
  .setAgencyName("MPAA")
  .setRating("pg-13")
  .build();
val price = Price.Builder()
  .setCurrentPrice("$14.99")
  .setStrikethroughPrice("$16.99")
  .build();
val contentRatings = Arrays.asList(rating1);
val seasonCount = 5;
val tvShowEntity = TvShowEntity.Builder()
  ...
  .addGenres(genres)
  .addContentRatings(contentRatings)
  .setRecommendationReason(topOnPartner or watchedSimilarTitles)
  .addAllAvailabilityTimeWindows(availabilityTimeWindows)
  .setSeasonCount(seasonCount)
  .setPrice(price)
  .build()

MediaActionFeedEntity

El siguiente es un ejemplo de cómo crear una MediaActionFeedEntity con todos los campos obligatorios:

val mediaActionFeedEntity = MediaActionFeedEntity.Builder()
  .setDataFeedElementId(id)
  .setCallToActionText("Watch Now")
  .addTag("Action")
  .build()

De manera opcional, proporciona datos adicionales, como descripción, motivo de la recomendación y período de visualización, que Google TV puede usar para mejorar las visualizaciones o para fines de filtrado.

val mediaActionFeedEntity = MediaActionFeedEntity.Builder()
  .setName("Movie name or TV Show name")
  .setDescription("A sentence describing an entity")
  .setRecommendationReason(topOnPartner or watchedSimilarTitles)
  .addPosterImages(images)
  .build()

LiveTvChannelEntity

Representa un canal de TV en vivo. El siguiente es un ejemplo de cómo crear una LiveTvChannelEntity con todos los campos obligatorios:

val liveTvChannelEntity = LiveTvChannelEntity.Builder()
  .setName("Channel Name")
  // ID of the live TV channel
  .setEntityId("https://www.example.com/channel/12345")
  .setDescription("A sentence describing this live TV channel.")
  // channel playback uri must contain at least PlatformType.TYPE_ANDROID_TV
  .addPlatformSpecificPlaybackUri(channelPlaybackUris)
  .addLogoImage(logoImage)
  .setCallToActionText("Watch Now")
  .addTag("News")
  .build()

De manera opcional, proporciona datos adicionales, como clasificaciones de contenido o motivo de la recomendación.

val rating1 = RatingSystem.Builder()
  .setAgencyName("MPAA")
  .setRating("pg-13")
  .build()
val contentRatings = Arrays.asList(rating1)

val liveTvChannelEntity = LiveTvChannelEntity.Builder()
  ...
  .addContentRatings(contentRatings)
  .setRecommendationReason(topOnPartner)
  .build()

LiveTvProgramEntity

Representa una tarjeta de programa de TV en vivo que se transmite o está programada para transmitirse en un canal de TV en vivo. El siguiente es un ejemplo de cómo crear una LiveTvProgramEntity con todos los campos obligatorios:

val liveTvProgramEntity = LiveTvProgramEntity.Builder()
  // First set the channel information
  .setChannelName("Channel Name")
  .setChannelId("https://www.example.com/channel/12345")
  // channel playback uri must contain at least PlatformType.TYPE_ANDROID_TV
  .addPlatformSpecificPlaybackUri(channelPlaybackUris)
  .setChannelLogoImage(channelLogoImage)
  // Then set the program or card specific information.
  .setName("Program Name")
  .setEntityId("https://www.example.com/schedule/123")
  .setDescription("Program Description")
  .addAvailabilityTimeWindow(
      DisplayTimeWindow.Builder()
        .setStartTimestampMillis(1756713600000L)// 2025-09-01T07:30:00+0000
        .setEndTimestampMillis(1756715400000L))// 2025-09-01T08:00:00+0000
  .addPosterImage(programImage)
  .setCallToActionText("Watch Now")
  .addTag("Sports")
  .build()

De manera opcional, proporciona datos adicionales, como clasificaciones de contenido, géneros o motivo de la recomendación.

val rating1 = RatingSystem.Builder()
  .setAgencyName("MPAA")
  .setRating("pg-13")
  .build()
val contentRatings = Arrays.asList(rating1)
val genres = Arrays.asList("Action", "Science fiction")

val liveTvProgramEntity = LiveTvProgramEntity.Builder()
  ...
  .addContentRatings(contentRatings)
  .addGenres(genres)
  .setRecommendationReason(topOnPartner)
  .build()