Interruzioni pubblicitarie
L'SDK Android Sender fornisce supporto per le interruzioni pubblicitarie e gli annunci companion all'interno di un determinato flusso multimediale.
Per saperne di più su come funzionano le interruzioni pubblicitarie, consulta la Panoramica delle interruzioni pubblicitarie di Web Receiver.
Anche se le interruzioni possono essere specificate sia sul mittente che sul destinatario, è consigliabile specificarle sul ricevitore web e sul ricevitore Android TV per mantenere un comportamento coerente su tutte le 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);
Aggiungere azioni personalizzate
Un'app mittente può estendere
MediaIntentReceiver
per gestire azioni personalizzate o sostituire il suo comportamento. Se hai implementato il tuo
MediaIntentReceiver
, devi aggiungerlo al manifest e impostarne il
nome in CastMediaOptions
. Questo esempio fornisce azioni personalizzate che
eseguono l'override dell'attivazione/disattivazione della riproduzione di contenuti multimediali da remoto, della pressione del pulsante multimediale e di 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) { } }
Aggiungere un canale personalizzato
Affinché l'app mittente possa comunicare con l'app destinataria, la tua app deve
creare un canale personalizzato. Il mittente può utilizzare 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 ricevitore può anche
inviare e ricevere messaggi
utilizzando lo stesso spazio dei nomi.
Il canale personalizzato viene 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 collegata l'app mittente all'app destinataria, il canale personalizzato può
essere creato 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 di riproduzione automatica e accodamento.
Eseguire l'override della selezione delle immagini per i widget UX
Vari componenti del framework (ovvero la finestra di dialogo di Cast, il mini
controller e UIMediaController, se configurato) mostreranno la copertina
dei contenuti multimediali in fase di trasmissione. Gli URL delle illustrazioni delle immagini sono in genere
inclusi in MediaMetadata
per i contenuti multimediali, ma l'app mittente potrebbe avere
un'origine 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 miniatura
di notifica o sfondo a schermo intero. L'implementazione predefinita di ImagePicker
sceglie sempre la prima immagine o restituisce null se non è disponibile alcuna immagine in
MediaMetadata
. La tua app può creare una sottoclasse di ImagePicker
ed eseguire l'override del metodo
onPickImage(MediaMetadata, ImageHints)
per fornire un'implementazione alternativa, quindi selezionare la sottoclasse
con il metodo
setImagePicker
di CastMediaOptions.Builder
.
ImageHints
fornisce suggerimenti a un ImagePicker
sul tipo e sulle dimensioni di un'immagine da
selezionare per la visualizzazione nell'interfaccia utente.
Personalizzare le finestre di dialogo di Cast
Gestione del ciclo di vita della sessione
SessionManager
è la posizione centrale per la gestione del ciclo di vita della sessione. SessionManager
ascolta
Android
MediaRouter
le modifiche dello stato di selezione del percorso per avviare, riprendere e terminare le sessioni. Quando viene selezionato un percorso, SessionManager
crea un oggetto Session
e tenta di avviarlo o riprenderlo. Quando un percorso viene deselezionato,
SessionManager
terminerà la sessione corrente.
Pertanto, per garantire che SessionManager
gestisca correttamente i cicli di vita delle sessioni, devi assicurarti che:
- Nella finestra di dialogo del selettore di route,
chiama
MediaRouter.selectRoute(MediaRouter.RouteInfo)
quando un utente seleziona un dispositivo. - Nella finestra di dialogo del controller del percorso (nello stato
connesso o
stato
trasmissione),
chiama
MediaRouter.unselect(int)
quando l'utente interrompe la trasmissione.
A seconda di come crei le finestre di dialogo di trasmissione, potrebbero essere necessarie ulteriori azioni:
- Se crei dialoghi di trasmissione utilizzando
MediaRouteChooserDialog
eMediaRouteControllerDialog
, la selezione delle route inMediaRouter
verrà aggiornata automaticamente, quindi non è necessario fare nulla. - Se hai configurato il pulsante Trasmetti utilizzando
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
oCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
, le finestre di dialogo vengono create utilizzandoMediaRouteChooserDialog
eMediaRouteControllerDialog
, quindi non è necessario fare nulla. - Per gli altri casi, creerai finestre di dialogo di trasmissione personalizzate, quindi devi
seguire le istruzioni riportate sopra per aggiornare lo stato di selezione dell'itinerario in
MediaRouter
.
Stato zero dispositivi
Se crei finestre di dialogo di trasmissione personalizzate, il tuo
MediaRouteChooserDialog
deve gestire correttamente il caso in cui non vengono trovati
dispositivi. La finestra di dialogo deve contenere indicatori che mostrino chiaramente agli utenti quando l'app sta ancora tentando di trovare dispositivi e quando il tentativo di rilevamento non è più attivo.
Se utilizzi MediaRouteChooserDialog
predefinito, lo stato zero dispositivi
è già gestito.
Passaggi successivi
Con questo si concludono le funzionalità che puoi aggiungere all'app mittente per Android. Ora puoi creare un'app mittente per un'altra piattaforma (iOS o web) oppure creare un'app Web Receiver.