Interruzioni pubblicitarie
L'SDK Android Sender fornisce supporto per le interruzioni pubblicitarie e gli annunci companion all'interno di un determinato stream multimediale.
Per ulteriori informazioni sul funzionamento delle interruzioni pubblicitarie, consulta la Panoramica delle interruzioni pubblicitarie del ricevitore web.
Anche se è possibile specificare le interruzioni sia sul mittente sia sul destinatario, è consigliabile specificarle sul ricevitore web e sul ricevitore Android TV per mantenere un comportamento coerente tra le varie piattaforme.
Su Android, specifica le interruzioni pubblicitarie in un comando di caricamento utilizzando AdBreakClipInfo
e AdBreakInfo
:
val breakClip1: AdBreakClipInfo = AdBreakClipInfo.Builder("bc0") .setTitle("Clip title") .setPosterUrl("https://www.some.url") .setDuration(60000) .setWhenSkippableInMs(5000) // Set this field so that the ad is skippable .build() val breakClip2: AdBreakClipInfo = … val breakClip3: AdBreakClipInfo = … val break1: AdBreakClipInfo = AdBreakInfo.Builder(/* playbackPositionInMs= */ 10000) .setId("b0") .setBreakClipIds({"bc0","bc1","bc2"}) … .build() val mediaInfo: MediaInfo = MediaInfo.Builder() … .setAdBreaks({break1}) .setAdBreakClips({breakClip1, breakClip2, breakClip3}) .build() val mediaLoadRequestData: MediaLoadRequestData = MediaInfo.Builder() … .setMediaInfo(mediaInfo) .build() remoteMediaClient.load(mediaLoadRequestData)
AdBreakClipInfo breakClip1 = new AdBreakClipInfo.Builder("bc0") .setTitle("Clip title") .setPosterUrl("https://www.some.url") .setDuration(60000) .setWhenSkippableInMs(5000) // Set this field so that the ad is skippable .build(); AdBreakClipInfo breakClip2 = … AdBreakClipInfo breakClip3 = … AdBreakInfo break1 = new AdBreakInfo.Builder(/* playbackPositionInMs= */ 10000) .setId("b0") .setBreakClipIds({"bc0","bc1","bc2"}) … .build(); MediaInfo mediaInfo = new MediaInfo.Builder() … .setAdBreaks({break1}) .setAdBreakClips({breakClip1, breakClip2, breakClip3}) .build(); MediaLoadRequestData mediaLoadRequestData = new MediaInfo.Builder() … .setMediaInfo(mediaInfo) .build(); remoteMediaClient.load(mediaLoadRequestData);
Aggiungi azioni personalizzate
Un'app del mittente può estendere MediaIntentReceiver
per gestire azioni personalizzate o sovrascrivere il suo comportamento. Se hai implementato il tuo
MediaIntentReceiver
, devi aggiungerlo al file manifest e impostare il suo
nome nel CastMediaOptions
. Questo esempio fornisce azioni personalizzate che eseguono l'override della riproduzione da remoto dei contenuti multimediali, premendo il pulsante dei contenuti multimediali e altri tipi di azioni.
// In AndroidManifest.xml
<receiver android:name="com.example.MyMediaIntentReceiver" />
// In your OptionsProvider var mediaOptions = CastMediaOptions.Builder() .setMediaIntentReceiverClassName(MyMediaIntentReceiver::class.java.name) .build() // Implementation of MyMediaIntentReceiver internal class MyMediaIntentReceiver : MediaIntentReceiver() { override fun onReceiveActionTogglePlayback(currentSession: Session) { } override fun onReceiveActionMediaButton(currentSession: Session, intent: Intent) { } override fun onReceiveOtherAction(context: Context?, action: String, intent: Intent) { } }
// In your OptionsProvider CastMediaOptions mediaOptions = new CastMediaOptions.Builder() .setMediaIntentReceiverClassName(MyMediaIntentReceiver.class.getName()) .build(); // Implementation of MyMediaIntentReceiver class MyMediaIntentReceiver extends MediaIntentReceiver { @Override protected void onReceiveActionTogglePlayback(Session currentSession) { } @Override protected void onReceiveActionMediaButton(Session currentSession, Intent intent) { } @Override protected void onReceiveOtherAction(Context context, String action, Intent intent) { } }
Aggiungi un canale personalizzato
Affinché l'app del mittente possa comunicare con l'app del destinatario, l'app deve creare un canale personalizzato. Il mittente può usare il canale personalizzato
per inviare messaggi stringa al destinatario. Ogni canale personalizzato è definito da uno spazio dei nomi univoco e deve iniziare con il prefisso urn:x-cast:
, ad esempio urn:x-cast:com.example.custom
. È possibile avere più canali personalizzati, ciascuno con uno spazio dei nomi univoco. L'app ricevente può anche
inviare e ricevere messaggi
utilizzando lo stesso spazio dei nomi.
Il canale personalizzato è implementato con l'interfaccia Cast.MessageReceivedCallback
:
class HelloWorldChannel : MessageReceivedCallback { val namespace: String get() = "urn:x-cast:com.example.custom" override fun onMessageReceived(castDevice: CastDevice, namespace: String, message: String) { Log.d(TAG, "onMessageReceived: $message") } }
class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return "urn:x-cast:com.example.custom"; } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { Log.d(TAG, "onMessageReceived: " + message); } }
Una volta che l'app del mittente è collegata all'app del destinatario, puoi creare il canale personalizzato utilizzando il metodo setMessageReceivedCallbacks
:
try { mCastSession.setMessageReceivedCallbacks( mHelloWorldChannel.namespace, mHelloWorldChannel) } catch (e: IOException) { Log.e(TAG, "Exception while creating channel", e) }
try { mCastSession.setMessageReceivedCallbacks( mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }
Una volta creato il canale personalizzato, il mittente può utilizzare il metodo sendMessage
per inviare messaggi stringa al destinatario tramite quel canale:
private fun sendMessage(message: String) { if (mHelloWorldChannel != null) { try { mCastSession.sendMessage(mHelloWorldChannel.namespace, message) .setResultCallback { status -> if (!status.isSuccess) { Log.e(TAG, "Sending message failed") } } } catch (e: Exception) { Log.e(TAG, "Exception while sending message", e) } } }
private void sendMessage(String message) { if (mHelloWorldChannel != null) { try { mCastSession.sendMessage(mHelloWorldChannel.getNamespace(), message) .setResultCallback( status -> { if (!status.isSuccess()) { Log.e(TAG, "Sending message failed"); } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } } }
Supporto della riproduzione automatica
Consulta la sezione API Riproduzione automatica e accodamento.
Sostituisci la selezione delle immagini per i widget UX
I vari componenti del framework (ovvero la finestra di dialogo Trasmetti, il mini
controller e il UIMediaController, se configurato) mostreranno l'artwork
per i contenuti multimediali attualmente trasmessi. Gli URL dell'artwork dell'immagine sono in genere inclusi nell'MediaMetadata
per i contenuti multimediali, ma l'app mittente potrebbe avere una fonte alternativa per gli URL.
La classe ImagePicker
definisce un mezzo per selezionare un'immagine appropriata dall'elenco di immagini in un MediaMetadata
, in base all'utilizzo dell'immagine, ad esempio la miniatura di notifica o lo sfondo a schermo intero. L'implementazione predefinita di ImagePicker
sceglie sempre la prima immagine oppure restituisce un valore nullo se non è disponibile nessuna immagine in
MediaMetadata
. La tua app può creare una sottoclasse ImagePicker
e sostituire il metodo
onPickImage(MediaMetadata, ImageHints)
per fornire un'implementazione alternativa, quindi selezionare quella sottoclasse
con il metodo
setImagePicker
CastMediaOptions.Builder
.
ImageHints
fornisce suggerimenti a ImagePicker
sul tipo e sulle dimensioni di un'immagine da
selezionare per la visualizzazione nella UI.
Personalizzazione delle finestre di dialogo di trasmissione
Gestione del ciclo di vita delle sessioni
SessionManager
è la posizione centrale per la gestione del ciclo di vita delle sessioni. SessionManager
ascolta
le modifiche allo stato di selezione dei percorsi
di Android
MediaRouter
per avviare, riprendere e terminare le sessioni. Quando viene selezionata una route, SessionManager
crea un oggetto Session
e prova ad avviarlo o a riprenderlo. Quando un percorso non è selezionato, SessionManager
terminerà la sessione corrente.
Di conseguenza, per assicurarti che SessionManager
gestisca correttamente i cicli di vita delle sessioni, devi assicurarti che:
- Nella finestra di dialogo del selettore del percorso, chiama
MediaRouter.selectRoute(MediaRouter.RouteInfo)
quando un utente seleziona un dispositivo. - Nella finestra di dialogo del controller di route (in stato
connesso o
stato
di trasmissione),
chiama
MediaRouter.unselect(int)
quando l'utente smette di trasmettere.
A seconda di come crei le finestre di dialogo Trasmetti, potrebbero essere necessarie ulteriori azioni:
- Se crei finestre di dialogo di trasmissione utilizzando
MediaRouteChooserDialog
eMediaRouteControllerDialog
, queste aggiorneranno automaticamente la selezione del percorso inMediaRouter
, quindi non dovrai fare nulla. - Se configuri il pulsante Trasmetti utilizzando
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
oCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
, le finestre di dialogo vengono effettivamente create utilizzandoMediaRouteChooserDialog
eMediaRouteControllerDialog
, quindi non devi fare nulla. - In altri casi, stai creando finestre di dialogo di trasmissione personalizzate, quindi devi
seguire le istruzioni precedenti per aggiornare lo stato di selezione della route in
MediaRouter
.
Stato zero dispositivi
Se crei finestre di dialogo Trasmetti personalizzate, il tuo MediaRouteChooserDialog
personalizzato dovrebbe gestire correttamente la presenza di zero dispositivi. La finestra di dialogo dovrebbe contenere indicatori che indicano agli utenti quando
l'app sta ancora cercando di trovare i dispositivi e quando il tentativo di rilevamento non è
più attivo.
Se utilizzi l'impostazione predefinita MediaRouteChooserDialog
, lo stato con zero dispositivi è già gestito.
Passaggi successivi
Con questo si concluderanno le funzionalità che puoi aggiungere all'app mittente Android. Ora puoi creare un'app mittente per un'altra piattaforma (iOS o web) oppure creare un'app di ricezione web.