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:
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);
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" />
// 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) { } }
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:
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); } }
Sobald die Senderanwendung mit der Empfängeranwendung verbunden ist, kann der benutzerdefinierte Kanal mit der Methode setMessageReceivedCallbacks
erstellt werden:
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); }
Sobald der benutzerdefinierte Kanal erstellt wurde, kann der Absender mit der Methode sendMessage
Stringnachrichten über diesen Kanal an den Empfänger senden:
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); } } }
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:
- Rufen Sie im Dialogfeld für die Routenauswahl
MediaRouter.selectRoute(MediaRouter.RouteInfo)
auf, wenn ein Nutzer ein Gerät auswählt. - Rufen Sie im Routingcontroller-Dialogfeld (entweder im verbundenen Status oder im Umwandlungsstatus)
MediaRouter.unselect(int)
auf, wenn der Nutzer das Streamen beendet.
Je nachdem, wie du die Cast-Dialogfelder erstellt hast, sind möglicherweise weitere Aktionen erforderlich:
- Wenn Sie Übertragungsdialoge mit
MediaRouteChooserDialog
undMediaRouteControllerDialog
erstellen, wird die Routenauswahl inMediaRouter
automatisch aktualisiert. Sie müssen nichts tun. - Wenn Sie das Cast-Symbol mit
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
oderCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
einrichten, werden die Dialogfelder mitMediaRouteChooserDialog
undMediaRouteControllerDialog
erstellt. Sie müssen also nichts weiter tun. - In anderen Fällen erstellen Sie benutzerdefinierte Cast-Dialogfelder. Folgen Sie dann der Anleitung oben, um den Status der Routenauswahl in
MediaRouter
zu aktualisieren.
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.