Videos con el SDK de Engage: Instrucciones de integración técnica de terceros

Google está compilando una plataforma integrada en el dispositivo que organiza las apps de los usuarios por verticales y que permite ofrecer una nueva experiencia envolvente para el descubrimiento y el consumo de contenido personalizado en las apps. Esta experiencia de pantalla completa brinda a los socios desarrolladores la oportunidad de mostrar su mejor contenido enriquecido en un canal dedicado fuera de su app.

Esta guía contiene instrucciones para que los socios desarrolladores integren su contenido de video con el SDK de Engage para propagar esta nueva área de la plataforma y las plataformas de Google existentes.

Información detallada sobre la integración

Terminología

Esta integración incluye los siguientes tres tipos de clústeres: Recommendation, Continuation y Featured.

  • En los clústeres de Recommendation, se muestran sugerencias personalizadas de contenido para ver de un socio desarrollador individual.

    Tus recomendaciones tienen la siguiente estructura:

    • Clúster de Recommendation: Es una vista de la IU que contiene un grupo de recomendaciones del mismo socio desarrollador.

      Figura 1: IU de Entertainment Space que muestra un clúster de Recommendation de un único socio
    • Entidad: Es un objeto que representa un solo elemento en un clúster. Una entidad puede ser una película, un programa de TV, una serie de TV, videos en vivo y mucho más. Consulta la sección para proporcionar los datos de la entidad si quieres obtener una lista de los tipos de entidades compatibles.

      Figura 2: IU de Entertainment Space que muestra una sola Entidad dentro del clúster de Recommendation de un único socio
  • En el clúster de Continuation, se muestran los videos sin terminar y los episodios nuevos y relevantes de varios socios desarrolladores en una sola agrupación de IU. Cada socio desarrollador podrá transmitir un máximo de 10 entidades en el clúster de Continuation. Algunas investigaciones muestran que las recomendaciones personalizadas y el contenido de Continuation personalizado crean una mejor participación del usuario.

    Figura 3: IU de Entertainment Space que muestra un clúster de Continuation con recomendaciones sin terminar de varios socios (solo una recomendación es visible actualmente)
  • El clúster de Featured muestra una selección de entidades de varios socios desarrolladores en una agrupación de IU. Habrá un solo clúster de Featured, que aparecerá cerca de la parte superior de la IU, con una ubicación de prioridad por sobre todos los clústeres de Recommendation. Cada socio desarrollador podrá transmitir hasta 10 entidades en el clúster de Featured.

    Figura 4: IU de Entertainment Space que muestra un clúster de Featured con recomendaciones de varios socios (solo una recomendación es visible actualmente)

Trabajo previo

Nivel de API mínimo: 19

Agrega la biblioteca com.google.android.engage:engage-core a tu app:

dependencies {
    // Make sure you also include that repository in your project's build.gradle file.
    implementation 'com.google.android.engage:engage-core:1.5.2'
}

Para obtener más información, consulta Visibilidad de paquetes en Android 11.

Resumen

El diseño se basa en una implementación de un servicio vinculado.

Los datos que un cliente puede publicar están sujetos a los siguientes límites para diferentes tipos de clústeres:

Tipo de clúster Límites del clúster Límites máximos de entidades en un clúster
Clústeres de Recommendation 5 como máximo 50 como máximo
Clúster de Continuation 1 como máximo 10 como máximo
Clúster de Featured 1 como máximo 10 como máximo

Paso 0: Migración desde la integración del SDK de Media Home existente

Cómo asignar modelos de datos a partir de una integración existente

Si migras desde una integración existente de Media Home, en la siguiente tabla, se describe cómo asignar modelos de datos en los SDK existentes al nuevo SDK de Engage:

Equivalente de integración de MediaHomeVideoContract Equivalente de integración de SDK de Engage
com.google.android.mediahome.video.PreviewChannel com.google.android.engage.common.datamodel.RecommendationCluster
com.google.android.mediahome.video.PreviewChannel.Builder com.google.android.engage.common.datamodel.RecommendationCluster.Builder
com.google.android.mediahome.video.PreviewChannelHelper com.google.android.engage.video.service.AppEngageVideoClient
com.google.android.mediahome.video.PreviewProgram Se divide en clases separadas: EventVideo, LiveStreamingVideo, Movie, TvEpisode, TvSeason, TvShow y VideoClipEntity
com.google.android.mediahome.video.PreviewProgram.Builder Se divide en compiladores en clases separadas: EventVideo, LiveStreamingVideo, Movie, TvEpisode, TvSeason, TvShow y VideoClipEntity
com.google.android.mediahome.video.VideoContract Ya no es necesario
com.google.android.mediahome.video.WatchNextProgram Se divide en atributos en clases separadas: EventVideoEntity, LiveStreamingVideoEntity, MovieEntity, TvEpisodeEntity, TvSeasonEntity, TvShowEntity y VideoClipEntity
com.google.android.mediahome.video.WatchNextProgram.Builder Se divide en atributos en clases separadas: EventVideoEntity, LiveStreamingVideoEntity, MovieEntity, TvEpisodeEntity, TvSeasonEntity, TvShowEntity y VideoClipEntity

Publicación de clústeres en el SDK de Media Home vs. el SDK de Engage

Con el SDK de Media Home, los clústeres y las entidades se publicaban a través de diferentes APIs:

