book_path: /distribute/other-docs/_book.yaml project_path: /distribute/other-docs/_project.yaml
Este guia mostra como integrar o recurso "Continuar assistindo" ao seu app Android TV usando o SDK Engage.
Pré-trabalho
Siga as instruções de Pré-trabalho no guia para iniciantes.
Integração
Criar entidades
O SDK definiu entidades diferentes para representar cada tipo de item. O cluster de continuação é compatível com as seguintes entidades:
Especifique os URIs e as imagens de pôster específicos da plataforma para essas entidades.
Além disso, crie URIs de reprodução para cada plataforma, como Android TV, Android ou iOS, se ainda não tiver feito isso. Assim, quando um usuário continua assistindo em cada plataforma, o app usa um URI de reprodução segmentado para abrir o conteúdo de vídeo.
// 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)
As imagens de pôster exigem um URI e dimensões de pixel (altura e largura). Para segmentar diferentes formatos, forneça várias imagens de pôster, mas verifique se todas mantêm uma proporção de 16:9 e uma altura mínima de 200 pixels para exibição correta da entidade "Continuar assistindo", principalmente no Espaço de entretenimento do Google. Imagens com altura menor que 200 pixels podem não ser mostradas.
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
Este exemplo mostra como criar um MovieEntity com todos os campos obrigatórios:
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()
Ao fornecer detalhes como gêneros e classificações de conteúdo, o Google TV pode mostrar seu conteúdo de maneiras mais dinâmicas e conectá-lo aos espectadores certos.
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()
As entidades ficam disponíveis automaticamente por 60 dias, a menos que você especifique um tempo de expiração menor. Defina uma expiração personalizada apenas se precisar que a entidade seja removida antes desse período padrão.
// 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
Este exemplo mostra como criar um TvEpisodeEntity com todos os campos
obrigatórios:
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()
A string do número do episódio (como "2") e a string do número da temporada (como "1") serão expandidas para a forma adequada antes de serem exibidas no card "Continuar assistindo". Eles precisam ser uma string numérica. Não coloque "e2", "episódio 2", "s1" ou "temporada 1".
Se um programa de TV tiver apenas uma temporada, defina o número da temporada como 1.
Para aumentar as chances de os espectadores encontrarem seu conteúdo no Google TV, forneça dados adicionais, como gêneros, classificações de conteúdo e períodos de disponibilidade. Esses detalhes podem melhorar as opções de exibição e filtragem.
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
Confira um exemplo de como criar um VideoClipEntity com todos os campos obrigatórios.
VideoClipEntity representa um clipe gerado pelo usuário, como um vídeo do 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()
Você pode definir o criador, a imagem do criador, o tempo de criação em milissegundos ou o período de disponibilidade .
LiveStreamingVideoEntity
Confira um exemplo de como criar um LiveStreamingVideoEntity com todos os campos obrigatórios.
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()
Se quiser, defina o horário de início, o ícone ou o nome do broadcaster ou o período de disponibilidade da entidade de transmissão ao vivo.
Para informações detalhadas sobre atributos e requisitos, consulte a referência da API.
Fornecer dados do cluster de continuação
O AppEngagePublishClient é responsável por publicar o cluster de continuação.
Use o método publishContinuationCluste para publicar um objeto ContinuationCluster.
Inicialize o cliente e verifique a disponibilidade do serviço conforme descrito no Guia de início rápido.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.addEntity(movieEntity1)
.addEntity(movieEntity2)
.addEntity(tvEpisodeEntity1)
.addEntity(tvEpisodeEntity2)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
Quando o serviço recebe a solicitação, as seguintes ações ocorrem em uma transação:
- Os dados do
ContinuationClusterdo parceiro do desenvolvedor são removidos. - Os dados da solicitação são analisados e armazenados no
ContinuationClusteratualizado.
Em caso de erro, a solicitação inteira é rejeitada e o estado atual é mantido.
As APIs de publicação são APIs de inserção que substituem o conteúdo já existente. Se você precisar atualizar uma entidade específica no cluster de continuação, será necessário publicar todas as entidades novamente.
Os dados de cluster de continuidade só devem ser fornecidos para contas de adultos. Publicar somente quando o perfil da conta pertencer a um adulto.
Sincronização entre dispositivos
A flag SyncAcrossDevices controla se os dados de ContinuationCluster de um usuário são sincronizados em dispositivos como TV, smartphone, tablets etc. A sincronização entre dispositivos fica desativada por padrão.
Valores:
true: os dados do cluster de continuação são compartilhados em todos os dispositivos do usuário para uma experiência de visualização perfeita. Recomendamos essa opção para ter a melhor experiência em vários dispositivos.false: os dados do cluster de continuação são restritos ao dispositivo atual.
Obter consentimento
O aplicativo de mídia precisa oferecer uma configuração clara para ativar ou desativar
a sincronização entre dispositivos. Explique os benefícios para o usuário e armazene a preferência dele
uma vez e aplique-a em publishContinuationCluster.
// Example to allow cross device syncing.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
Para aproveitar ao máximo nosso recurso entre dispositivos, verifique se o app recebe o consentimento do usuário e ative o SyncAcrossDevices para true. Isso permite que o conteúdo seja sincronizado perfeitamente em todos os dispositivos, resultando em uma melhor experiência do usuário e maior engajamento. Por exemplo, um parceiro que implementou isso teve um aumento de 40% nos cliques em "Continuar assistindo" porque o conteúdo dele apareceu em vários dispositivos.
Excluir os dados de descoberta de vídeo
Para excluir manualmente os dados de um usuário do servidor do Google TV antes do período padrão de retenção de 60 dias, use o método deleteClusters. Ao receber a solicitação, o serviço vai excluir todos os dados de descoberta de vídeo do perfil da conta ou de toda a conta.
O enum DeleteReason define o motivo da exclusão de dados.
O código a seguir remove os dados de "Continuar assistindo" ao sair.
// 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()
)
Teste
Use o app de verificação para conferir se a integração do SDK do Engage está funcionando corretamente.
Depois de invocar a API Publish, confira se os dados estão sendo publicados corretamente verificando o app de verificação. Seu cluster de continuação vai aparecer como uma linha distinta na interface do app.
- Teste estas ações no seu app:
- Faça login.
- Alternar entre perfis(se aplicável).
- Iniciar e pausar um vídeo ou voltar para a página inicial.
- Feche o app durante a reprodução de vídeo.
- Remover um item da linha "Continuar assistindo" (se disponível).
- Depois de cada ação, confirme se o app invocou a API
publishContinuationClusterse se os dados estão sendo mostrados corretamente no app de verificação. O app de verificação mostra uma marca de seleção verde "Tudo certo" para entidades implementadas corretamente.
Figura 1. Sucesso do app de verificação O app de verificação vai sinalizar todas as entidades problemáticas.
Figura 2. Erro no app de verificação Para resolver problemas com entidades, use o controle remoto da TV para selecionar e clicar na entidade no app de verificação. Os problemas específicos vão aparecer e serão destacados em vermelho para sua análise (confira o exemplo abaixo).
Figura 3. Detalhes do erro do app de verificação