1. Panoramica
Questo codelab ti spiegherà come modificare un'app video per Android esistente per trasmettere contenuti su un dispositivo con tecnologia Google Cast.
Che cos'è Google Cast?
Google Cast consente agli utenti di trasmettere contenuti da un dispositivo mobile alla TV. Gli utenti possono quindi utilizzare il dispositivo mobile come telecomando per la riproduzione di contenuti multimediali sulla TV.
L'SDK Google Cast ti consente di estendere l'app per controllare una TV o un sistema audio. L'SDK Cast ti consente di aggiungere i componenti necessari all'interfaccia utente in base all'elenco di controllo per la progettazione di Google Cast.
L'elenco di controllo per la progettazione di Google Cast viene fornito per semplificare e prevedere l'esperienza utente con tutte le piattaforme supportate.
Cosa realizzeremo?
Dopo aver completato il codelab, avrai un'app video per Android in grado di trasmettere video a un dispositivo compatibile con Google Cast.
Obiettivi didattici
- Come aggiungere l'SDK Google Cast a un'app video di esempio.
- Come aggiungere il pulsante Trasmetti per selezionare un dispositivo Google Cast.
- Come connettersi a un dispositivo di trasmissione e avviare un ricevitore multimediale.
- Come trasmettere un video.
- Come aggiungere un controller Mini Cast all'app.
- Come supportare le notifiche dei contenuti multimediali e i controlli della schermata di blocco.
- Come aggiungere un controller espanso.
- Come fornire un overlay introduttivo.
- Come personalizzare i widget di trasmissione.
- Come eseguire l'integrazione con Cast Connect
Che cosa ti serve
- L'ultimo SDK Android.
- Android Studio versione 3.2 o successive
- Un dispositivo mobile con Android 4.1 Jelly Bean (livello API 16) o versioni successive.
- Un cavo dati USB per collegare il dispositivo mobile al computer di sviluppo.
- Un dispositivo Google Cast, ad esempio Chromecast o Android TV, configurato con accesso a Internet.
- Una TV o un monitor con ingresso HDMI.
- Per testare l'integrazione di Cast Connect è necessario Chromecast con Google TV, ma facoltativo per il resto del codelab. Se non ne hai uno, puoi saltare il passaggio Aggiungi assistenza per la trasmissione alla fine di questo tutorial.
Esperienza
- Devi disporre di conoscenze pregresse in merito a Kotlin e Android.
- Avrai anche bisogno di una conoscenza precedente della TV.
Come utilizzerai questo tutorial?
Come valuteresti la tua esperienza con la creazione di app per Android?
Come giudichi la tua esperienza con la visione della TV?
2. Recupera il codice campione
Puoi scaricare tutto il codice campione sul tuo computer...
e decomprimi il file ZIP scaricato.
3. Esegui l'app di esempio
Innanzitutto, vediamo come si presenta l'app di esempio completata. L'app è un video player di base. L'utente può selezionare un video da un elenco, quindi riprodurlo localmente sul dispositivo o trasmetterlo a un dispositivo Google Cast.
Una volta scaricato il codice, segui queste istruzioni per aprire ed eseguire l'app di esempio completata in Android Studio:
Seleziona il comando Importa progetto nella schermata di benvenuto o le opzioni di menu File > Nuovo > Importa progetto....
Seleziona la directory app-done
dalla cartella del codice di esempio e fai clic su OK.
Fai clic su File > Sincronizza progetto con file Gradle.
Attiva il debug USB sul tuo dispositivo Android. Su Android 4.2 e versioni successive, la schermata Opzioni sviluppatore è nascosta per impostazione predefinita. Per renderla visibile, vai a Impostazioni > Informazioni sul telefono e tocca Numero build sette volte. Torna alla schermata precedente, vai a Sistema > Avanzate e tocca Opzioni sviluppatore in basso, quindi tocca Debug USB per attivare l'opzione.
Collega il tuo dispositivo Android e fai clic sul pulsante Esegui in Android Studio. Dovresti vedere l'app video Trasmetti video dopo qualche secondo.
Fai clic sul pulsante Trasmetti nell'app video e seleziona il tuo dispositivo Google Cast.
Seleziona un video e fai clic sul pulsante di riproduzione.
La riproduzione del video inizierà sul tuo dispositivo Google Cast.
Verrà visualizzato il controller espanso. Puoi utilizzare il pulsante di riproduzione/pausa per controllare la riproduzione.
Torna all'elenco dei video.
Nella parte inferiore dello schermo è ora visibile un mini controller.
Fai clic sul pulsante di pausa nel mini controller per mettere in pausa il video sul ricevitore. Fai clic sul pulsante di riproduzione del mini controller per continuare a riprodurre il video.
Fai clic sul pulsante Home del dispositivo mobile. Dovresti visualizzare le notifiche menu a discesa per la sessione di trasmissione.
Blocca il telefono e quando lo sblocchi, dovresti vedere una notifica sulla schermata di blocco per controllare la riproduzione dei contenuti multimediali o interrompere la trasmissione.
Torna all'app video e fai clic sul pulsante Trasmetti per interrompere la trasmissione sul dispositivo Google Cast.
Domande frequenti
4. Prepara il progetto di avvio
Dobbiamo aggiungere il supporto per Google Cast all'app iniziale che hai scaricato. Ecco alcuni termini di Google Cast che utilizzeremo in questo codelab:
- L'app mittente sia eseguita su un dispositivo mobile o laptop
- L'app destinatario viene eseguita sul dispositivo Google Cast.
Ora puoi iniziare a sviluppare il progetto iniziale utilizzando Android Studio:
- Seleziona la directory
app-start
dal codice di esempio scaricato (seleziona Importa progetto nella schermata di benvenuto o l'opzione di menu File > Nuovo > Importa progetto...). - Fai clic sul pulsante
Sincronizza progetto con file Gradle.
- Fai clic sul pulsante
Esegui per eseguire l'app ed esplorare l'interfaccia utente.
Progettazione di app
L'app recupera un elenco di video da un server web remoto e fornisce un elenco all'utente. Gli utenti possono selezionare un video per visualizzarne i dettagli oppure riprodurlo localmente sul dispositivo mobile.
L'app è composta da due attività principali: VideoBrowserActivity
e LocalPlayerActivity
. Per integrare le funzionalità di Google Cast, le attività devono ereditare da AppCompatActivity
o dall'elemento principale FragmentActivity
. Questo limite esiste perché dobbiamo aggiungere l'MediaRouteButton
(fornito nella libreria di supporto di MediaRouter) come MediaRouteActionProvider
e questo funziona solo se l'attività eredita dalle classi indicate sopra. La libreria di supporto di MediaRouter dipende dalla libreria di assistenza di AppCompat che fornisce le classi richieste.
Attività del browser video
Questa attività contiene un Fragment
(VideoBrowserFragment
). Questo elenco è supportato da ArrayAdapter
(VideoListAdapter
). L'elenco dei video e i metadati associati sono ospitati su un server remoto come file JSON. Un AsyncTaskLoader
(VideoItemLoader
) recupera questo JSON e lo elabora per creare un elenco di MediaItem
oggetti.
Un oggetto MediaItem
modella un video e i relativi metadati associati, come il titolo, la descrizione, l'URL dello stream, l'URL per le immagini di supporto e le tracce di testo associate (per i sottotitoli) se presenti. L'oggetto MediaItem
viene passato tra le attività, quindi MediaItem
ha metodi di utilità per convertirlo in un Bundle
e viceversa.
Quando il caricatore crea l'elenco di MediaItems
, lo passa all'VideoListAdapter
che quindi presenta l'elenco MediaItems
nell'VideoBrowserFragment
. All'utente viene mostrato un elenco di miniature con una breve descrizione per ogni video. Quando un elemento viene selezionato, l'elemento MediaItem
corrispondente viene convertito in un Bundle
e viene passato a LocalPlayerActivity
.
Attività del player locale
Questa attività visualizza i metadati di un determinato video e consente all'utente di riprodurlo localmente sul dispositivo mobile.
L'attività ospita una VideoView
, alcuni controlli dei contenuti multimediali e un'area di testo per mostrare la descrizione del video selezionato. Il player copre la parte superiore dello schermo, lasciando spazio per la descrizione dettagliata del video sottostante. L'utente può riprodurre/mettere in pausa o cercare la riproduzione locale di video.
Dipendenze
Poiché utilizziamo AppCompatActivity
, abbiamo bisogno della libreria di assistenza di AppCompat. Per gestire l'elenco dei video e ricevere le immagini in modo asincrono, utilizziamo la libreria Volley.
Domande frequenti
5. Aggiungere il pulsante Trasmetti
In un'applicazione compatibile con Google Cast, il pulsante Trasmetti viene visualizzato in ciascuna delle sue attività. Se fai clic sul pulsante Trasmetti, viene visualizzato un elenco di dispositivi di trasmissione che possono essere selezionati da un utente. Se l'utente stava riproducendo i contenuti localmente sul dispositivo di trasmissione, selezionando o avviando la riproduzione di un dispositivo di trasmissione verrà avviata la riproduzione sul dispositivo in questione. Durante una sessione di trasmissione, l'utente può fare clic sul pulsante Trasmetti in qualsiasi momento e interrompere la trasmissione dell'applicazione al dispositivo di trasmissione. L'utente deve essere in grado di connettersi o disconnettersi dal dispositivo di trasmissione durante qualsiasi attività dell'applicazione, come descritto nell'Elenco di controllo per la progettazione di Google Cast.
Dipendenze
Aggiorna il file build.gradle dell'app per includere le dipendenze di libreria necessarie:
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'androidx.mediarouter:mediarouter:1.3.1'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.google.android.gms:play-services-cast-framework:21.1.0'
implementation 'com.android.volley:volley:1.2.1'
implementation "androidx.core:core-ktx:1.8.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
Sincronizza il progetto per confermare le build del progetto senza errori.
Inizializzazione
Il framework Cast ha un oggetto singleton globale, CastContext
, che coordina tutte le interazioni Cast.
Devi implementare l'interfaccia OptionsProvider
per fornire CastOptions
necessario per inizializzare il singleton CastContext
. L'opzione più importante è l'ID applicazione del ricevitore, che viene utilizzato per filtrare i risultati del dispositivo di trasmissione e avviare l'applicazione del ricevitore quando viene avviata una sessione di trasmissione.
Se sviluppi la tua app compatibile con Google Cast, devi registrarti come sviluppatore e poi ottenere un ID applicazione per l'app. Per questo codelab, utilizzeremo un ID app di esempio.
Aggiungi il seguente nuovo file CastOptionsProvider.kt
al pacchetto com.google.sample.cast.refplayer
del progetto:
package com.google.sample.cast.refplayer
import android.content.Context
import com.google.android.gms.cast.framework.OptionsProvider
import com.google.android.gms.cast.framework.CastOptions
import com.google.android.gms.cast.framework.SessionProvider
class CastOptionsProvider : OptionsProvider {
override fun getCastOptions(context: Context): CastOptions {
return CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.build()
}
override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
return null
}
}
Ora dichiara OptionsProvider
nel tag "application
" del file AndroidManifest.xml
dell'app:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />
Inizializza lentamente CastContext
nel metodo onCreate VideoBrowserActivity
:
import com.google.android.gms.cast.framework.CastContext
private var mCastContext: CastContext? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.video_browser)
setupActionBar()
mCastContext = CastContext.getSharedInstance(this)
}
Aggiungi la stessa logica di inizializzazione a LocalPlayerActivity
.
Pulsante Trasmetti
Ora che CastContext
è inizializzato, dobbiamo aggiungere il pulsante Trasmetti per consentire all'utente di selezionare un dispositivo di trasmissione. Il pulsante Trasmetti viene implementato da MediaRouteButton
dalla libreria di supporto MediaRouter. Come per qualsiasi altra azione che puoi aggiungere alle tue attività (utilizzando una ActionBar
o una Toolbar
), devi prima aggiungere al menu la voce del menu corrispondente.
Modifica il file res/menu/browse.xml
e aggiungi la voce MediaRouteActionProvider
nel menu prima della voce delle impostazioni:
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
Esegui l'override del metodo onCreateOptionsMenu()
di VideoBrowserActivity
utilizzando CastButtonFactory
per collegare MediaRouteButton
al framework di trasmissione:
import com.google.android.gms.cast.framework.CastButtonFactory
private var mediaRouteMenuItem: MenuItem? = null
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.browse, menu)
mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu,
R.id.media_route_menu_item)
return true
}
Esegui l'override di onCreateOptionsMenu
in LocalPlayerActivity
in modo simile.
Fai clic sul pulsante Esegui per eseguire l'app sul tuo dispositivo mobile. Dovresti vedere un pulsante Trasmetti nella barra delle azioni dell'app e, quando ci fai clic, vengono elencati i dispositivi di trasmissione sulla tua rete locale. La funzionalità di rilevamento dei dispositivi viene gestita automaticamente dalla
CastContext
. Seleziona il tuo dispositivo di trasmissione per caricare l'app del ricevitore di esempio. Puoi spostarti tra l'attività di navigazione e l'attività locale del player e lo stato del pulsante Trasmetti rimane sincronizzato.
Non abbiamo ancora collegato alcun supporto per la riproduzione di contenuti multimediali, quindi non puoi ancora riprodurre video sul dispositivo di trasmissione. Fai clic sul pulsante Trasmetti per disconnetterti.
6. Trasmissione di contenuti video
Estenderemo l'app di esempio anche per riprodurre video da remoto su un dispositivo di trasmissione. Per farlo, dobbiamo ascoltare i vari eventi generati dal framework Cast.
Trasmissione di contenuti multimediali
In linea generale, se vuoi riprodurre contenuti multimediali su un dispositivo di trasmissione, procedi nel seguente modo:
- Crea un oggetto
MediaInfo
che modella un elemento multimediale. - Connettiti al dispositivo di trasmissione e avvia l'applicazione del ricevitore.
- Carica l'oggetto
MediaInfo
nel ricevitore e riproduci i contenuti. - Monitora lo stato dei contenuti multimediali.
- Invia comandi di riproduzione al ricevitore in base alle interazioni degli utenti.
Abbiamo già eseguito il passaggio 2 nella sezione precedente. Il passaggio 3 è facile da eseguire con il framework di trasmissione. Il passaggio 1 corrisponde alla mappatura di un oggetto a un altro; MediaInfo
è un elemento che il framework Cast comprende e MediaItem
è l'incapsulamento della nostra app per un elemento multimediale; possiamo mappare facilmente un MediaItem
a un MediaInfo
.
L'app di esempio LocalPlayerActivity
già distingue tra riproduzione locale e remota utilizzando questa enumerazione:
private var mLocation: PlaybackLocation? = null
enum class PlaybackLocation {
LOCAL, REMOTE
}
enum class PlaybackState {
PLAYING, PAUSED, BUFFERING, IDLE
}
Non è importante in questo codelab capire esattamente come funziona tutta la logica del player di esempio. È importante comprendere che il media player dell'app deve essere modificato per essere a conoscenza delle due posizioni di riproduzione in modo simile.
Al momento il player locale è sempre in stato di riproduzione locale perché non sa ancora nulla sugli stati di trasmissione. Dobbiamo aggiornare l'UI in base alle transizioni di stato che si verificano nel framework di trasmissione. Ad esempio, se iniziamo a trasmettere, dobbiamo interrompere la riproduzione locale e disattivare alcuni controlli. Analogamente, se interrompiamo la trasmissione quando siamo in questa attività, dobbiamo passare alla riproduzione locale. Per gestirla dobbiamo ascoltare i vari eventi generati dal framework Cast.
Gestione della sessione di trasmissione
Per il framework Cast, una sessione di trasmissione combina i passaggi per la connessione a un dispositivo, l'avvio (o la partecipazione), la connessione a un'applicazione di ricezione e l'inizializzazione di un canale di controllo dei contenuti multimediali, se opportuno. Il canale di controllo dei contenuti multimediali è il modo in cui il framework di trasmissione invia e riceve i messaggi dal lettore multimediale del ricevitore.
La sessione di trasmissione viene avviata automaticamente quando l'utente seleziona un dispositivo dal pulsante Trasmetti e si interrompe automaticamente quando l'utente si disconnette. Anche la riconnessione a una sessione del destinatario a causa di problemi di rete viene gestita automaticamente dall'SDK Cast.
Aggiungiamo un SessionManagerListener
a LocalPlayerActivity
:
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
...
private var mSessionManagerListener: SessionManagerListener<CastSession>? = null
private var mCastSession: CastSession? = null
...
private fun setupCastListener() {
mSessionManagerListener = object : SessionManagerListener<CastSession> {
override fun onSessionEnded(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionResumed(session: CastSession, wasSuspended: Boolean) {
onApplicationConnected(session)
}
override fun onSessionResumeFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionStarted(session: CastSession, sessionId: String) {
onApplicationConnected(session)
}
override fun onSessionStartFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionStarting(session: CastSession) {}
override fun onSessionEnding(session: CastSession) {}
override fun onSessionResuming(session: CastSession, sessionId: String) {}
override fun onSessionSuspended(session: CastSession, reason: Int) {}
private fun onApplicationConnected(castSession: CastSession) {
mCastSession = castSession
if (null != mSelectedMedia) {
if (mPlaybackState == PlaybackState.PLAYING) {
mVideoView!!.pause()
loadRemoteMedia(mSeekbar!!.progress, true)
return
} else {
mPlaybackState = PlaybackState.IDLE
updatePlaybackLocation(PlaybackLocation.REMOTE)
}
}
updatePlayButton(mPlaybackState)
invalidateOptionsMenu()
}
private fun onApplicationDisconnected() {
updatePlaybackLocation(PlaybackLocation.LOCAL)
mPlaybackState = PlaybackState.IDLE
mLocation = PlaybackLocation.LOCAL
updatePlayButton(mPlaybackState)
invalidateOptionsMenu()
}
}
}
Nell'attività LocalPlayerActivity
, ci piacerebbe ricevere una notifica quando siamo connessi o disconnessi dal dispositivo di trasmissione, in modo da poter passare al player locale. Tieni presente che la connettività può essere interrotta non solo dall'istanza della tua applicazione in esecuzione sul tuo dispositivo mobile, ma anche da un'altra istanza della tua (o di un'altra) applicazione in esecuzione su un altro dispositivo mobile.
La sessione attualmente attiva è accessibile come SessionManager.getCurrentSession()
. Le sessioni vengono create e eliminate automaticamente in risposta alle interazioni degli utenti con le finestre di dialogo Trasmetti.
Dobbiamo registrare il listener di sessioni e inizializzare alcune variabili che utilizzeremo nell'attività. Modifica il metodo LocalPlayerActivity
onCreate
in:
import com.google.android.gms.cast.framework.CastContext
...
private var mCastContext: CastContext? = null
...
override fun onCreate(savedInstanceState: Bundle?) {
...
mCastContext = CastContext.getSharedInstance(this)
mCastSession = mCastContext!!.sessionManager.currentCastSession
setupCastListener()
...
loadViews()
...
val bundle = intent.extras
if (bundle != null) {
....
if (shouldStartPlayback) {
....
} else {
if (mCastSession != null && mCastSession!!.isConnected()) {
updatePlaybackLocation(PlaybackLocation.REMOTE)
} else {
updatePlaybackLocation(PlaybackLocation.LOCAL)
}
mPlaybackState = PlaybackState.IDLE
updatePlayButton(mPlaybackState)
}
}
...
}
Caricamento dell'elemento multimediale in corso...
Nell'SDK Cast, RemoteMediaClient
fornisce una serie di pratiche API per gestire la riproduzione dei contenuti multimediali remoti sul ricevitore. Per un CastSession
che supporta la riproduzione di contenuti multimediali, l'istanza crea automaticamente un'istanza di RemoteMediaClient
. È possibile accedervi chiamando il metodo getRemoteMediaClient()
sull'istanza CastSession
. Aggiungi i seguenti metodi a LocalPlayerActivity
per caricare il video attualmente selezionato sul ricevitore:
import com.google.android.gms.cast.framework.media.RemoteMediaClient
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaLoadOptions
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.common.images.WebImage
import com.google.android.gms.cast.MediaLoadRequestData
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
if (mCastSession == null) {
return
}
val remoteMediaClient = mCastSession!!.remoteMediaClient ?: return
remoteMediaClient.load( MediaLoadRequestData.Builder()
.setMediaInfo(buildMediaInfo())
.setAutoplay(autoPlay)
.setCurrentTime(position.toLong()).build())
}
private fun buildMediaInfo(): MediaInfo? {
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
mSelectedMedia?.studio?.let { movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, it) }
mSelectedMedia?.title?.let { movieMetadata.putString(MediaMetadata.KEY_TITLE, it) }
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(0))))
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(1))))
return mSelectedMedia!!.url?.let {
MediaInfo.Builder(it)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType("videos/mp4")
.setMetadata(movieMetadata)
.setStreamDuration((mSelectedMedia!!.duration * 1000).toLong())
.build()
}
}
Aggiorna vari metodi esistenti per usare la logica della sessione di trasmissione per supportare la riproduzione da remoto:
private fun play(position: Int) {
startControllersTimer()
when (mLocation) {
PlaybackLocation.LOCAL -> {
mVideoView!!.seekTo(position)
mVideoView!!.start()
}
PlaybackLocation.REMOTE -> {
mPlaybackState = PlaybackState.BUFFERING
updatePlayButton(mPlaybackState)
//seek to a new position within the current media item's new position
//which is in milliseconds from the beginning of the stream
mCastSession!!.remoteMediaClient?.seek(position.toLong())
}
else -> {}
}
restartTrickplayTimer()
}
private fun togglePlayback() {
...
PlaybackState.IDLE -> when (mLocation) {
...
PlaybackLocation.REMOTE -> {
if (mCastSession != null && mCastSession!!.isConnected) {
loadRemoteMedia(mSeekbar!!.progress, true)
}
}
else -> {}
}
...
}
override fun onPause() {
...
mCastContext!!.sessionManager.removeSessionManagerListener(
mSessionManagerListener!!, CastSession::class.java)
}
override fun onResume() {
Log.d(TAG, "onResume() was called")
mCastContext!!.sessionManager.addSessionManagerListener(
mSessionManagerListener!!, CastSession::class.java)
if (mCastSession != null && mCastSession!!.isConnected) {
updatePlaybackLocation(PlaybackLocation.REMOTE)
} else {
updatePlaybackLocation(PlaybackLocation.LOCAL)
}
super.onResume()
}
Per il metodo updatePlayButton
, modifica il valore della variabile isConnected
:
private fun updatePlayButton(state: PlaybackState?) {
...
val isConnected = (mCastSession != null
&& (mCastSession!!.isConnected || mCastSession!!.isConnecting))
...
}
Ora, fai clic sul pulsante Esegui per eseguire l'app sul tuo dispositivo mobile. Collegati al tuo dispositivo di trasmissione e inizia a riprodurre un video. Dovresti vedere il video in riproduzione sul ricevitore.
7. Mini controller
L'elenco di controllo per la trasmissione dei contenuti richiede che tutte le app di trasmissione forniscano un mini controller che venga visualizzato quando l'utente esce dalla pagina dei contenuti corrente. Il mini controller fornisce l'accesso istantaneo e un promemoria visibile per la sessione di trasmissione corrente.
L'SDK Cast offre una visualizzazione personalizzata, MiniControllerFragment
, che può essere aggiunta al file di layout dell'app delle attività in cui vuoi mostrare il mini controller.
Aggiungi la seguente definizione di frammento alla fine di res/layout/player_activity.xml
e res/layout/video_browser.xml
:
<fragment
android:id="@+id/castMiniController"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="gone"
class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment"/>
Fai clic sul pulsante Esegui per eseguire l'app e trasmettere un video. Quando inizia la riproduzione sul ricevitore, dovresti vedere il mini controller nella parte inferiore di ogni attività. Puoi controllare la riproduzione da remoto utilizzando il mini controller. Se passi dall'attività di esplorazione all'attività locale del player, lo stato del mini controller deve rimanere sincronizzato con lo stato di riproduzione dei contenuti multimediali del ricevitore.
8. Notifica e schermata di blocco
L'elenco di controllo per la progettazione di Google Cast richiede un'app del mittente per implementare i controlli multimediali da una notifica e dalla schermata di blocco.
L'SDK Cast fornisce una MediaNotificationService
che consente all'app del mittente di creare controlli multimediali per la notifica e la schermata di blocco. Il servizio viene unito automaticamente al manifest dell'app in base al grado.
L'MediaNotificationService
verrà eseguito in background quando il mittente trasmette, mostrando una notifica con una miniatura dell'immagine e i metadati sull'elemento corrente, un pulsante per riprodurre/mettere in pausa e un pulsante per l'interruzione.
I controlli delle notifiche e della schermata di blocco possono essere attivati con CastOptions
durante l'inizializzazione di CastContext
. I controlli dei contenuti multimediali per la notifica e la schermata di blocco sono attivi per impostazione predefinita. La funzionalità di blocco schermo è attiva purché la notifica sia attiva.
Modifica CastOptionsProvider
e modifica l'implementazione di getCastOptions
in modo che corrisponda a questo codice:
import com.google.android.gms.cast.framework.media.CastMediaOptions
import com.google.android.gms.cast.framework.media.NotificationOptions
override fun getCastOptions(context: Context): CastOptions {
val notificationOptions = NotificationOptions.Builder()
.setTargetActivityClassName(VideoBrowserActivity::class.java.name)
.build()
val mediaOptions = CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.build()
return CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.setCastMediaOptions(mediaOptions)
.build()
}
Fai clic sul pulsante Esegui per eseguire l'app sul tuo dispositivo mobile. Trasmetti un video e esci dall'app di esempio. Dovresti ricevere una notifica relativa al video attualmente in riproduzione sul ricevitore. Se blocchi il dispositivo mobile, ora dovresti vedere i controlli per la riproduzione di contenuti multimediali sul dispositivo di trasmissione nella schermata di blocco.
9. Overlay introduttivo
L'elenco di controllo per la progettazione di Google Cast richiede che l'app del mittente presenti il pulsante Trasmetti agli utenti esistenti per informarli che l'app del mittente supporta la trasmissione e aiuta anche gli utenti nuovi.
L'SDK Cast offre una visualizzazione personalizzata, IntroductoryOverlay
, che può essere utilizzata per mettere in evidenza il pulsante Trasmetti quando viene mostrato per la prima volta agli utenti. Aggiungi il codice seguente a VideoBrowserActivity
:
import com.google.android.gms.cast.framework.IntroductoryOverlay
import android.os.Looper
private var mIntroductoryOverlay: IntroductoryOverlay? = null
private fun showIntroductoryOverlay() {
mIntroductoryOverlay?.remove()
if (mediaRouteMenuItem?.isVisible == true) {
Looper.myLooper().run {
mIntroductoryOverlay = com.google.android.gms.cast.framework.IntroductoryOverlay.Builder(
this@VideoBrowserActivity, mediaRouteMenuItem!!)
.setTitleText("Introducing Cast")
.setSingleTime()
.setOnOverlayDismissedListener(
object : IntroductoryOverlay.OnOverlayDismissedListener {
override fun onOverlayDismissed() {
mIntroductoryOverlay = null
}
})
.build()
mIntroductoryOverlay!!.show()
}
}
}
Ora aggiungi una classe CastStateListener
e chiama il metodo showIntroductoryOverlay
quando è disponibile un dispositivo di trasmissione modificando il metodo onCreate
e sostituendo i metodi onResume
e onPause
in modo che corrispondano a quanto segue:
import com.google.android.gms.cast.framework.CastState
import com.google.android.gms.cast.framework.CastStateListener
private var mCastStateListener: CastStateListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.video_browser)
setupActionBar()
mCastStateListener = object : CastStateListener {
override fun onCastStateChanged(newState: Int) {
if (newState != CastState.NO_DEVICES_AVAILABLE) {
showIntroductoryOverlay()
}
}
}
mCastContext = CastContext.getSharedInstance(this)
}
override fun onResume() {
super.onResume()
mCastContext?.addCastStateListener(mCastStateListener!!)
}
override fun onPause() {
super.onPause()
mCastContext?.removeCastStateListener(mCastStateListener!!)
}
Cancella i dati dell'app o rimuovila dal tuo dispositivo. Successivamente, fai clic sul pulsante Esegui per eseguire l'app sul tuo dispositivo mobile. Dovresti vedere l'overlay introduttivo (cancella i dati dell'app se non viene visualizzato).
10. Controller espanso
L'elenco di controllo per la progettazione di Google Cast richiede che l'app del mittente fornisca un controller espanso per i contenuti multimediali trasmessi. Il controller espanso è una versione a schermo intero del mini controller.
L'SDK Cast fornisce un widget per il controller espanso denominato ExpandedControllerActivity
. Questa è una classe astratta che devi aggiungere a una sottoclasse per aggiungere un pulsante Trasmetti.
Innanzitutto crea un nuovo file di risorse di menu, denominato expanded_controller.xml
, affinché il controller espanso fornisca il pulsante Trasmetti:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
</menu>
Crea un nuovo pacchetto expandedcontrols
nel pacchetto com.google.sample.cast.refplayer
. Successivamente, crea un nuovo file denominato ExpandedControlsActivity.kt
nel pacchetto com.google.sample.cast.refplayer.expandedcontrols
.
package com.google.sample.cast.refplayer.expandedcontrols
import android.view.Menu
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
import com.google.sample.cast.refplayer.R
import com.google.android.gms.cast.framework.CastButtonFactory
class ExpandedControlsActivity : ExpandedControllerActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.expanded_controller, menu)
CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item)
return true
}
}
Ora ExpandedControlsActivity
deve essere dichiarato in AndroidManifest.xml
all'interno del tag application
sopra OPTIONS_PROVIDER_CLASS_NAME
:
<application>
...
<activity
android:name="com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.CastVideosDark"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.google.sample.cast.refplayer.VideoBrowserActivity"/>
</activity>
...
</application>
Modifica CastOptionsProvider
e NotificationOptions
e CastMediaOptions
per impostare l'attività target su ExpandedControlsActivity
:
import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity
override fun getCastOptions(context: Context): CastOptions {
val notificationOptions = NotificationOptions.Builder()
.setTargetActivityClassName(ExpandedControlsActivity::class.java.name)
.build()
val mediaOptions = CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name)
.build()
return CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.setCastMediaOptions(mediaOptions)
.build()
}
Aggiorna il metodo LocalPlayerActivity
loadRemoteMedia
per visualizzare ExpandedControlsActivity
quando viene caricato il supporto remoto:
import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
if (mCastSession == null) {
return
}
val remoteMediaClient = mCastSession!!.remoteMediaClient ?: return
remoteMediaClient.registerCallback(object : RemoteMediaClient.Callback() {
override fun onStatusUpdated() {
val intent = Intent(this@LocalPlayerActivity, ExpandedControlsActivity::class.java)
startActivity(intent)
remoteMediaClient.unregisterCallback(this)
}
})
remoteMediaClient.load(MediaLoadRequestData.Builder()
.setMediaInfo(buildMediaInfo())
.setAutoplay(autoPlay)
.setCurrentTime(position.toLong()).build())
}
Fai clic sul pulsante Esegui per eseguire l'app sul tuo dispositivo mobile e trasmettere un video. Dovresti vedere il controller espanso. Torna all'elenco dei video e, quando fai clic sul mini controller, questo verrà caricato di nuovo. Esci dall'app per visualizzare la notifica. Fai clic sull'immagine della notifica per caricare il controller espanso.
11. Aggiungi il supporto per Cast Connect
La raccolta di Cast Connect consente alle applicazioni esistenti dei mittenti di comunicare con le applicazioni Android TV tramite il protocollo Cast. Cast Connect si basa sull'infrastruttura di trasmissione e la tua app per Android TV funge da ricevitore.
Dipendenze
Nota: per l'implementazione di Cast Connect, il play-services-cast-framework
deve essere 19.0.0
o superiore.
Opzioni di lancio
Per poter lanciare l'applicazione Android TV, chiamata anche Ricevitore Android, dobbiamo impostare il flag setAndroidReceiverCompatible
su true nell'oggetto LaunchOptions
. L'oggetto LaunchOptions
determina la modalità di avvio del destinatario e viene passato all'oggetto CastOptions
restituito dalla classe CastOptionsProvider
. Se imposti il flag indicato sopra su false
, in Cast Console verrà avviato il ricevitore web per l'ID app definito.
Nel file CastOptionsProvider.kt
, aggiungi quanto segue al metodo getCastOptions
:
import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
.setAndroidReceiverCompatible(true)
.build()
return new CastOptions.Builder()
.setLaunchOptions(launchOptions)
...
.build()
Imposta credenziali di lancio
Per il mittente, puoi specificare CredentialsData
per indicare chi partecipa alla sessione. credentials
è una stringa che può essere definita dall'utente, purché l'app ATV possa riconoscerla. Il CredentialsData
viene trasmesso alla tua app Android TV soltanto al momento del lancio o durante la registrazione. Se lo imposti di nuovo mentre sei connesso, non verrà trasmesso all'app Android TV.
Per impostare le credenziali di lancio, CredentialsData
deve essere definito e passato all'oggetto LaunchOptions
. Aggiungi il codice seguente al metodo getCastOptions
nel file CastOptionsProvider.kt
:
import com.google.android.gms.cast.CredentialsData
...
val credentialsData = CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build()
val launchOptions = LaunchOptions.Builder()
...
.setCredentialsData(credentialsData)
.build()
Imposta credenziali su LoadRequest
Se l'app ricevitore web e l'app Android TV gestiscono credentials
in modo diverso, potrebbe essere necessario definire credentials
separatamente per ciascuno di essi. Per risolvere questo problema, aggiungi il seguente codice nel file LocalPlayerActivity.kt
nella funzione loadRemoteMedia
:
remoteMediaClient.load(MediaLoadRequestData.Builder()
...
.setCredentials("user-credentials")
.setAtvCredentials("atv-user-credentials")
.build())
A seconda dell'app del destinatario a cui viene trasmesso il mittente, l'SDK gestisce automaticamente le credenziali da utilizzare per la sessione corrente.
Test di Cast Connect
Procedura per installare l'APK Android TV su Chromecast con Google TV
- Trova l'indirizzo IP del tuo dispositivo Android TV. Di solito è disponibile in Impostazioni > Rete e Internet > (Nome della rete a cui è connesso il dispositivo). A destra vengono visualizzati i dettagli e l'IP del dispositivo sulla rete.
- Utilizza l'indirizzo IP del dispositivo per stabilire la connessione tramite ADB utilizzando il terminale:
$ adb connect <device_ip_address>:5555
- Dalla finestra del terminale, vai alla cartella di primo livello per gli esempi di codelab che hai scaricato all'inizio. Ad esempio:
$ cd Desktop/android_codelab_src
- Installa il file .apk in questa cartella su Android TV eseguendo questo comando:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Ora dovresti riuscire a vedere un'app chiamata Trasmetti video nel menu Le tue app del tuo dispositivo Android TV.
- Torna al tuo progetto Android Studio e fai clic sul pulsante Esegui per installare ed eseguire l'app del mittente sul tuo dispositivo mobile fisico. Fai clic sull'icona di trasmissione nell'angolo in alto a destra e seleziona il tuo dispositivo Android TV dalle opzioni disponibili. A questo punto dovresti vedere l'app Android TV avviata sul tuo dispositivo Android TV e riprodurre un video dovrebbe consentirti di controllare la riproduzione del video usando il telecomando di Android TV.
12. Personalizza i widget di trasmissione
Puoi personalizzare i widget di trasmissione impostando i colori, assegnando uno stile ai pulsanti, al testo e alle miniature e scegliendo i tipi di pulsanti da visualizzare.
Aggiorna res/values/styles_castvideo.xml
<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
...
<item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
<item name="castIntroOverlayStyle">@style/CustomCastIntroOverlay</item>
<item name="castMiniControllerStyle">@style/CustomCastMiniController</item>
<item name="castExpandedControllerStyle">@style/CustomCastExpandedController</item>
<item name="castExpandedControllerToolbarStyle">
@style/ThemeOverlay.AppCompat.ActionBar
</item>
...
</style>
Dichiara i seguenti temi personalizzati:
<!-- Customize Cast Button -->
<style name="CustomMediaRouterTheme" parent="Theme.MediaRouter">
<item name="mediaRouteButtonStyle">@style/CustomMediaRouteButtonStyle</item>
</style>
<style name="CustomMediaRouteButtonStyle" parent="Widget.MediaRouter.Light.MediaRouteButton">
<item name="mediaRouteButtonTint">#EEFF41</item>
</style>
<!-- Customize Introductory Overlay -->
<style name="CustomCastIntroOverlay" parent="CastIntroOverlay">
<item name="castButtonTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Button</item>
<item name="castTitleTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Title</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Button" parent="android:style/TextAppearance">
<item name="android:textColor">#FFFFFF</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Title" parent="android:style/TextAppearance.Large">
<item name="android:textColor">#FFFFFF</item>
</style>
<!-- Customize Mini Controller -->
<style name="CustomCastMiniController" parent="CastMiniController">
<item name="castShowImageThumbnail">true</item>
<item name="castTitleTextAppearance">@style/TextAppearance.AppCompat.Subhead</item>
<item name="castSubtitleTextAppearance">@style/TextAppearance.AppCompat.Caption</item>
<item name="castBackground">@color/accent</item>
<item name="castProgressBarColor">@color/orange</item>
</style>
<!-- Customize Expanded Controller -->
<style name="CustomCastExpandedController" parent="CastExpandedController">
<item name="castButtonColor">#FFFFFF</item>
<item name="castPlayButtonDrawable">@drawable/cast_ic_expanded_controller_play</item>
<item name="castPauseButtonDrawable">@drawable/cast_ic_expanded_controller_pause</item>
<item name="castStopButtonDrawable">@drawable/cast_ic_expanded_controller_stop</item>
</style>
13. Congratulazioni
Ora sai come attivare un'app video con Google Cast usando i widget SDK di trasmissione su Android.
Per maggiori dettagli, consulta la guida per gli sviluppatori di Android Sender.