Questa guida illustra come integrare la funzionalità Continua a guardare nella tua app per Android TV utilizzando l'SDK Engage.
Preparazione
Completa le istruzioni di preparazione nella guida introduttiva.
Integrazione
Creare entità
L'SDK ha definito diverse entità per rappresentare ogni tipo di articolo. Il cluster di continuazione supporta le seguenti entità:
Specifica gli URI e le immagini dei poster specifici della piattaforma per queste entità.
Inoltre, crea gli URI di riproduzione per ogni piattaforma, ad esempio Android TV, Android o iOS, se non l'hai già fatto. In questo modo, quando un utente continua a guardare su ogni piattaforma, l'app utilizza un URI di riproduzione mirato per riprodurre i contenuti 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)
Le immagini dei poster richiedono un URI e le dimensioni in pixel (altezza e larghezza). Per scegliere come target diversi fattori di forma, fornisci più immagini dei poster, ma verifica che tutte le immagini mantengano le proporzioni 16:9 e un'altezza minima di 200 pixel per la visualizzazione corretta dell'entità "Continua a guardare", soprattutto all'interno di Entertainment Space di Google. Le immagini con un'altezza inferiore a 200 pixel potrebbero non essere mostrate.
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
Questo esempio mostra come creare una MovieEntity con tutti i campi obbligatori:
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)
.setCallToActionText("Resume")
.addTag("Action")
.build()
Fornire dettagli come generi e classificazione dei contenuti consente a Google TV di mostrare i tuoi contenuti in modi più dinamici e di metterli in contatto con gli spettatori giusti.
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()
Le entità rimangono automaticamente disponibili per 60 giorni, a meno che tu non specifichi un periodo di scadenza più breve. Imposta una scadenza personalizzata solo se devi rimuovere l'entità prima di questo periodo predefinito.
// 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
Questo esempio mostra come creare una TvEpisodeEntity con tutti i campi obbligatori:
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")
.setCallToActionText("Resume")
.addTag("Comedy")
.build()
La stringa del numero dell'episodio (ad esempio "2") e la stringa del numero della stagione (ad esempio "1")
verranno espanse nel formato corretto prima di essere visualizzate sulla scheda Continua a
guardare. Tieni presente che devono essere stringhe numeriche, non inserire "e2", "episodio 2", "s1" o "stagione 1".
Se un determinato programma TV ha una sola stagione, imposta il numero della stagione su 1.
Per massimizzare le probabilità che gli spettatori trovino i tuoi contenuti su Google TV, valuta la possibilità di fornire dati aggiuntivi come generi, classificazione dei contenuti e finestre temporali di disponibilità, in quanto questi dettagli possono migliorare le opzioni di visualizzazione e filtro.
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
Ecco un esempio di creazione di una VideoClipEntity con tutti i campi obbligatori.
VideoClipEntity rappresenta una clip generata dall'utente, ad esempio un video di 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)
.setCallToActionText("Resume")
.addTag("Vlog")
.build()
Facoltativamente, puoi impostare il creatore, l'immagine del creatore, l'ora di creazione in millisecondi o la finestra temporale di disponibilità .
LiveStreamingVideoEntity
Ecco un esempio di creazione di una LiveStreamingVideoEntity con tutti i campi obbligatori.
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)
.setCallToActionText("Resume")
.addTag("Live")
.build()
Facoltativamente, puoi impostare l'ora di inizio, l'emittente, l'icona dell'emittente o la finestra temporale di disponibilità per l'entità del live streaming.
Per informazioni dettagliate su attributi e requisiti, consulta il Riferimento API.
Fornire i dati del cluster di continuazione
AppEngagePublishClient è responsabile della pubblicazione del cluster di continuazione.
Utilizza il metodo publishContinuationCluste per pubblicare un oggetto ContinuationCluster.
Assicurati di inizializzare il client e di verificare la disponibilità del servizio come descritto nella guida introduttiva.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.addEntity(movieEntity1)
.addEntity(movieEntity2)
.addEntity(tvEpisodeEntity1)
.addEntity(tvEpisodeEntity2)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
Quando il servizio riceve la richiesta, vengono eseguite le seguenti azioni all'interno di una transazione:
- Vengono rimossi i dati
ContinuationClusteresistenti del partner sviluppatore. - I dati della richiesta vengono analizzati e archiviati in
ContinuationClusteraggiornato.
In caso di errore, l'intera richiesta viene rifiutata e lo stato esistente viene mantenuto.
Le API di pubblicazione sono API upsert; sostituiscono i contenuti esistenti. Se devi aggiornare un'entità specifica nel cluster di continuazione, dovrai pubblicare di nuovo tutte le entità.
I dati del cluster di continuazione devono essere forniti solo per gli account per adulti. Pubblica solo quando il profilo dell'account appartiene a un adulto.
Sincronizzazione cross-device
setSyncAcrossDevices controlla se i dati ContinuationCluster di un utente vengono sincronizzati su dispositivi come TV, smartphone, tablet e così via. La sincronizzazione cross-device è disattivata per impostazione predefinita.
Valori:
true: i dati del cluster di continuazione vengono condivisi su tutti i dispositivi dell'utente per un'esperienza di visualizzazione senza interruzioni. Consigliamo vivamente questa opzione per un'esperienza cross-device ottimale.false: i dati del cluster di continuazione sono limitati al dispositivo corrente.
Inoltre, devi fornire un AccountProfile con un ID account affinché i contenuti vengano sincronizzati tra i dispositivi. Consulta
Creare un profilo dell'account.
Ottenere il consenso
L'applicazione multimediale deve fornire un'impostazione chiara per attivare o disattivare la sincronizzazione cross-device. Spiega i vantaggi all'utente, memorizza la sua preferenza una sola volta e applicala di conseguenza in publishContinuationCluster.
// Example to allow cross device syncing.
client.publishContinuationCluster(
PublishContinuationClusterRequest
.Builder()
.setContinuationCluster(
ContinuationCluster.Builder()
.setAccountProfile(accountProfile)
.setSyncAcrossDevices(true)
.build()
)
.build()
)
Per sfruttare al meglio la nostra funzionalità cross-device, verifica che l'app ottenga il consenso dell'utente e imposta SyncAcrossDevices su true. In questo modo, i contenuti possono essere sincronizzati senza problemi tra i dispositivi, migliorando l'esperienza utente e aumentando il coinvolgimento. Ad esempio, un partner che ha implementato questa funzionalità ha registrato un aumento del 40% dei clic su "Continua a guardare" perché i suoi contenuti sono stati visualizzati su più dispositivi.
Eliminare i dati di Engage
Per eliminare manualmente i dati di un utente dal server di Google TV prima del periodo di conservazione standard di 60 giorni, utilizza il metodo deleteClusters. Dopo aver ricevuto la richiesta, il servizio eliminerà tutti i dati di Engage esistenti per il profilo dell'account o per l'intero account.
L'enum DeleteReason definisce il motivo dell'eliminazione dei dati.
Il seguente codice rimuove i dati di Continua a guardare al momento della disconnessione.
// 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()
)
Test
Utilizza l'app di verifica per verificare che l'integrazione dell'SDK Engage funzioni correttamente.
Dopo aver richiamato l'API di pubblicazione, verifica che i dati vengano pubblicati correttamente controllando l'app di verifica. Il cluster di continuazione deve essere visualizzato come una riga distinta nell'interfaccia dell'app.
- Prova queste azioni nella tua app:
- Accedi.
- Passa da un profilo all'altro(se applicabile).
- Avvia e metti in pausa un video oppure torna alla home page.
- Chiudi l'app durante la riproduzione del video.
- Rimuovi un elemento dalla riga "Continua a guardare" (se supportato).
- Dopo ogni azione, verifica che l'app abbia richiamato l'API
publishContinuationClusterse che i dati vengano visualizzati correttamente nell'app di verifica. L'app di verifica mostra un segno di spunta verde "Tutto ok" per le entità implementate correttamente.
Figura 1. App di verifica: operazione riuscita L'app di verifica segnalerà eventuali entità problematiche.
Figura 2. App di verifica: errore Per risolvere i problemi relativi alle entità con errori, utilizza il telecomando della TV per selezionare e fare clic sull'entità nell'app di verifica. I problemi specifici verranno visualizzati ed evidenziati in rosso per la tua revisione (vedi l'esempio di seguito).
Figura 3. App di verifica: dettagli dell'errore