// 1. Fetch existing channels
List<PreviewChannel> channels = PreviewChannelHelper.getAllChannels();

// 2. If there are no channels, publish new channels
long channelId = PreviewChannelHelper.publishChannel(builder.build());

// 3. If there are existing channels, decide whether to update channel contents
PreviewChannelHelper.updatePreviewChannel(channelId, builder.build());

// 4. Delete all programs in the channel
PreviewChannelHelper.deleteAllPreviewProgramsByChannelId(channelId);

// 5. publish new programs in the channel
PreviewChannelHelper.publishPreviewProgram(builder.build());

Con el SDK de Engage, la publicación de clústeres y entidades se combina en una sola llamada a la API. Todas las entidades que pertenecen a un clúster se publican juntas con ese clúster:

Kotlin

RecommendationCluster.Builder()
            .addEntity(MOVIE_ENTITY)
            .addEntity(MOVIE_ENTITY)
            .addEntity(MOVIE_ENTITY)
            .setTitle("Top Picks For You")
            .build()

Java

new RecommendationCluster.Builder()
                        .addEntity(MOVIE_ENTITY)
                        .addEntity(MOVIE_ENTITY)
                        .addEntity(MOVIE_ENTITY)
                        .setTitle("Top Picks For You")
                        .build();

Paso 1: Proporciona los datos de la entidad

El SDK definió distintas entidades para representar cada tipo de elemento. Admitimos las siguientes entidades para la categoría Mirar:

  1. MovieEntity
  2. TvShowEntity
  3. TvSeasonEntity
  4. TvEpisodeEntity
  5. LiveStreamingVideoEntity
  6. VideoClipEntity

En el siguiente gráfico, se describen los atributos y los requisitos para cada tipo.

MovieEntity

Atributo Requisito Notas
Nombre Obligatorio
Imágenes de pósteres Obligatorio Se requiere al menos una imagen, que debe tener una determinada relación de aspecto (se prefiere el formato horizontal, pero te recomendamos que pases las imágenes en formatos vertical y horizontal para diferentes situaciones).

Consulta la sección Especificaciones de imagen para obtener más información.

URI de reproducción Obligatorio

Es el vínculo directo a la app del proveedor para comenzar a reproducir la película.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes.

URI de la página de información Opcional

Es el vínculo directo a la app del proveedor para mostrar detalles sobre la película.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes

Fecha de lanzamiento Obligatorio Debe expresarse en milisegundos de época.
Disponibilidad Obligatorio

AVAILABLE: El contenido está disponible para el usuario sin necesidad de que se realice ninguna otra acción.

FREE_WITH_SUBSCRIPTION: El contenido está disponible una vez que el usuario compra una suscripción.

PAID_CONTENT: El contenido requiere la compra o el alquiler por parte del usuario.

PURCHASED: El usuario compró o alquiló el contenido.

Precio de la oferta Opcional Texto libre
Duración Obligatorio Debe expresarse en milisegundos.
Género Obligatorio Texto libre
Clasificación del contenido Obligatorio Texto libre, sigue el estándar de la industria (ejemplo).
Tipo de Ver a continuación Condicionalmente obligatorio

Se debe proporcionar cuando el elemento está en el clúster de Continuation y debe ser uno de los siguientes cuatro tipos:

CONTINUE: El usuario ya miró más de 1 minuto de este contenido.

NEW: El usuario miró todos los episodios disponibles de algún contenido basado en episodios, pero uno nuevo ya está disponible, y hay exactamente uno sin mirar Esto funciona para programas de TV, partidos de fútbol grabados de una serie, entre otros.

NEXT: El usuario miró uno o más episodios completos de algún contenido basado en episodios, pero queda un episodio restante o más por ver. El último episodio no es "NUEVO" (NEW) y se publicó antes de que el usuario comenzara a mirar el contenido basado en episodios.

WATCHLIST: El usuario eligió agregar de manera explícita una película, un evento o una serie a una lista para ver luego de seleccionar manualmente lo que quiere ver a continuación.

Tiempo de la participación más reciente Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation. Debe expresarse en milisegundos de época.
Hora de la última posición de reproducción Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation y el tipo WatchNextType es CONTINUE. Debe expresarse en milisegundos de época.

TvShowEntity

Atributo Requisito Notas
Nombre Obligatorio
Imágenes de pósteres Obligatorio Se requiere al menos una imagen, que debe tener una determinada relación de aspecto (se prefiere el formato horizontal, pero te recomendamos que pases las imágenes en formatos vertical y horizontal para diferentes situaciones).

Consulta la sección Especificaciones de imagen para obtener más información.

URI de la página de información Obligatorio

Es el vínculo directo a la app del proveedor para mostrar los detalles del programa de TV.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes.

URI de reproducción Opcional

Es el vínculo directo a la app del proveedor para comenzar a reproducir el programa de TV.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes.

Fecha de emisión del primer episodio Obligatorio Debe expresarse en milisegundos de época.
Fecha de emisión del episodio más reciente Opcional Debe expresarse en milisegundos de época.
Disponibilidad Obligatorio

AVAILABLE: El contenido está disponible para el usuario sin necesidad de que se realice ninguna otra acción.

FREE_WITH_SUBSCRIPTION: El contenido está disponible una vez que el usuario compra una suscripción.

PAID_CONTENT: El contenido requiere la compra o el alquiler por parte del usuario.

PURCHASED: El usuario compró o alquiló el contenido.

