book_path: /distribute/other-docs/_book.yaml project_path: /distribute/other-docs/_project.yaml
En esta guía, se explica cómo integrar la función Mirar a continuación en tu app para Android TV con el SDK de Engage.
Trabajo previo
Completa las instrucciones de Trabajo previo en la guía de introducción.
Integración
Crea entidades
El SDK definió distintas entidades para representar cada tipo de elemento. El clúster de continuación admite las siguientes entidades:
Especifica los URIs y las imágenes de póster específicos de la plataforma para estas entidades.
Además, crea URIs de reproducción para cada plataforma (como Android TV, Android o iOS) si aún no lo hiciste. Por lo tanto, cuando un usuario sigue mirando contenido en cada plataforma, la app usa un URI de reproducción segmentado para reproducir el contenido de video.
// 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)
Las imágenes de póster requieren un URI y dimensiones en píxeles (alto y ancho). Proporciona varias imágenes de póster para segmentar diferentes factores de forma, 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 "Seguir mirando" 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.
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
En este ejemplo, se muestra cómo crear un objeto MovieEntity con todos los campos obligatorios:
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()
Proporcionar detalles como los géneros y las clasificaciones de contenido le permite a Google TV mostrar tu contenido de formas más dinámicas y conectarlo con los usuarios adecuados.
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()
Las entidades permanecen disponibles automáticamente durante 60 días, a menos que especifiques un tiempo de vencimiento más corto. Solo establece un vencimiento personalizado si necesitas que se quite la entidad antes de este período predeterminado.
// 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
En este ejemplo, se muestra cómo crear un objeto TvEpisodeEntity con todos los campos obligatorios:
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()
La cadena del número de episodio (como "2") y la cadena del número de temporada (como "1") se expandirán a la forma adecuada antes de mostrarse en la tarjeta de continuar mirando. Ten en cuenta que deben ser una cadena numérica. No ingreses "e2", "episodio 2", "s1" ni "temporada 1".
Si un programa de TV en particular tiene una sola temporada, establece el número de temporada como 1.
Para maximizar las posibilidades de que los usuarios encuentren tu contenido en Google TV, considera proporcionar datos adicionales, como géneros, calificaciones de contenido y períodos de disponibilidad, ya que estos detalles pueden mejorar las opciones de visualización y filtrado.
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
Este es un ejemplo de cómo crear un objeto VideoClipEntity con todos los campos obligatorios.
VideoClipEntity representa un clip generado por el usuario, como un video de 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()
De manera opcional, puedes establecer el creador, la imagen del creador, la hora de creación en milisegundos o el período de disponibilidad .
LiveStreamingVideoEntity
Este es un ejemplo de cómo crear un objeto LiveStreamingVideoEntity con todos los campos obligatorios.
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()
De manera opcional, puedes establecer la hora de inicio, el emisor, el ícono del emisor o el período de disponibilidad de la entidad de transmisión en vivo.
Para obtener información detallada sobre los atributos y los requisitos, consulta la referencia de la API.
Proporciona datos del clúster de continuación
AppEngagePublishClient es responsable de publicar el clúster de Continuation.
Usas el método publishContinuationCluste para publicar un objeto ContinuationCluster.
Asegúrate de inicializar el cliente y verificar la disponibilidad del servicio como se describe en la guía de introducción.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.addEntity(movieEntity1)
.addEntity(movieEntity2)
.addEntity(tvEpisodeEntity1)
.addEntity(tvEpisodeEntity2)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
Cuando el servicio recibe la solicitud, se realizan las siguientes acciones en una transacción:
- Se quitan los datos existentes de
ContinuationClusterdel socio desarrollador. - Los datos de la solicitud se analizan y se almacenan en el
ContinuationClusteractualizado.
En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.
Las APIs de publicación son APIs de inserción y actualización. Reemplazan el contenido existente. Si necesitas actualizar una entidad específica en el clúster de continuación, deberás volver a publicar todas las entidades.
Los datos del clúster de continuación solo se deben proporcionar para las cuentas de adultos. Se publica solo cuando el perfil de la cuenta pertenece a un adulto.
Sincronización entre dispositivos
La marca SyncAcrossDevices controla si los datos de ContinuationCluster de un usuario se sincronizan en todos los dispositivos, como TVs, teléfonos, tablets, etcétera. La sincronización en varios dispositivos está inhabilitada de forma predeterminada.
Valores:
true: Los datos de clúster de continuación se comparten en todos los dispositivos del usuario para brindar una experiencia de visualización fluida. Te recomendamos esta opción para obtener la mejor experiencia en todos los dispositivos.false: Los datos del clúster de continuación están restringidos al dispositivo actual.
Obtén el consentimiento
La app de medios debe proporcionar un parámetro de configuración claro para habilitar o inhabilitar la sincronización multidispositivo. Explica los beneficios al usuario y almacena su preferencia una vez para aplicarla en publishContinuationCluster según corresponda.
// Example to allow cross device syncing.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
Para aprovechar al máximo nuestra función multidispositivo, verifica que la app obtenga el consentimiento del usuario y habilita SyncAcrossDevices para true. Esto permite que el contenido se sincronice sin problemas en todos los dispositivos, lo que genera una mejor experiencia del usuario y una mayor participación. Por ejemplo, un socio que implementó esta función observó un aumento del 40% en los clics de "Seguir mirando" porque su contenido se mostró en varios dispositivos.
Borra los datos de la campaña de descubrimiento de video
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 deleteClusters. Cuando reciba la solicitud, el servicio borrará todos los datos existentes de descubrimiento de videos del perfil de la cuenta o de toda la cuenta.
La enumeración DeleteReason define el motivo de la eliminación de datos.
El siguiente código quita los datos de Continuar mirando cuando se cierra la sesión.
// 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()
)
Prueba
Usa la app de verificación para verificar que la integración del SDK de Engage funcione correctamente.
Después de invocar la API de publicación, verifica que la app de verificación publique tus datos correctamente. Tu clúster de continuación debe mostrarse como una fila distinta en la interfaz de la app.
- Prueba estas acciones en tu app:
- Accede.
- Cambia entre perfiles(si corresponde).
- Iniciar y, luego, pausar un video, o volver a la página principal
- Cierra la app durante la reproducción de videos.
- Quitar un elemento de la fila "Seguir mirando" (si es compatible)
- Después de cada acción, confirma que tu app invocó la API de
publishContinuationClustersy que los datos se muestran correctamente en la app de verificación. La app de verificación muestra una marca de verificación verde con el mensaje "Todo bien" para las entidades implementadas correctamente.
Figura 1: Éxito de la app de verificación La app de verificación marcará las entidades problemáticas.
Figura 2: Error de la app de verificación Para solucionar problemas relacionados con entidades que tienen errores, usa el control remoto de la TV para seleccionar y hacer clic en la entidad en la app de verificación. Los problemas específicos se mostrarán y destacarán en rojo para que los revises (consulta el ejemplo a continuación).
Figura 3: Detalles del error de la app de verificación