Ihrer Android-App erweiterte Funktionen hinzufügen

Werbeunterbrechungen

Das Android Sender SDK unterstützt Werbeunterbrechungen und Companion-Anzeigen in einem bestimmten Medienstream.

Weitere Informationen zur Funktionsweise von Werbeunterbrechungen findest du in der Übersicht zu Werbeunterbrechungen im Webempfänger.

Pausen können zwar sowohl auf dem Sender als auch auf dem Empfänger festgelegt werden, es wird jedoch empfohlen, sie auf dem Webempfänger und dem Android TV-Empfänger festzulegen, um ein einheitliches Verhalten auf allen Plattformen zu gewährleisten.

Unter Android kannst du Werbeunterbrechungen in einem Ladebefehl mit AdBreakClipInfo und AdBreakInfo festlegen:

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);

Benutzerdefinierte Aktionen hinzufügen

Eine Senderanwendung kann MediaIntentReceiver erweitern, um benutzerdefinierte Aktionen zu verarbeiten oder deren Verhalten zu überschreiben. Wenn du deine eigene MediaIntentReceiver implementiert hast, musst du sie dem Manifest hinzufügen und außerdem ihren Namen in der CastMediaOptions festlegen. Dieses Beispiel enthält benutzerdefinierte Aktionen, die die Ein/Aus-Schaltfläche für die Remote-Medienwiedergabe, das Drücken der Medienschaltfläche und andere Aktionen überschreiben.

// 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) {
    }
}

Benutzerdefinierten Channel hinzufügen

Damit die Senderanwendung mit der Empfängeranwendung kommunizieren kann, muss sie einen benutzerdefinierten Kanal erstellen. Der Absender kann über den benutzerdefinierten Kanal Stringnachrichten an den Empfänger senden. Jeder benutzerdefinierte Channel wird durch einen eindeutigen Namespace definiert und muss mit dem Präfix urn:x-cast: beginnen, z. B. urn:x-cast:com.example.custom. Sie können mehrere benutzerdefinierte Channels mit jeweils einem eigenen Namespace haben. Die Empfängeranwendung kann mit demselben Namespace auch Nachrichten senden und empfangen.

Der benutzerdefinierte Channel wird über die Schnittstelle Cast.MessageReceivedCallback implementiert:

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);
    }
}

Sobald die Senderanwendung mit der Empfängeranwendung verbunden ist, kann der benutzerdefinierte Kanal mit der Methode setMessageReceivedCallbacks erstellt werden:

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);
}

Sobald der benutzerdefinierte Kanal erstellt wurde, kann der Absender mit der Methode sendMessage Stringnachrichten über diesen Kanal an den Empfänger senden:

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);
        }
    }
}

Autoplay unterstützen

Weitere Informationen findest du im Abschnitt Autoplay und Queueing APIs.

Bildauswahl für UX-Widgets überschreiben

Verschiedene Komponenten des Frameworks (wie das Cast-Dialogfeld, der Mini-Controller und der UIMediaController, falls konfiguriert) zeigen das Artwork für die aktuell gestreamten Medien an. Die URLs zu den Bildgrafiken sind in der Regel im MediaMetadata für die Medien enthalten. Die Absender-App kann jedoch auch eine alternative Quelle für die URLs haben.

Die Klasse ImagePicker definiert eine Möglichkeit zur Auswahl eines geeigneten Bildes aus der Liste der Bilder in einem MediaMetadata, basierend auf der Verwendung des Bildes, z. B. der Miniaturansicht einer Benachrichtigung oder des Vollbildhintergrunds. Die Standardimplementierung ImagePicker wählt immer das erste Bild aus oder gibt null zurück, wenn kein Bild im MediaMetadata verfügbar ist. Ihre Anwendung kann eine abgeleitete Klasse von ImagePicker erstellen und die Methode onPickImage(MediaMetadata, ImageHints) überschreiben, um eine alternative Implementierung bereitzustellen. Anschließend können Sie diese abgeleitete Klasse mit der Methode setImagePicker von CastMediaOptions.Builder auswählen. ImageHints liefert einem ImagePicker Hinweise auf den Typ und die Größe eines Bildes, das zur Anzeige auf der Benutzeroberfläche ausgewählt werden soll.

Cast-Dialogfelder anpassen

Sitzungslebenszyklus verwalten

SessionManager ist der zentrale Ort für die Verwaltung des Sitzungslebenszyklus. SessionManager wartet auf Änderungen des Routenauswahlstatus von Android MediaRouter, um Sitzungen zu starten, fortzusetzen und zu beenden. Wenn eine Route ausgewählt ist, erstellt SessionManager ein Session-Objekt und versucht, es zu starten oder fortzusetzen. Wenn eine Route nicht ausgewählt ist, beendet SessionManager die aktuelle Sitzung.

Damit Sitzungslebenszyklen von SessionManager ordnungsgemäß verwaltet werden, müssen Sie daher auf Folgendes achten:

Je nachdem, wie du die Cast-Dialogfelder erstellt hast, sind möglicherweise weitere Aktionen erforderlich:

Status „Null Geräte“

Wenn du benutzerdefinierte Cast-Dialogfelder erstellst, sollte deine benutzerdefinierte MediaRouteChooserDialog den Fall verarbeiten können, dass keine Geräte gefunden werden. Im Dialogfeld sollten Anzeigen angezeigt werden, die Nutzer deutlich machen, wenn Ihre App noch versucht, Geräte zu finden, und der Erkennungsversuch nicht mehr aktiv ist.

Wenn du den Standard-MediaRouteChooserDialog verwendest, wird der Status „0 Geräte“ bereits verarbeitet.

Nächste Schritte

Damit sind die Funktionen abgeschlossen, die Sie der Sender-App in Android hinzufügen können. Sie können jetzt eine Sender-App für eine andere Plattform (iOS oder Web) oder eine Web Receiver-App erstellen.