Precio de la oferta Opcional Texto libre
Cantidad de temporadas Obligatorio Número entero positivo
Género Obligatorio Texto libre
Clasificación del contenido Obligatorio Texto libre, sigue el estándar de la industria (ejemplo).
Tipo de Ver a continuación Condicionalmente obligatorio

Se debe proporcionar cuando el elemento está en el clúster de Continuation y debe ser uno de los siguientes cuatro tipos:

CONTINUE: El usuario ya miró más de 1 minuto de este contenido.

NEW: El usuario miró todos los episodios disponibles de algún contenido basado en episodios, pero uno nuevo ya está disponible, y hay exactamente uno sin mirar Esto funciona para programas de TV, partidos de fútbol grabados de una serie, entre otros.

NEXT: El usuario miró uno o más episodios completos de algún contenido basado en episodios, pero queda un episodio restante o más por ver. El último episodio no es "NUEVO" (NEW) y se publicó antes de que el usuario comenzara a mirar el contenido basado en episodios.

WATCHLIST: El usuario eligió agregar de manera explícita una película, un evento o una serie a una lista para ver luego de seleccionar manualmente lo que quiere ver a continuación.

Tiempo de la participación más reciente Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation. Debe expresarse en milisegundos de época.
Hora de la última posición de reproducción Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation y el tipo WatchNextType es CONTINUE. Debe expresarse en milisegundos de época.

TvSeasonEntity

Atributo Requisito Notas
Nombre Obligatorio
Imágenes de pósteres Obligatorio Se requiere al menos una imagen, que debe tener una determinada relación de aspecto (se prefiere el formato horizontal, pero te recomendamos que pases las imágenes en formatos vertical y horizontal para diferentes situaciones).

Consulta la sección Especificaciones de imagen para obtener más información.

URI de la página de información Obligatorio

Es el vínculo directo a la app del proveedor para mostrar los detalles de la temporada del programa de TV.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes.

URI de reproducción Opcional

Es el vínculo directo a la app del proveedor para comenzar a reproducir la temporada del programa de TV.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes.

Cómo mostrar el número de temporada

Opcional

Disponible en la versión 1.3.1

Cadena
Fecha de emisión del primer episodio Obligatorio Debe expresarse en milisegundos de época.
Fecha de emisión del episodio más reciente Opcional Debe expresarse en milisegundos de época.
Disponibilidad Obligatorio

AVAILABLE: El contenido está disponible para el usuario sin necesidad de que se realice ninguna otra acción.

FREE_WITH_SUBSCRIPTION: El contenido está disponible una vez que el usuario compra una suscripción.

PAID_CONTENT: El contenido requiere la compra o el alquiler por parte del usuario.

PURCHASED: El usuario compró o alquiló el contenido.

Precio de la oferta Opcional Texto libre
Cantidad de episodios Obligatorio Número entero positivo
Género Obligatorio Texto libre
Clasificación del contenido Obligatorio Texto libre, sigue el estándar de la industria. (ejemplo).
Tipo de Ver a continuación Condicionalmente obligatorio

Se debe proporcionar cuando el elemento está en el clúster de Continuation y debe ser uno de los siguientes cuatro tipos:

CONTINUE: El usuario ya miró más de 1 minuto de este contenido.

NEW: El usuario miró todos los episodios disponibles de algún contenido basado en episodios, pero uno nuevo ya está disponible, y hay exactamente uno sin mirar Esto funciona para programas de TV, partidos de fútbol grabados de una serie, entre otros.

NEXT: El usuario miró uno o más episodios completos de algún contenido basado en episodios, pero queda un episodio restante o más por ver. El último episodio no es "NUEVO" (NEW) y se publicó antes de que el usuario comenzara a mirar el contenido basado en episodios.

WATCHLIST: El usuario eligió agregar de manera explícita una película, un evento o una serie a una lista para ver luego de seleccionar manualmente lo que quiere ver a continuación.

Tiempo de la participación más reciente Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation. Debe expresarse en milisegundos de época.
Hora de la última posición de reproducción Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation y el tipo WatchNextType es CONTINUE. Debe expresarse en milisegundos de época.

TvEpisodeEntity

Atributo Requisito Notas
Nombre Obligatorio
Imágenes de pósteres Obligatorio Se requiere al menos una imagen, que debe tener una determinada relación de aspecto (se prefiere el formato horizontal, pero te recomendamos que pases las imágenes en formatos vertical y horizontal para diferentes situaciones).

Consulta la sección Especificaciones de imagen para obtener más información.

URI de reproducción Obligatorio

Es el vínculo directo a la app del proveedor para comenzar a reproducir el episodio.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes.

URI de la página de información Opcional

Es el vínculo directo a la app del proveedor para mostrar detalles sobre el episodio del programa de TV.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes.

Cómo mostrar el número de episodio

Opcional

Disponible en la versión 1.3.1

Cadena
Fecha de emisión Obligatorio Debe expresarse en milisegundos de época.
Disponibilidad Obligatorio

AVAILABLE: El contenido está disponible para el usuario sin necesidad de que se realice ninguna otra acción.

FREE_WITH_SUBSCRIPTION: El contenido está disponible una vez que el usuario compra una suscripción.

PAID_CONTENT: El contenido requiere la compra o el alquiler por parte del usuario.

PURCHASED: El usuario compró o alquiló el contenido.

