Aggiungi funzionalità avanzate alla tua app Android

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 su come funzionano le interruzioni pubblicitarie, consulta la panoramica sulle interruzioni pubblicitarie dei ricevitori web.

Sebbene le interruzioni possano essere specificate sia sul mittente che sul destinatario, ti consigliamo di specificarle su web ricevitore e 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:

Kotlin
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)
Java
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 ignorarne il comportamento. Se hai implementato il tuo MediaIntentReceiver, devi aggiungerlo al manifest e impostare il suo nome in CastMediaOptions. Questo esempio fornisce azioni personalizzate che eseguono l'override 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" />
Kotlin
// 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) {
    }
}
Java
// 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, quest'ultima 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, ognuno con uno spazio dei nomi univoco. L'app ricevente può anche inviare e ricevere messaggi utilizzando lo stesso spazio dei nomi.

Il canale personalizzato viene implementato con l'interfaccia Cast.MessageReceivedCallback:

Kotlin
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")
    }
}
Java
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);
    }
}

Dopo aver collegato l'app del mittente a quella del destinatario, il canale personalizzato può essere creato utilizzando il metodo setMessageReceivedCallbacks:

Kotlin
try {
    mCastSession.setMessageReceivedCallbacks(
        mHelloWorldChannel.namespace,
        mHelloWorldChannel)
} catch (e: IOException) {
    Log.e(TAG, "Exception while creating channel", e)
}
Java
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 su quel canale:

Kotlin
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)
        }
    }
}
Java
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 coda.

Esegui l'override della selezione delle immagini per i widget UX

Nei vari componenti del framework (ovvero la finestra di dialogo Cast, mini controller e UIMediaController, se configurato) viene mostrato l'artwork per i contenuti multimediali attualmente trasmessi. In genere, gli URL dell'artwork dell'immagine sono inclusi nel MediaMetadata dei contenuti multimediali, ma l'app del 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'uso dell'immagine, ad esempio, miniatura di notifica o sfondo a schermo intero. L'implementazione predefinita di ImagePicker sceglie sempre la prima immagine o restituisce un valore null se nessuna immagine è disponibile in MediaMetadata. La tua app può eseguire la sottoclasse ImagePicker e sostituire il metodo onPickImage(MediaMetadata, ImageHints) per fornire un'implementazione alternativa, per poi selezionare la sottoclasse con il metodo setImagePicker di CastMediaOptions.Builder. ImageHints fornisce suggerimenti a un ImagePicker circa il tipo e le dimensioni di un'immagine da selezionare per la visualizzazione nell'interfaccia utente.

Personalizzazione delle finestre di dialogo Trasmetti

Gestione del ciclo di vita delle sessioni

SessionManager è il punto centrale per la gestione del ciclo di vita delle sessioni. SessionManager ascolta Android MediaRouter Lo stato di selezione del percorso cambia 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 terminerà la sessione corrente.

Di conseguenza, per assicurarti che SessionManager gestisca correttamente i cicli di vita delle sessioni, devi assicurarti che:

A seconda di come crei le finestre di dialogo Trasmetti, potrebbe essere necessario eseguire altre azioni:

Stato zero dispositivi

Se crei finestre di dialogo di trasmissione personalizzate, il tuo MediaRouteChooserDialog personalizzato deve gestire correttamente il caso in cui non vengano rilevati dispositivi. La finestra di dialogo dovrebbe avere indicatori che indicano chiaramente agli utenti quando la tua app sta ancora cercando di trovare dispositivi e quando il tentativo di rilevamento non è più attivo.

Se utilizzi il valore predefinito MediaRouteChooserDialog, lo stato Zero dispositivi è già gestito.

Passaggi successivi

Con questo terminiamo 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 Web ricevitore.