O recurso "Continuar assistindo" usa o cluster de continuação para mostrar vídeos inacabados e os próximos episódios da mesma temporada de TV de vários apps em um grupo de interfaces. É possível destacar as entidades deles nesse cluster de continuação. Siga este guia para saber como melhorar o engajamento do usuário com a experiência de continuar assistindo usando o SDK Engage.
Etapa 1: preparação
Antes de começar, siga estas etapas:
Verifique se o app é direcionado ao nível 19 da API ou mais recente para essa integração.
Adicione a biblioteca
com.google.android.engage
ao app:Há SDKs separados para usar na integração: um para apps para dispositivos móveis e outro para apps de TV.
Dispositivos móveis
dependencies { implementation 'com.google.android.engage:engage-core:1.5.5 }
TV
dependencies { implementation 'com.google.android.engage:engage-tv:1.0.2 }
Defina o ambiente do serviço Engage como produção no arquivo
AndroidManifest.xml
.Dispositivos móveis
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION"> </meta-data>
TV
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION"> </meta-data>
Adicionar permissão para
WRITE_EPG_DATA
para o APK de TV<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
Garanta a publicação confiável do conteúdo usando um serviço em segundo plano, como
androidx.work
, para programação.Para oferecer uma experiência de visualização perfeita, publique dados de continuação de exibição quando estes eventos ocorrerem:
- Primeiro login: quando um usuário faz login pela primeira vez, a publicação dos dados garante que o histórico de visualização dele esteja disponível imediatamente.
- Criação ou troca de perfil (apps com vários perfis): se o app oferece suporte a vários perfis, publique dados quando um usuário cria ou troca de perfil. Isso garante que cada usuário tenha uma experiência personalizada.
- Interrupção da reprodução de vídeo: para ajudar os usuários a retomar de onde pararam, publique dados quando eles pausarem ou pararem um vídeo ou quando o app sair durante a reprodução.
- Atualizações da bandeja "Continuar assistindo" (se houver suporte): quando um usuário remove um item da bandeja "Continuar assistindo", reflita essa mudança publicando dados atualizados. Isso garante que a bandeja permaneça relevante e personalizada.
- Finalização do vídeo:
- Para filmes, remova o filme concluído da bandeja "Continuar assistindo". Se o filme fizer parte de uma série, adicione o próximo para manter o usuário engajado.
- Para episódios, remova o episódio concluído e adicione o próximo da série, se disponível, para incentivar a continuação da visualização.
Integração
AccountProfile
Para permitir uma experiência personalizada de "continuar assistindo" no Google TV, forneça informações da conta e do perfil. Use o AccountProfile para fornecer:
ID da conta: um identificador exclusivo que representa a conta do usuário no seu app. Pode ser o ID real da conta ou uma versão obfuscada adequada.
ID do perfil (opcional): se o aplicativo oferecer suporte a vários perfis em uma única conta, forneça um identificador exclusivo para o perfil de usuário específico (real ou ofuscado).
// If your app only supports account
val accountProfile = AccountProfile.Builder()
.setAccountId("your_users_account_id")
.build()
// If your app supports both account and profile
val accountProfile = AccountProfile.Builder()
.setAccountId("your_users_account_id")
.setProfileId("your_users_profile_id")
.build()
Criar entidades
O SDK definiu entidades diferentes para representar cada tipo de item. O cluster de continuação oferece suporte às seguintes entidades:
Especifique os URIs específicos da plataforma e as imagens de cartaz 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 reproduzir o conteúdo do 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 cartaz exigem um URI e dimensões em pixels (altura e largura). Segmente diferentes formatos fornecendo várias imagens de cartaz, mas garanta que todas as imagens mantenham uma proporção de 16:9 e uma altura mínima de 200 pixels para a exibição correta da entidade "Continue assistindo", especialmente no Espaço de entretenimento do Google. Imagens com altura menor que 200 pixels podem não ser exibidas.
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)
MovieEntity
Este exemplo mostra como criar uma 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 permanecem 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 = new 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
necessá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 o formato adequado antes de serem exibidas no card de
continuar assistindo. Elas precisam ser uma string numérica. Não coloque "e2",
"episódio 2", "s1" ou "temporada 1".
Se um programa de TV específico tiver apenas uma temporada, defina o número da temporada como 1.
Para maximizar as chances de os espectadores encontrarem seu conteúdo no Google TV, forneça mais dados, como gêneros, classificações de conteúdo e janelas de disponibilidade, porque esses detalhes podem melhorar as exibições e as opções de 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 a janela 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 transmissor, o ícone do transmissor ou a janela de disponibilidade para a 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
AppEngagePublishClient
é responsável pela publicação do cluster de continuação.
Use o método publishContinuationCluster()
para publicar um
objeto ContinuationCluster
.
Primeiro, use isServiceAvailable() para verificar se o serviço está disponível para integração.
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
ContinuationCluster
do parceiro do desenvolvedor são removidos. - Os dados da solicitação são analisados e armazenados no
ContinuationCluster
atualizado.
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 ContinuationCluster, será necessário publicar todas as entidades novamente.
Os dados do ContinuationCluster só podem ser fornecidos para contas de adultos. Publicar apenas quando o AccountProfile pertencer a um adulto.
Sincronização entre dispositivos
Flag SyncAcrossDevices
Essa flag controla se os dados do ContinuationCluster de um usuário são sincronizados em todos os dispositivos (TV, smartphone, tablet etc.). O padrão é falso, o que significa que a sincronização entre dispositivos está desativada por padrão.
Valores:
- true: os dados do ContinuationCluster 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.
- Falso: os dados do ContinuationCluster são restritos ao dispositivo atual.
Obtenha consentimento:
O app de mídia precisa fornecer uma configuração clara para ativar/desativar a sincronização entre dispositivos. Explique os benefícios para o usuário e armazene a preferência do usuário uma vez e aplique-a em publishContinuationCluster de acordo.
// 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 como "true". Isso permite que o conteúdo seja sincronizado entre dispositivos, o que resulta em uma melhor experiência do usuário e aumenta o engajamento. Por exemplo, um parceiro que implementou isso teve um aumento de 40% nos cliques em "Continuar assistindo" porque o conteúdo dele foi exibido 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 client.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 tipo enumerado DeleteReason
define o motivo da exclusão de dados.
O código a seguir remove os dados de continuação de exibição 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(
new DeleteClustersRequest.Builder()
.setAccountProfile(AccountProfile())
.setReason(DeleteReason.DELETE_REASON_USER_LOG_OUT)
.setSyncAcrossDevices(true)
.build()
)
Teste
Use o app de verificação para garantir que a integração do SDK Engage esteja funcionando corretamente. Esse aplicativo Android fornece ferramentas para ajudar você a verificar seus dados e confirmar se as intents de transmissão estão sendo processadas corretamente.
Depois de invocar a API de publicação, confirme se os dados estão sendo publicados corretamente verificando o app de verificação. O cluster de continuação vai ser exibido como uma linha distinta na interface do app.
- Verifique se a flag do serviço de engajamento NÃO está definida como produção no arquivo de manifesto do Android do seu app.
- Instalar e abrir o app Engage Verify
- Se
isServiceAvailable
forfalse
, clique no botão "Ativar" para ativar. - Insira o nome do pacote do app para ver automaticamente os dados publicados assim que você começar a publicação.
- Teste estas ações no seu app:
- Faça login.
- Alternar entre perfis(se aplicável).
- Comece, pause um vídeo ou volte para a página inicial.
- Feche o app durante a reprodução de vídeo.
- Remover um item da linha "Continuar assistindo" (se houver suporte).
- Após cada ação, confirme se o app invocou a API publishContinuationClusters e se os dados são mostrados corretamente no app de verificação.
O app de verificação vai mostrar uma marca 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 de verificação do app Para resolver problemas com entidades com erros, 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