Precio de la oferta Opcional Texto libre
Duración Obligatorio Debe ser un valor positivo, expresado en milisegundos.
Género Obligatorio Texto libre
Clasificación del contenido Obligatorio Texto libre, sigue el estándar de la industria (ejemplo).
Tipo de Ver a continuación Condicionalmente obligatorio

Se debe proporcionar cuando el elemento está en el clúster de Continuation y debe ser uno de los siguientes cuatro tipos:

CONTINUE: El usuario ya miró más de 1 minuto de este contenido.

NEW: El usuario miró todos los episodios disponibles de algún contenido basado en episodios, pero uno nuevo ya está disponible, y hay exactamente uno sin mirar Esto funciona para programas de TV, partidos de fútbol grabados de una serie, entre otros.

NEXT: El usuario miró uno o más episodios completos de algún contenido basado en episodios, pero queda un episodio restante o más por ver. El último episodio no es "NUEVO" (NEW) y se publicó antes de que el usuario comenzara a mirar el contenido basado en episodios.

WATCHLIST: El usuario eligió agregar de manera explícita una película, un evento o una serie a una lista para ver luego de seleccionar manualmente lo que quiere ver a continuación.

Tiempo de la participación más reciente Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation. Debe expresarse en milisegundos de época.
Hora de la última posición de reproducción Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation y el tipo WatchNextType es CONTINUE. Debe expresarse en milisegundos de época.

LiveStreamingVideoEntity

Atributo Requisito Notas
Nombre Obligatorio
Imágenes de pósteres Obligatorio Se requiere al menos una imagen, que debe tener una determinada relación de aspecto (se prefiere el formato horizontal, pero te recomendamos que pases las imágenes en formatos vertical y horizontal para diferentes situaciones).

Consulta la sección Especificaciones de imagen para obtener más información.

URI de reproducción Obligatorio

Es el vínculo directo a la app del proveedor para comenzar a reproducir el video.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes.

Emisora Obligatorio Texto libre
Hora de inicio Opcional Debe expresarse en milisegundos de época.
Hora de finalización Opcional Debe expresarse en milisegundos de época.
Cantidad de vistas Opcional Texto libre, debe localizarse.
Tipo de Ver a continuación Condicionalmente obligatorio

Se debe proporcionar cuando el elemento está en el clúster de Continuation y debe ser uno de los siguientes cuatro tipos:

CONTINUE: El usuario ya miró más de 1 minuto de este contenido.

NEW: El usuario miró todos los episodios disponibles de algún contenido basado en episodios, pero uno nuevo ya está disponible, y hay exactamente uno sin mirar Esto funciona para programas de TV, partidos de fútbol grabados de una serie, entre otros.

NEXT: El usuario miró uno o más episodios completos de algún contenido basado en episodios, pero queda un episodio restante o más por ver. El último episodio no es "NUEVO" (NEW) y se publicó antes de que el usuario comenzara a mirar el contenido basado en episodios.

WATCHLIST: El usuario eligió agregar de manera explícita una película, un evento o una serie a una lista para ver luego de seleccionar manualmente lo que quiere ver a continuación.

Tiempo de la participación más reciente Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation. Debe expresarse en milisegundos de época.
Hora de la última posición de reproducción Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation y el tipo WatchNextType es CONTINUE. Debe expresarse en milisegundos de época.

VideoClipEntity

El objeto VideoClipEntity representa una entidad de video que proviene de redes sociales, como TikTok o YouTube.

Atributo Requisito Notas
Nombre Obligatorio
Imágenes de pósteres Obligatorio Se requiere al menos una imagen, que debe tener una determinada relación de aspecto (se prefiere el formato horizontal, pero te recomendamos que pases las imágenes en formatos vertical y horizontal para diferentes situaciones).

Consulta la sección Especificaciones de imagen para obtener más información.

URI de reproducción Obligatorio

Es el vínculo directo a la app del proveedor para comenzar a reproducir el video.

Nota: Puedes usar vínculos directos para la atribución. Consulta estas Preguntas frecuentes.

Hora de creación Obligatorio Debe expresarse en milisegundos de época.
Duración Obligatorio Debe ser un valor positivo, expresado en milisegundos.
Creador Obligatorio Texto libre
Imagen del creador Opcional Imagen del avatar del creador
Cantidad de vistas Opcional Texto libre, debe localizarse.
Tipo de Ver a continuación Condicionalmente obligatorio

Se debe proporcionar cuando el elemento está en el clúster de Continuation y debe ser uno de los siguientes cuatro tipos:

CONTINUE: El usuario ya miró más de 1 minuto de este contenido.

NEW: El usuario miró todos los episodios disponibles de algún contenido basado en episodios, pero uno nuevo ya está disponible, y hay exactamente uno sin mirar Esto funciona para programas de TV, partidos de fútbol grabados de una serie, entre otros.

NEXT: El usuario miró uno o más episodios completos de algún contenido basado en episodios, pero queda un episodio restante o más por ver. El último episodio no es "NUEVO" (NEW) y se publicó antes de que el usuario comenzara a mirar el contenido basado en episodios.

WATCHLIST: El usuario eligió agregar de manera explícita una película, un evento o una serie a una lista para ver luego de seleccionar manualmente lo que quiere ver a continuación.

Tiempo de la participación más reciente Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation. Debe expresarse en milisegundos de época.
Hora de la última posición de reproducción Condicionalmente obligatorio Se debe proporcionar cuando el elemento está en el clúster de Continuation y el tipo WatchNextType es CONTINUE. Debe expresarse en milisegundos de época.

