Interruzioni pubblicitarie
L'SDK Android Sender fornisce il supporto per le interruzioni pubblicitarie e gli annunci companion all'interno di un determinato stream multimediale.
Per ulteriori informazioni su come funzionano le interruzioni pubblicitarie, consulta la panoramica delle interruzioni pubblicitarie del ricevitore web.
Sebbene le interruzioni possano essere specificate sia sul mittente sia sul ricevitore, è consigliabile specificarle sul ricevitore web e sul ricevitore Android TV per mantenere un comportamento coerente tra 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 sostituiscono l'attivazione/disattivazione della riproduzione di contenuti multimediali remoti, la pressione del pulsante multimediale 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) { } }
Aggiungere un canale personalizzato
Affinché l'app mittente possa comunicare con l'app ricevitore, la tua app deve creare un canale personalizzato. Il mittente può utilizzare il canale personalizzato per inviare messaggi stringa al ricevitore. 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, ognuno 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'
Cast.MessageReceivedCallback
interfaccia:
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 mittente è connessa all'app ricevitore, il canale personalizzato può
essere creato utilizzando il
setMessageReceivedCallbacks
metodo:
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
sendMessage
metodo per inviare messaggi stringa al ricevitore 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); } } }
Supportare la riproduzione automatica
Consulta la sezione API di riproduzione automatica e accodamento.
Sostituire la selezione delle immagini per i widget dell'esperienza utente
Vari componenti del framework (in particolare la finestra di dialogo Cast, il mini controller e UIMediaController, se configurato) mostreranno la grafica dei contenuti multimediali attualmente trasmessi. In genere, gli URL della grafica delle immagini sono inclusi in MediaMetadata per i contenuti multimediali, ma l'app mittente potrebbe avere un'origine alternativa per gli URL.
La
ImagePicker
classe 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 della notifica
o lo 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 e sostituire il
onPickImage(MediaMetadata, ImageHints)
metodo per fornire un'implementazione alternativa, quindi selezionare la sottoclasse
con il
setImagePicker
metodo di CastMediaOptions.Builder.
ImageHints
fornisce suggerimenti a ImagePicker sul tipo e sulle dimensioni di un'immagine da selezionare per la visualizzazione nell'interfaccia utente.
Personalizzare le finestre di dialogo Cast
Gestire il ciclo di vita della sessione
SessionManager
è il punto centrale per la gestione del ciclo di vita della sessione. SessionManager ascolta
le modifiche dello stato di selezione della route
MediaRouter
di Android per avviare, riprendere e terminare le sessioni. Quando viene selezionata una route, SessionManager crea un oggetto
Session
e tenta di avviarlo o riprenderlo. Quando una route non è selezionata, SessionManager termina la sessione corrente.
Pertanto, per assicurarti 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 di route (nello stato connesso
o nello stato
di trasmissione),
chiama
MediaRouter.unselect(int)quando l'utente interrompe la trasmissione.
A seconda di come crei le finestre di dialogo Cast, potrebbero essere necessarie ulteriori azioni:
- Se crei finestre di dialogo Cast utilizzando
MediaRouteChooserDialogeMediaRouteControllerDialog, queste finestre di dialogo aggiorneranno automaticamente la selezione della route inMediaRouter, quindi non è necessario fare nulla. - Se configuri il pulsante Trasmetti utilizzando
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)oCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton), le finestre di dialogo vengono create utilizzandoMediaRouteChooserDialogeMediaRouteControllerDialog, quindi non è necessario fare nulla. - In altri casi, creerai finestre di dialogo Cast personalizzate, quindi devi seguire le istruzioni riportate sopra per aggiornare lo stato di selezione della route in
MediaRouter.
Stato di zero dispositivi
Se crei finestre di dialogo Cast personalizzate, il tuo MediaRouteChooserDialog personalizzato deve gestire correttamente il caso in cui non vengono trovati dispositivi. La finestra di dialogo deve avere indicatori che indicano chiaramente agli utenti quando l'app sta ancora tentando di trovare i dispositivi e quando il tentativo di rilevamento non è più attivo.
Se utilizzi MediaRouteChooserDialog predefinito, lo stato di zero dispositivi è già gestito.
Passaggi successivi
Concludiamo con le funzionalità che puoi aggiungere alla tua app Android Sender. Ora puoi creare un'app mittente per un'altra piattaforma (iOS o web) o creare un'app ricevitore web.