Continua a guardare utilizza il cluster Continua per mostrare i video non terminati e gli episodi successivi da guardare della stessa stagione TV, da più app in un unico raggruppamento dell'interfaccia utente. Puoi mettere in evidenza le loro entità in questo cluster di continuazione. Segui questa guida per scoprire come migliorare il coinvolgimento degli utenti tramite l'esperienza Continua a guardare utilizzando l'SDK Engage.
Preparazione
Prima di iniziare, completa i seguenti passaggi:
aggiornamento all'API target 19 o versioni successive
Aggiungi la libreria
com.google.android.engage
alla tua app:Esistono SDK separati da utilizzare nell'integrazione: uno per le app mobile e uno per le app TV.
Dispositivo mobile
dependencies { implementation 'com.google.android.engage:engage-core:1.5.5 }
TV
dependencies { implementation 'com.google.android.engage:engage-tv:1.0.2 }
Imposta l'ambiente di servizio Engage su produzione nel file
AndroidManifest.xml
.Dispositivo mobile
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION" />
TV
<meta-data android:name="com.google.android.engage.service.ENV" android:value="PRODUCTION" />
Aggiungi l'autorizzazione per
WRITE_EPG_DATA
per l'APK della TV<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
Verifica la pubblicazione di contenuti affidabili utilizzando un servizio in background, come
androidx.work
, per la pianificazione.Per offrire un'esperienza di visualizzazione senza interruzioni, pubblica i dati di Continua a guardare quando si verificano questi eventi:
- Primo accesso: quando un utente accede per la prima volta, pubblica i dati per assicurarti che la cronologia delle visualizzazioni sia disponibile immediatamente.
- Creazione o cambio di profilo (app multi-profilo): se la tua app supporta più profili, pubblica i dati quando un utente crea o cambia profilo.
- Interruzione della riproduzione video: per aiutare gli utenti a riprendere la riproduzione da dove l'avevano interrotta, pubblica i dati quando mettono in pausa o interrompono un video oppure quando l'app viene chiusa durante la riproduzione.
- Aggiornamenti della sezione Continua a guardare (se supportata): quando un utente rimuove un elemento dalla sezione Continua a guardare, rifletti la modifica pubblicando dati aggiornati.
- Completamento video:
- Per i film, rimuovi il film completato dalla sezione Continua a guardare. Se il film fa parte di una serie, aggiungi il film successivo per mantenere alto il coinvolgimento dell'utente.
- Per le puntate, rimuovi quella completata e aggiungi la successiva della serie, se disponibile, per incoraggiare la visione continuativa.
Integrazione
AccountProfile
Per consentire un'esperienza personalizzata di "Continua a guardare" su Google TV, fornisci le informazioni dell'account e del profilo. Utilizza AccountProfile per fornire:
ID account: un identificatore univoco che rappresenta l'account dell'utente all'interno della tua applicazione. Può trattarsi dell'ID account effettivo o di una versione offuscata in modo appropriato.
ID profilo (facoltativo): se la tua applicazione supporta più profili all'interno di un singolo account, fornisci un identificatore univoco per il profilo utente specifico (di nuovo, reale o offuscato).
// 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()
Crea entità
L'SDK ha definito entità diverse per rappresentare ogni tipo di elemento. Il cluster di continuazione supporta le seguenti entità:
Specifica gli URI e le immagini di copertina specifici della piattaforma per queste entità.
Inoltre, crea URI di riproduzione per ogni piattaforma, ad esempio Android TV, Android o iOS, se non l'hai ancora fatto. Pertanto, 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 di copertina richiedono un URI e le dimensioni in pixel (altezza e larghezza). Prendi di mira diversi fattori di forma fornendo più immagini del poster, ma verifica che tutte le immagini mantengano proporzioni 16:9 e un'altezza minima di 200 pixel per la corretta visualizzazione dell'entità "Continua a guardare", in particolare 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 un 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)
.build()
Fornire dettagli come generi e classificazioni dei contenuti consente a Google TV di mostrare i tuoi contenuti in modo più dinamico 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 disponibili automaticamente per 60 giorni, a meno che tu non specifichi un periodo di scadenza più breve. Imposta una scadenza personalizzata solo se vuoi che l'entità venga rimossa 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 un 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")
.build()
La stringa del numero di episodio (ad esempio "2"
) e la stringa del numero di stagione (ad esempio "1"
) verranno espanse nel formato corretto prima di essere visualizzate nella scheda Continua a guardare. Tieni presente che deve essere una stringa numerica, non inserire "e2",
o "episodio 2", o "s1" o "stagione 1".
Se un determinato programma TV ha una sola stagione, imposta il numero della stagione su 1.
Per massimizzare le possibilità che gli spettatori trovino i tuoi contenuti su Google TV, valuta la possibilità di fornire dati aggiuntivi come generi, classificazioni 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 un VideoClipEntity
con tutti i campi obbligatori.
VideoClipEntity
rappresenta un clip generato dagli utenti, 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)
.build()
Puoi impostare facoltativamente 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 un 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)
.build()
Se vuoi, puoi impostare l'ora di inizio, l'emittente, l'icona dell'emittente o la finestra temporale di disponibilità per l'entità live streaming.
Per informazioni dettagliate su attributi e requisiti, consulta il riferimento API.
Fornisci i dati del cluster di continuazione
AppEngagePublishClient
è responsabile della pubblicazione del cluster Continua.
Utilizzi il metodo publishContinuationCluster()
per pubblicare un oggetto ContinuationCluster
.
Innanzitutto, devi utilizzare isServiceAvailable() per verificare se il servizio è disponibile per l'integrazione.
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, le seguenti azioni vengono eseguite all'interno di una transazione:
- I dati
ContinuationCluster
esistenti del partner sviluppatore vengono rimossi. - I dati della richiesta vengono analizzati e archiviati nel
ContinuationCluster
aggiornato.
In caso di errore, l'intera richiesta viene rifiutata e lo stato esistente viene mantenuto.
Le API di pubblicazione sono API upsert, ovvero sostituiscono i contenuti esistenti. Se devi aggiornare una specifica entità in ContinuationCluster, dovrai pubblicare di nuovo tutte le entità.
I dati ContinuationCluster devono essere forniti solo per gli account per adulti. Pubblica solo quando AccountProfile appartiene a un adulto.
Sincronizzazione cross-device
Il flag SyncAcrossDevices
controlla se i dati ContinuationCluster
di un utente vengono sincronizzati tra dispositivi come TV, smartphone, tablet e così via. La sincronizzazione tra dispositivi è disattivata per impostazione predefinita.
Valori:
- true: i dati ContinuationCluster vengono condivisi su tutti i dispositivi dell'utente per un'esperienza di visualizzazione senza interruzioni. Consigliamo vivamente questa opzione per la migliore esperienza cross-device.
- false: I dati di ContinuationCluster sono limitati al dispositivo corrente.
Ottenere il consenso:
L'applicazione multimediale deve fornire un'impostazione chiara per attivare/disattivare la sincronizzazione cross-device. Spiega i vantaggi per l'utente e 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 attiva SyncAcrossDevices
per true
. Ciò consente ai contenuti di
sincronizzarsi senza problemi su tutti 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 Video discovery
Per eliminare manualmente i dati di un utente dal server Google TV prima del periodo di conservazione standard di 60 giorni, utilizza il metodo client.deleteClusters(). Una volta ricevuta la richiesta, il servizio eliminerà tutti i dati esistenti di scoperta dei video per il profilo dell'account o per l'intero account.
L'enumerazione 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. Questa applicazione per Android fornisce strumenti per aiutarti a verificare i tuoi dati e confermare che gli intent di trasmissione vengano gestiti 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 riga distinta nell'interfaccia dell'app.
- Imposta Engage Service Flag solo per le build non di produzione nel file manifest Android della tua app.
- Installa e apri l'app Engage Verify.
- Se
isServiceAvailable
èfalse
, fai clic sul pulsante "Attiva/Disattiva" per attivarlo. - Inserisci il nome del pacchetto della tua app per visualizzare automaticamente i dati pubblicati una volta che inizi la pubblicazione.
- Testa queste azioni nella tua app:
- Accedi.
- Passa da un profilo all'altro(se applicabile).
- Avvia, metti in pausa un video o torna alla home page.
- Chiudi l'app durante la riproduzione del video.
- Rimuovere un elemento dalla riga "Continua a guardare" (se supportata).
- Dopo ogni azione, verifica che la tua app abbia richiamato l'API
publishContinuationClusters
e che i dati vengano visualizzati correttamente nell'app di verifica. L'app di verifica mostrerà un segno di spunta verde "Tutto a posto" per le entità implementate correttamente.
Figura 1. Verifica app riuscita L'app di verifica segnalerà eventuali entità problematiche.
Figura 2. Errore dell'app di verifica 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. Dettagli errore app di verifica
API REST
L'SDK Engage offre un'API REST per fornire un'esperienza coerente di Continua a guardare su piattaforme non Android come iOS e Roku TV. L'API consente agli sviluppatori di aggiornare lo stato "Continua a guardare" per gli utenti che hanno attivato le piattaforme non Android.
Prerequisiti
- Devi prima completare l'integrazione basata sull'SDK Engage on-device.
Questo passaggio fondamentale stabilisce l'associazione necessaria tra l'ID utente di Google e il
AccountProfile
della tua app. - Accesso e autenticazione API: per visualizzare e abilitare l'API nel tuo progetto Google Cloud, devi superare un processo di allowlist. Tutte le richieste API richiedono l'autenticazione.
Ottenere l'accesso
Per ottenere l'accesso per visualizzare e attivare l'API nella console Google Cloud, il tuo account deve essere registrato.
- L'ID cliente Google Workspace deve essere disponibile. Se non è disponibile, potresti dover configurare Google Workspace e tutti gli Account Google che vuoi utilizzare per chiamare l'API.
- Configura un account con Google Cloud Console utilizzando un indirizzo email associato a Google Workspace.
- Creare un nuovo progetto
- Crea un service account per l'autenticazione API. Una volta creato il service account, avrai due elementi:
- Un ID service account.
- Un file JSON con la chiave dell'account di servizio. Conserva questo file in modo sicuro, ti servirà in un secondo momento per autenticare il client nell'API.
- Workspace e gli Account Google associati ora possono utilizzare le API REST. Una volta propagata la modifica, riceverai una notifica che ti comunicherà se l'API è pronta per essere chiamata dai tuoi service account.
- Segui questi passaggi per prepararti a effettuare una chiamata API delegata.
Pubblica cluster di continuazione
Per pubblicare i dati di scoperta dei video, esegui una richiesta POST all'API publishContinuationCluster
utilizzando la seguente sintassi.
https://tvvideodiscovery.googleapis.com/v1/packages/{package_name}/accounts/{account_id}/profiles/{profile_id}/publishContinuationCluster
Dove:
package_name
: Il nome del pacchetto del fornitore di contenuti multimedialiaccountId
: l'ID univoco dell'account dell'utente nel tuo sistema. Deve corrispondere aaccountId
utilizzato nel percorso sul dispositivo.profileId
: l'ID univoco del profilo dell'utente all'interno dell'account nel tuo sistema. Deve corrispondere a profileId utilizzato nel percorso sul dispositivo.
L'URL dell'account senza profilo è:
https://tvvideodiscovery.googleapis.com/v1/packages/{package_name}/accounts/{account_id}/publishContinuationCluster
Il payload della richiesta è rappresentato nel campo entities
. entities
rappresenta un elenco di entità di contenuti che possono essere MovieEntity
o
TVEpisodeEntity
. Questo campo è obbligatorio.
Corpo della richiesta
Field |
Tipo |
Obbligatorio |
Descrizione |
entità |
Elenco di oggetti MediaEntity |
Sì |
Elenco delle entità di contenuti (max. 5), verranno conservate solo le prime cinque e le altre verranno eliminate. È consentito un elenco vuoto per indicare che l'utente ha terminato di guardare tutte le entità. |
Il campo entities
contiene movieEntity
e tvEpisodeEntity
individuali.
Field |
Tipo |
Obbligatorio |
Descrizione |
movieEntity |
MovieEntity |
Sì |
Un oggetto che rappresenta un film all'interno di ContinuationCluster. |
tvEpisodeEntity |
TvEpisodeEntity |
Sì |
Un oggetto che rappresenta una puntata di una serie TV all'interno di ContinuationCluster. |
Ogni oggetto nell'array di entità deve essere uno dei tipi MediaEntity disponibili,
ovvero MovieEntity
e TvEpisodeEntity
, insieme ai campi comuni e
specifici per il tipo.
Lo snippet di codice riportato di seguito mostra il payload del corpo della richiesta per l'API
publishContinuationCluster
.
{
"entities": [
{
"movieEntity": {
"watch_next_type": "WATCH_NEXT_TYPE_CONTINUE",
"name": "Movie1",
"platform_specific_playback_uris": [
"https://www.example.com/entity_uri_for_android",
"https://www.example.com/entity_uri_for_iOS"
],
"poster_images": [
"http://www.example.com/movie1_img1.png",
"http://www.example.com/movie1_imag2.png"
],
"last_engagement_time_millis": 864600000,
"duration_millis": 5400000,
"last_play_back_position_time_millis": 3241111
}
},
{
"tvEpisodeEntity": {
"watch_next_type": "WATCH_NEXT_TYPE_CONTINUE",
"name": "TV SERIES EPISODE 1",
"platform_specific_playback_uris": [
"https://www.example.com/entity_uri_for_android",
"https://www.example.com/entity_uri_for_iOS"
],
"poster_images": [
"http://www.example.com/episode1_img1.png",
"http://www.example.com/episode1_imag2.png"
],
"last_engagement_time_millis": 864600000,
"duration_millis": 1800000,
"last_play_back_position_time_millis": 2141231,
"episode_display_number": "1",
"season_number": "1",
"show_title": "title"
}
}
]
}
Eliminare i dati degli annunci video discovery
Utilizza l'API clearClusters
per rimuovere i dati di rilevamento dei video.
Utilizza l'URL POST per rimuovere le entità dai dati di scoperta dei video.
Per eliminare i dati del cluster di continuazione, esegui una richiesta POST all'API
clearClusters
utilizzando la seguente sintassi.
https://tvvideodiscovery.googleapis.com/v1/packages/{package_name}/accounts/{account_id}/profiles/{profile_id}/clearClusters
Dove:
package_name
: Il nome del pacchetto del fornitore di contenuti multimediali.accountId
: l'ID univoco dell'account dell'utente nel tuo sistema. Deve corrispondere aaccountId
utilizzato nel percorso sul dispositivo.profileId
: l'ID univoco del profilo dell'utente all'interno dell'account nel tuo sistema. Deve corrispondere a profileId utilizzato nel percorso sul dispositivo.
Il payload dell'API clearClusters
contiene un solo campo, reason
,
che contiene un DeleteReason
che specifica il motivo della rimozione
dei dati.
{
"reason": "DELETE_REASON_LOSS_OF_CONSENT"
}
Test
Dopo aver pubblicato correttamente i dati, utilizza un account di test utente per verificare che i contenuti previsti vengano visualizzati nella riga "Continua a guardare" sulle piattaforme Google di destinazione, come Google TV e le app mobile Google TV per Android e iOS.
Durante i test, consenti un ritardo di propagazione ragionevole di pochi minuti e rispetta i requisiti di visualizzazione, ad esempio la visione di una parte di un film o il completamento di un episodio. Per ulteriori dettagli, consulta le linee guida di Cosa guardare per gli sviluppatori di app.