Especificaciones de imagen

En la siguiente sección, se indican las especificaciones obligatorias para los recursos de imagen:

Formatos de archivo

PNG, JPG, GIF estático, WebP

Tamaño máximo de los archivos

5120 KB

Recomendaciones adicionales

  • Área segura para la imagen: Coloca el contenido importante en el 80% central de la imagen.

Ejemplo

Kotlin

var movie = MovieEntity.Builder()
    .setName("Avengers")
    .addPosterImage(Image.Builder()
                          .setImageUri(Uri.parse("http://www.x.com/image.png"))
                          .setImageHeightInPixel(960)
                          .setImageWidthInPixel(408)
                          .build())
    .setPlayBackUri(Uri.parse("http://tv.com/playback/1"))
    .setReleaseDateEpochMillis(1633032895L)
    .setAvailability(ContentAvailability.AVAILABILITY_AVAILABLE)
    .setDurationMillis(12345678L)
    .addGenre("action")
    .addContentRating("R")
    .setWatchNextType(WatchNextType.TYPE_NEW)
    .setLastEngagementTimeMillis(1664568895L)
    .build()

Java

MovieEntity movie = new MovieEntity.Builder()
                  .setName("Avengers")
                  .addPosterImage(
                      new Image.Builder()
                          .setImageUri(Uri.parse("http://www.x.com/image.png"))
                          .setImageHeightInPixel(960)
                          .setImageWidthInPixel(408)
                          .build())
                  .setPlayBackUri(Uri.parse("http://tv.com/playback/1"))
                  .setReleaseDateEpochMillis(1633032895L)
                  .setAvailability(ContentAvailability.AVAILABILITY_AVAILABLE)
                  .setDurationMillis(12345678L)
                  .addGenre("action")
                  .addContentRating("R")
                  .setWatchNextType(WatchNextType.TYPE_NEW)
                  .setLastEngagementTimeMillis(1664568895L)
                  .build();

Paso 2: Proporciona los datos de los clústeres

Se recomienda que el trabajo de publicación de contenido se ejecute en segundo plano (por ejemplo, con WorkManager) y se programe con frecuencia o en eventos (por ejemplo, cada vez que el usuario abre la app o cuando acaba de agregar algo a su carrito).

AppEngagePublishClient es responsable de publicar los clústeres. Las siguientes APIs están disponibles en el cliente:

  • isServiceAvailable
  • publishRecommendationClusters
  • publishFeaturedCluster
  • publishContinuationCluster
  • publishUserAccountManagementRequest
  • updatePublishStatus
  • deleteRecommendationsClusters
  • deleteFeaturedCluster
  • deleteContinuationCluster
  • deleteUserManagementCluster
  • deleteClusters

isServiceAvailable

Esta API se usa para verificar si el servicio está disponible para la integración y si el contenido se puede presentar en el dispositivo.

Kotlin

client.isServiceAvailable.addOnCompleteListener { task ->
    if (task.isSuccessful) {
        // Handle IPC call success
        if(task.result) {
          // Service is available on the device, proceed with content publish
          // calls.
        } else {
          // Service is not available, no further action is needed.
        }
    } else {
      // The IPC call itself fails, proceed with error handling logic here,
      // such as retry.
    }
}

Java

client.isServiceAvailable().addOnCompleteListener(task - > {
    if (task.isSuccessful()) {
        // Handle success
        if(task.getResult()) {
          // Service is available on the device, proceed with content publish
          // calls.
        } else {
          // Service is not available, no further action is needed.
        }
    } else {
      // The IPC call itself fails, proceed with error handling logic here,
      // such as retry.
    }
});

publishRecommendationClusters

Esta API se usa para publicar una lista de objetos RecommendationCluster.

Kotlin

client.publishRecommendationClusters(
      PublishRecommendationClustersRequest.Builder()
        .addRecommendationCluster(
          RecommendationCluster.Builder()
            .addEntity(entity1)
            .addEntity(entity2)
            .setTitle("Top Picks For You")
            .build()
        )
        .build()
    )

Java

client.publishRecommendationClusters(
            new PublishRecommendationClustersRequest.Builder()
                .addRecommendationCluster(
                    new RecommendationCluster.Builder()
                        .addEntity(entity1)
                        .addEntity(entity2)
                        .setTitle("Top Picks For You")
                        .build())
                .build());

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

  • Se quitan los datos existentes de RecommendationCluster del socio desarrollador.
  • Los datos de la solicitud se analizan y se almacenan en el clúster de Recommendation actualizado.

En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

publishFeaturedCluster

Esta API se usa para publicar una lista de objetos FeaturedCluster.

Kotlin

client.publishFeaturedCluster(
    PublishFeaturedClusterRequest.Builder()
      .setFeaturedCluster(
        FeaturedCluster.Builder()
          .addEntity(entity1)
          .addEntity(entity2)
          .build())
      .build())

Java

client.publishFeaturedCluster(
            new PublishFeaturedClustersRequest.Builder()
                .addFeaturedCluster(
                    new FeaturedCluster.Builder()
                        .addEntity(entity1)
                        .addEntity(entity2)
                        .build())
                .build());

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

  • Se quitan los datos existentes de FeaturedCluster del socio desarrollador.
  • Los datos de la solicitud se analizan y se almacenan en el clúster de Featured actualizado.

