Werbeunterbrechungen
Das Android Sender SDK unterstützt Werbeunterbrechungen und Companion-Anzeigen in einem bestimmten Mediastream.
Weitere Informationen zur Funktionsweise von Werbeunterbrechungen findest du in der Übersicht über Werbeunterbrechungen für Web Receiver.
Werbeunterbrechungen können sowohl auf dem Sender als auch auf dem Empfänger angegeben werden. Es wird jedoch empfohlen, sie auf dem Web Receiver und dem Android TV-Empfänger anzugeben, um ein einheitliches Verhalten auf allen Plattformen zu gewährleisten.
Unter Android geben Sie Werbeunterbrechungen in einem Ladebefehl mit AdBreakClipInfo und AdBreakInfo an:
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 Sender-App kann MediaIntentReceiver erweitern, um benutzerdefinierte Aktionen zu verarbeiten oder das Verhalten zu überschreiben. Wenn Sie einen eigenen MediaIntentReceiver implementiert haben, müssen Sie ihn dem Manifest hinzufügen und seinen Namen in der CastMediaOptions festlegen. In diesem Beispiel werden benutzerdefinierte Aktionen bereitgestellt, die die Remote-Medienwiedergabe, das Drücken der Medientaste und andere Arten von 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 Sender-App mit der Empfänger-App kommunizieren kann, muss Ihre App einen benutzerdefinierten Kanal erstellen. Der Sender kann den benutzerdefinierten Kanal verwenden, um Stringnachrichten an den Empfänger zu senden. Jeder benutzerdefinierte Kanal wird durch einen eindeutigen Namespace definiert und muss mit dem Präfix urn:x-cast: beginnen, z. B. urn:x-cast:com.example.custom. Es ist möglich, mehrere benutzerdefinierte Kanäle zu haben, die jeweils einen eindeutigen Namespace haben. Die Empfänger-App kann auch Nachrichten über denselben Namespace senden und empfangen.
Der benutzerdefinierte Kanal wird mit der 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 Sender-App mit der Empfänger-App 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); }
Nachdem der benutzerdefinierte Kanal erstellt wurde, kann der Sender die Methode sendMessage verwenden, um String-Nachrichten über diesen Kanal an den Empfänger zu 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 Warteschlangen-APIs.
Bildauswahl für UX-Widgets überschreiben
Verschiedene Komponenten des Frameworks (nämlich das Cast-Dialogfeld, der Mini-Controller und der UIMediaController, sofern konfiguriert) zeigen Cover für die aktuell gestreamten Medien an. Die URLs zu den Bild-Artworks sind normalerweise in den MediaMetadata für die Medien enthalten, die Sender-App kann jedoch eine alternative Quelle für die URLs haben.
Die Klasse ImagePicker definiert eine Möglichkeit, ein geeignetes Bild aus der Liste der Bilder in einem MediaMetadata auszuwählen, basierend auf der Verwendung des Bildes, z. B. als Miniaturansicht für Benachrichtigungen oder als Vollbildhintergrund. Die Standardimplementierung von ImagePicker wählt immer das erste Bild aus oder gibt null zurück, wenn im MediaMetadata kein Bild verfügbar ist. Ihre App kann eine Unterklasse von ImagePicker erstellen und die Methode onPickImage(MediaMetadata, ImageHints) überschreiben, um eine alternative Implementierung bereitzustellen. Anschließend können Sie diese Unterklasse mit der Methode setImagePicker von CastMediaOptions.Builder auswählen.
ImageHints liefert Hinweise für ein ImagePicker zum Typ und zur Größe eines Bildes, das für die Anzeige in der Benutzeroberfläche ausgewählt werden soll.
Cast-Dialogfelder anpassen
Sitzungslebenszyklus verwalten
SessionManager ist der zentrale Ort für die Verwaltung des Lebenszyklus von Sitzungen. SessionManager wartet auf Änderungen des Routenauswahlstatus von Android MediaRouter, um Sitzungen zu starten, fortzusetzen und zu beenden. Wenn eine Route ausgewählt wird, erstellt SessionManager ein Session-Objekt und versucht, es zu starten oder fortzusetzen. Wenn die Auswahl einer Route aufgehoben wird, beendet SessionManager die aktuelle Sitzung.
Damit SessionManager die Lebenszyklen von Sitzungen ordnungsgemäß verwaltet, müssen Sie Folgendes sicherstellen:
- Rufe im Dialogfeld zur Routenauswahl
MediaRouter.selectRoute(MediaRouter.RouteInfo)auf, wenn ein Nutzer ein Gerät auswählt. - Rufe im Dialogfeld des Routen-Controllers (entweder im verbundenen Zustand oder im Streaming-Zustand)
MediaRouter.unselect(int)auf, wenn der Nutzer das Streaming beendet.
Je nachdem, wie du die Cast-Dialogfelder erstellst, sind möglicherweise zusätzliche Aktionen erforderlich:
- Wenn du Cast-Dialogfelder mit
MediaRouteChooserDialogundMediaRouteControllerDialogerstellst, wird die Routenauswahl inMediaRouterautomatisch aktualisiert. Du musst also nichts weiter tun. - Wenn Sie das Cast-Symbol mit
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)oderCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)eingerichtet haben, werden die Dialogfelder tatsächlich mitMediaRouteChooserDialogundMediaRouteControllerDialogerstellt. Es ist also auch nichts zu tun. - In anderen Fällen erstellst du benutzerdefinierte Cast-Dialogfelder. Folge dann der Anleitung oben, um den Status der Routenauswahl in
MediaRouterzu aktualisieren.
Keine Geräte vorhanden
Wenn du benutzerdefinierte Cast-Dialogfelder erstellst, sollte dein benutzerdefiniertes MediaRouteChooserDialog den Fall, dass keine Geräte gefunden werden, ordnungsgemäß verarbeiten. Das Dialogfeld sollte Anzeigen enthalten, die den Nutzern verdeutlichen, wann die App noch versucht, Geräte zu finden, und wann der Suchversuch nicht mehr aktiv ist.
Wenn Sie die Standard-MediaRouteChooserDialog verwenden, wird der Status „Keine Geräte“ bereits verarbeitet.
Nächste Schritte
Damit sind die Funktionen, die Sie Ihrer Android-Sender-App hinzufügen können, vollständig. Sie können jetzt eine Sender-App für eine andere Plattform (iOS oder Web) oder eine Web-Receiver-App erstellen.