En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

publishContinuationCluster

Esta API se usa para publicar un objeto ContinuationCluster.

Kotlin

client.publishContinuationCluster(
    PublishContinuationClusterRequest.Builder()
      .setContinuationCluster(
        ContinuationCluster.Builder()
          .addEntity(entity1)
          .addEntity(entity2)
          .build())
      .build())

Java

client.publishContinuationCluster(
            new PublishContinuationClusterRequest.Builder()
                .setContinuationCluster(
                    new ContinuationCluster.Builder()
                        .addEntity(entity1)
                        .addEntity(entity2)
                        .build())
                .build());

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

  • Se quitan los datos existentes de ContinuationCluster del socio desarrollador.
  • Los datos de la solicitud se analizan y se almacenan en el clúster de Continuation actualizado.

En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

publishUserAccountManagementRequest

Esta API se usa para publicar una tarjeta de acceso. La acción de acceso dirige a los usuarios a la página de acceso de la app para que esta pueda publicar contenido (o proporcionar contenido más personalizado).

Los siguientes metadatos forman parte de la tarjeta de acceso:

Atributo Requisito Descripción
URI de acción Obligatorio Vínculo directo a la acción (p. ej., navega a la página de acceso de la app)
Imagen Opcional: En caso de que no se proporcione el título, debes brindar uno.

Imagen que se muestra en la tarjeta

Imágenes con una relación de aspecto de 16 × 9, con una resolución de 1264 × 712

Título Opcional: En caso de que no se proporcione la imagen, debes brindar una. Título en la tarjeta
Texto de acción Opcional Texto que se muestra en la CTA (p. ej., Acceder)
Subtítulo Opcional Subtítulo opcional en la tarjeta

Kotlin

var SIGN_IN_CARD_ENTITY =
      SignInCardEntity.Builder()
          .addPosterImage(
              Image.Builder()
                  .setImageUri(Uri.parse("http://www.x.com/image.png"))
                  .setImageHeightInPixel(500)
                  .setImageWidthInPixel(500)
                  .build())
          .setActionText("Sign In")
          .setActionUri(Uri.parse("http://xx.com/signin"))
          .build()

client.publishUserAccountManagementRequest(
            PublishUserAccountManagementRequest.Builder()
                .setSignInCardEntity(SIGN_IN_CARD_ENTITY)
                .build());

Java

SignInCardEntity SIGN_IN_CARD_ENTITY =
      new SignInCardEntity.Builder()
          .addPosterImage(
              new Image.Builder()
                  .setImageUri(Uri.parse("http://www.x.com/image.png"))
                  .setImageHeightInPixel(500)
                  .setImageWidthInPixel(500)
                  .build())
          .setActionText("Sign In")
          .setActionUri(Uri.parse("http://xx.com/signin"))
          .build();

client.publishUserAccountManagementRequest(
            new PublishUserAccountManagementRequest.Builder()
                .setSignInCardEntity(SIGN_IN_CARD_ENTITY)
                .build());

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

  • Se quitan los datos existentes de UserAccountManagementCluster del socio desarrollador.
  • Los datos de la solicitud se analizan y se almacenan en el clúster de UserAccountManagementCluster actualizado.

En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

updatePublishStatus

Si, por algún motivo empresarial interno, no se publica ninguno de los clústeres, te recomendamos que actualices el estado de publicación a través de la API de updatePublishStatus. A continuación, explicamos por qué es importante:

  • Proporcionar el estado en todas las situaciones, incluso cuando el contenido está publicado (STATUS == PUBLISHED), es fundamental para propagar los paneles que usan este estado explícito para transmitir el estado y otras métricas de tu integración.
  • Si no se publica contenido pero el estado de integración no está roto (STATUS == NOT_PUBLISHED), Google puede evitar activar alertas en los paneles de estado de la app. Confirma que el contenido no se publicó debido a una situación prevista desde el punto de vista del proveedor.
  • Ayuda a los desarrolladores a proporcionar estadísticas sobre cuándo se publican los datos y cuándo no.
  • Google puede usar los códigos de estado para sugerir al usuario que realice determinadas acciones en la app de modo que pueda ver el contenido de la app o superarlo.

La lista de códigos de estado de publicación aptos es la siguiente:

// Content is published
AppEngagePublishStatusCode.PUBLISHED,

// Content is not published as user is not signed in
AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SIGN_IN,

// Content is not published as user is not subscribed
AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SUBSCRIPTION,

// Content is not published as user location is ineligible
AppEngagePublishStatusCode.NOT_PUBLISHED_INELIGIBLE_LOCATION,

// Content is not published as there is no eligible content
AppEngagePublishStatusCode.NOT_PUBLISHED_NO_ELIGIBLE_CONTENT,

// Content is not published as the feature is disabled by the client
// Available in v1.3.1
AppEngagePublishStatusCode.NOT_PUBLISHED_FEATURE_DISABLED_BY_CLIENT,

// Content is not published as the feature due to a client error
// Available in v1.3.1
AppEngagePublishStatusCode.NOT_PUBLISHED_CLIENT_ERROR,

// Content is not published as the feature due to a service error
// Available in v1.3.1
AppEngagePublishStatusCode.NOT_PUBLISHED_SERVICE_ERROR,

// Content is not published due to some other reason
// Reach out to engage-developers@ before using this enum.
AppEngagePublishStatusCode.NOT_PUBLISHED_OTHER

Si el contenido no se publica debido a que un usuario no accedió, te recomendamos que publiques la tarjeta de acceso. Si, por algún motivo, los proveedores no pueden publicar la tarjeta de acceso, recomendamos que llames a la API de updatePublishStatus con el código de estado NOT_PUBLISHED_REQUIRES_SIGN_IN.

Kotlin

client.updatePublishStatus(
   PublishStatusRequest.Builder()
     .setStatusCode(AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SIGN_IN)
     .build())

Java

client.updatePublishStatus(
    new PublishStatusRequest.Builder()
        .setStatusCode(AppEngagePublishStatusCode.NOT_PUBLISHED_REQUIRES_SIGN_IN)
        .build());

deleteRecommendationClusters

Esta API se usa para borrar el contenido de los clústeres de Recommendation.

Kotlin

client.deleteRecommendationClusters()

Java

client.deleteRecommendationClusters();

Cuando el servicio recibe la solicitud, quita los datos existentes de los clústeres de Recommendation. En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

deleteFeaturedCluster

Esta API se usa para borrar el contenido del clúster de Featured.

Kotlin

client.deleteFeaturedCluster()

Java

client.deleteFeaturedCluster();

Cuando el servicio recibe la solicitud, quita los datos existentes del clúster de Featured. En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

deleteContinuationCluster

Esta API se usa para borrar el contenido del clúster de Continuation.

Kotlin

client.deleteContinuationCluster()

Java

client.deleteContinuationCluster();

Cuando el servicio recibe la solicitud, quita los datos existentes del clúster de Continuation. En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

deleteUserManagementCluster

Esta API se usa para borrar el contenido del clúster de UserAccountManagement.

Kotlin

client.deleteUserManagementCluster()

Java

client.deleteUserManagementCluster();

Cuando el servicio recibe la solicitud, quita los datos existentes del clúster de UserAccountManagement. En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

deleteClusters

Esta API se usa para borrar el contenido de un tipo de clúster determinado.

Kotlin

client.deleteClusters(
    DeleteClustersRequest.Builder()
      .addClusterType(ClusterType.TYPE_CONTINUATION)
      .addClusterType(ClusterType.TYPE_FEATURED)
      .addClusterType(ClusterType.TYPE_RECOMMENDATION)
      .build())

Java

client.deleteClusters(
            new DeleteClustersRequest.Builder()
                .addClusterType(ClusterType.TYPE_CONTINUATION)
                .addClusterType(ClusterType.TYPE_FEATURED)
                .addClusterType(ClusterType.TYPE_RECOMMENDATION)
                .build());

Cuando el servicio recibe la solicitud, quita los datos existentes de todos los clústeres que coincidan con los tipos de clúster especificados. Los clientes pueden optar por pasar uno o varios tipos de clústeres. En caso de error, se rechaza la solicitud completa y se mantiene el estado existente.

Manejo de errores

Te recomendamos que escuches el resultado de la tarea de las APIs de publicación, de manera que se pueda realizar una acción de seguimiento para recuperar y volver a enviar una tarea con éxito.

Kotlin

client.publishRecommendationClusters(
        PublishRecommendationClustersRequest.Builder()
          .addRecommendationCluster(..)
          .build())
      .addOnCompleteListener { task ->
        if (task.isSuccessful) {
          // do something
        } else {
          val exception = task.exception
          if (exception is AppEngageException) {
            @AppEngageErrorCode val errorCode = exception.errorCode
            if (errorCode == AppEngageErrorCode.SERVICE_NOT_FOUND) {
              // do something
            }
          }
        }
      }

Java

client.publishRecommendationClusters(
              new PublishRecommendationClustersRequest.Builder()
                  .addRecommendationCluster(...)
                  .build())
          .addOnCompleteListener(
              task -> {
                if (task.isSuccessful()) {
                  // do something
                } else {
                  Exception exception = task.getException();
                  if (exception instanceof AppEngageException) {
                    @AppEngageErrorCode
                    int errorCode = ((AppEngageException) exception).getErrorCode();
                    if (errorCode == AppEngageErrorCode.SERVICE_NOT_FOUND) {
                      // do something
                    }
                  }
                }
              });

El error se muestra como una AppEngageException con la causa incluida como un código de error.

Código de error Nombre del error Nota
1 SERVICE_NOT_FOUND El servicio no está disponible en el dispositivo determinado.
2 SERVICE_NOT_AVAILABLE El servicio está disponible en el dispositivo determinado, pero no en el momento de la llamada (por ejemplo, está inhabilitado explícitamente).
3 SERVICE_CALL_EXECUTION_FAILURE No se pudo ejecutar la tarea debido a problemas con los subprocesos. En este caso, se puede volver a intentar.
4 SERVICE_CALL_PERMISSION_DENIED El llamador no tiene permiso para realizar la llamada de servicio.
5 SERVICE_CALL_INVALID_ARGUMENT La solicitud contiene datos no válidos (por ejemplo, una cantidad de clústeres mayor que la permitida).
6 SERVICE_CALL_INTERNAL Hay un error en el servicio.
7 SERVICE_CALL_RESOURCE_EXHAUSTED La llamada de servicio se realiza con demasiada frecuencia.

Paso 3: Controla los intents de transmisión

Además de realizar llamadas a las APIs de publicación de contenido a través de un trabajo, también se requiere configurar un BroadcastReceiver para recibir la solicitud de publicación de contenido.

El objetivo de los intents de transmisión es principalmente reactivar apps y forzar la sincronización de datos. Los intents de transmisión no están diseñados para enviarse con mucha frecuencia. Solo se activan cuando el servicio de Engage determina que el contenido puede estar inactivo (por ejemplo, si es de hace una semana). De esa manera, será más probable que el usuario tenga una experiencia de contenido actualizada, incluso si la aplicación no se ejecutó durante un período prolongado.

El BroadcastReceiver debe configurarse de las siguientes dos maneras:

  • Registra de forma dinámica una instancia de la clase BroadcastReceiver con Context.registerReceiver(). Esto permite la comunicación desde aplicaciones que aún están activas en la memoria.

Kotlin

class AppEngageBroadcastReceiver : BroadcastReceiver(){
  // Trigger recommendation cluster publish when PUBLISH_RECOMMENDATION broadcast
  // is received
  // Trigger featured cluster publish when PUBLISH_FEATURED broadcast is received
  // Trigger continuation cluster publish when PUBLISH_CONTINUATION broadcast is
  // received
}

fun registerBroadcastReceivers(context: Context){
  var  context = context
  context = context.applicationContext

// Register Recommendation Cluster Publish Intent
  context.registerReceiver(AppEngageBroadcastReceiver(),
                           IntentFilter(Intents.ACTION_PUBLISH_RECOMMENDATION))

// Register Featured Cluster Publish Intent
  context.registerReceiver(AppEngageBroadcastReceiver(),
                           IntentFilter(Intents.ACTION_PUBLISH_FEATURED))

// Register Continuation Cluster Publish Intent
  context.registerReceiver(AppEngageBroadcastReceiver(),
                           IntentFilter(Intents.ACTION_PUBLISH_CONTINUATION))
}

Java

class AppEngageBroadcastReceiver extends BroadcastReceiver {
// Trigger recommendation cluster publish when PUBLISH_RECOMMENDATION broadcast
// is received

// Trigger featured cluster publish when PUBLISH_FEATURED broadcast is received

// Trigger continuation cluster publish when PUBLISH_CONTINUATION broadcast is
// received
}

public static void registerBroadcastReceivers(Context context) {

context = context.getApplicationContext();

// Register Recommendation Cluster Publish Intent
context.registerReceiver(new AppEngageBroadcastReceiver(),
new IntentFilter(com.google.android.engage.service.Intents.ACTION_PUBLISH_RECOMMENDATION));

// Register Featured Cluster Publish Intent
context.registerReceiver(new AppEngageBroadcastReceiver(),
new IntentFilter(com.google.android.engage.service.Intents.ACTION_PUBLISH_FEATURED));

// Register Continuation Cluster Publish Intent
context.registerReceiver(new AppEngageBroadcastReceiver(),
new IntentFilter(com.google.android.engage.service.Intents.ACTION_PUBLISH_CONTINUATION));

}
  • Declara de forma estática una implementación con la etiqueta <receiver> en tu archivo AndroidManifest.xml. Esto permite que la aplicación reciba intents de transmisión cuando no está en ejecución y que la aplicación publique el contenido.
<application>
   <receiver
      android:name=".AppEngageBroadcastReceiver"
      android:exported="true"
      android:enabled="true">
      <intent-filter>
         <action android:name="com.google.android.engage.action.PUBLISH_RECOMMENDATION" />
      </intent-filter>
      <intent-filter>
         <action android:name="com.google.android.engage.action.PUBLISH_FEATURED" />
      </intent-filter>
      <intent-filter>
         <action android:name="com.google.android.engage.action.PUBLISH_CONTINUATION" />
      </intent-filter>
   </receiver>
</application>

El servicio envía los siguientes intents:

  • com.google.android.engage.action.PUBLISH_RECOMMENDATION Te recomendamos que inicies una llamada a publishRecommendationClusters cuando recibas este intent.
  • com.google.android.engage.action.PUBLISH_FEATURED Te recomendamos que inicies una llamada a publishFeaturedCluster cuando recibas este intent.
  • com.google.android.engage.action.PUBLISH_CONTINUATION Te recomendamos que inicies una llamada a publishContinuationCluster cuando recibas este intent.

Flujo de trabajo de integración

Si deseas obtener una guía paso a paso para verificar la integración una vez que esta se complete, consulta Flujo de trabajo de integración para desarrolladores de Engage.

Preguntas frecuentes

Consulta Preguntas frecuentes sobre el SDK de Engage para ver preguntas frecuentes.

Contacto

Comunícate con engage-developers@google.com si tienes preguntas durante el proceso de integración.

Próximos pasos

Después de completar esta integración, sigue estos pasos:

  • Envía un correo electrónico a engage-developers@google.com y adjunta el APK integrado que está listo para que Google lo pruebe.
  • Google realiza una verificación y revisiones internas para asegurarse de que la integración funcione según lo previsto. Si se necesitan cambios, Google se comunica contigo con los detalles necesarios.
  • Cuando se completen las pruebas y no se necesiten cambios, Google se comunica contigo para notificarte que puedes comenzar a publicar el APK integrado y actualizado en Play Store.
  • Después de que Google confirme que tu APK actualizado se publicó en Play Store, los clústeres de Recommendation, Featured y Continuation se pueden publicar y estar visibles para los usuarios.