In diesem Entwicklerleitfaden wird beschrieben, wie Sie die Google Cast-Unterstützung auf Ihrem Android-Gerät einrichten. die das Android Sender SDK verwendet.
Das Mobilgerät oder der Laptop ist der Sender, der die Wiedergabe steuert. Das Google Cast-Gerät ist der Receiver, mit dem die Inhalte auf dem Fernseher wiedergegeben werden.
Das Absender-Framework bezieht sich auf das Binärprogramm der Cast-Klassenbibliothek und die zugehörigen Ressourcen, die zur Laufzeit auf dem Absender vorhanden sind. Die Absender-App oder die Cast App bezieht sich auf eine App, die auch auf dem Absender ausgeführt wird. Web Receiver App bezieht sich auf die HTML-App, die auf dem für Google Cast optimierten Gerät ausgeführt wird.
Das Absender-Framework nutzt ein asynchrones Callback-Design, um den Absender zu informieren. für Ereignisse und den Wechsel zwischen den verschiedenen Status der Cast App. Zyklus.
Anwendungsfluss
In den folgenden Schritten wird der typische allgemeine Ausführungsablauf für einen Absender beschrieben Android-App:
- Das Cast-Framework startet automatisch
MediaRouter
Geräteerkennung basierend auf demActivity
-Lebenszyklus - Wenn der Nutzer auf das Cast-Symbol klickt, zeigt das Framework das Cast-Symbol mit der Liste der gefundenen Übertragungsgeräte.
- Wenn der Nutzer ein Übertragungsgerät auswählt, versucht das Framework, die Web Receiver auf dem Übertragungsgerät.
- Das Framework ruft Callbacks in der Absender-App auf, um zu bestätigen, dass das Web Receiver-App wurde gestartet.
- Das Framework schafft einen Kommunikationskanal zwischen dem Absender und dem Web. Receiver-Apps.
- Das Framework nutzt den Kommunikationskanal, um Medien zu laden und zu steuern auf dem Web Receiver wiedergegeben werden.
- Das Framework synchronisiert den Status der Medienwiedergabe zwischen Absender und Web Receiver: Wenn der Nutzer UI-Aktionen für Absender durchführt, wird das Framework übergeben. Mediensteuerungsanfragen an den Web Receiver gesendet werden, Medienstatusaktualisierungen sendet, aktualisiert das Framework den Status der Absender-UI.
- Wenn der Nutzer auf das Cast-Symbol klickt, um die Verbindung zum Übertragungsgerät zu trennen, trennt das Framework die Absender-App vom Web Receiver.
Für eine umfassende Liste aller Klassen, Methoden und Ereignisse in Google Cast Android SDK finden Sie in der Referenz zur Google Cast Sender API für Android-Geräte In den folgenden Abschnitten wird beschrieben, wie Sie Google Cast zu Ihrer Android-App hinzufügen.
Android-Manifest konfigurieren
Für die Datei AndroidManifest.xml Ihrer App müssen Sie Folgendes konfigurieren: Elemente für das Cast SDK:
uses-sdk
Lege die Mindest- und Ziel-API-Levels für Android fest, die vom Cast SDK unterstützt werden. Derzeit ist das Minimum das API-Level 23 und das Ziel ist API-Level 34.
<uses-sdk
android:minSdkVersion="23"
android:targetSdkVersion="34" />
android:theme
Legen Sie das Design Ihrer App basierend auf der Android SDK-Mindestversion fest. Wenn beispielsweise
Sie kein eigenes Theme implementieren, sollten Sie eine Variante von
Theme.AppCompat
beim Targeting auf eine Android SDK-Mindestversion, die
vor Lollipop.
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat" >
...
</application>
Cast-Kontext initialisieren
Das Framework hat ein globales Singleton-Objekt, das CastContext
, das Koordinaten
alle Interaktionen des Frameworks.
Ihre App muss die
OptionsProvider
mit den Optionen zum Initialisieren der
CastContext
Singleton. OptionsProvider
stellt eine Instanz von
CastOptions
mit Optionen, die sich auf das Verhalten des Frameworks auswirken. Die meisten
wichtig ist die Web Receiver-Anwendungs-ID, die zum Filtern
und die Web Receiver App zu starten, wenn ein Stream läuft
begonnen.
class CastOptionsProvider : OptionsProvider { override fun getCastOptions(context: Context): CastOptions { return Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .build() } override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? { return null } }
public class CastOptionsProvider implements OptionsProvider { @Override public CastOptions getCastOptions(Context context) { CastOptions castOptions = new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .build(); return castOptions; } @Override public List<SessionProvider> getAdditionalSessionProviders(Context context) { return null; } }
Du musst den voll qualifizierten Namen der implementierten OptionsProvider
angeben
als Metadatenfeld in der Datei AndroidManifest.xml der Sender-App:
<application>
...
<meta-data
android:name=
"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.foo.CastOptionsProvider" />
</application>
CastContext
wird verzögert initialisiert, wenn CastContext.getSharedInstance()
aufgerufen wird.
class MyActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { val castContext = CastContext.getSharedInstance(this) } }
public class MyActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { CastContext castContext = CastContext.getSharedInstance(this); } }
Die Cast UX-Widgets
Das Cast-Framework stellt die Widgets bereit, die dem Cast-Design entsprechen. Checkliste:
Einführendes Overlay: Das Framework bietet eine benutzerdefinierte Ansicht,
IntroductoryOverlay
, der dem Nutzer angezeigt wird, um auf das Cast-Symbol aufmerksam zu machen. wenn ein Receiver zum ersten Mal verfügbar ist. Die Sender-App kann den Text und die Position des Titels anpassen, Text.Cast-Symbol: Das Cast-Symbol ist immer sichtbar, unabhängig davon, ob Übertragungsgeräte verfügbar sind. Wenn der Nutzer zum ersten Mal auf das Cast-Symbol klickt, wird ein Cast-Dialogfeld angezeigt. der die gefundenen Geräte enthält. Wenn der Nutzer auf das Cast-Symbol klickt Solange das Gerät verbunden ist, werden die aktuellen Medienmetadaten (z. B. Titel, den Namen des Tonstudios und eine Miniaturansicht) um die Verbindung zum Übertragungsgerät zu trennen. Das Cast-Symbol wird manchmal auch als als „Cast-Symbol“.
Mini-Controller: Wenn der Nutzer Inhalte streamt und die aktuelle Seite verlassen hat Inhaltsseite oder maximierter Controller auf einen anderen Bildschirm in der Sender-App, wird unten auf dem Bildschirm angezeigt, die gerade gestreamten Medienmetadaten abrufen und die Wiedergabe steuern können.
Erweiterter Controller: Wenn der Nutzer Inhalte streamt und auf die Medienbenachrichtigung klickt oder Mini-Controller erscheint, wird der maximierte Controller gestartet, der die die gerade Medienmetadaten wiedergeben, und bietet mehrere Schaltflächen zum der Medienwiedergabe.
Benachrichtigung: Nur für Android. Wenn der Nutzer Inhalte streamt und das Fenster verlässt, Absender-App angezeigt wird, wird eine Medienbenachrichtigung mit der aktuellen Übertragung Medienmetadaten und Wiedergabesteuerung.
Sperrbildschirm: Nur für Android. Wenn der Nutzer Inhalte streamt und navigiert (oder das Gerät navigiert) Zeitüberschreitung) angezeigt wird, wird ein Steuerelement für den Sperrbildschirm zeigt die aktuell gestreamten Medienmetadaten und die Wiedergabesteuerung.
In der folgenden Anleitung wird beschrieben, wie Sie diese Widgets Ihrem für Ihre App.
Cast-Symbol hinzufügen
Das Android-
MediaRouter
APIs wurden entwickelt, um die Medienanzeige und -wiedergabe auf sekundären Geräten zu ermöglichen.
Android-Apps, die die MediaRouter
API verwenden, sollten ein Cast-Symbol als Teil enthalten
ihrer Benutzeroberfläche, um Nutzern die Auswahl einer Medienroute zum Abspielen von Medien zu ermöglichen.
einem sekundären Gerät, z. B. einem Übertragungsgerät.
Das Framework macht das Hinzufügen eines
MediaRouteButton
als
Cast button
sehr einfach. Du musst zuerst einen Menüpunkt oder ein MediaRouteButton
in der XML-Datei hinzufügen
die Ihre Speisekarte definiert, und verwenden
CastButtonFactory
um sie mit dem Framework zu verbinden.
// To add a Cast button, add the following snippet.
// menu.xml
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always" />
// Then override the onCreateOptionMenu() for each of your activities. // MyActivity.kt override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.main, menu) CastButtonFactory.setUpMediaRouteButton( applicationContext, menu, R.id.media_route_menu_item ) return true }
// Then override the onCreateOptionMenu() for each of your activities. // MyActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.main, menu); CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, R.id.media_route_menu_item); return true; }
Wenn Activity
dann übernimmt von
FragmentActivity
,
können Sie eine
MediaRouteButton
zu Ihrem Layout hinzufügen.
// activity_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal" >
<androidx.mediarouter.app.MediaRouteButton
android:id="@+id/media_route_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:mediaRouteTypes="user"
android:visibility="gone" />
</LinearLayout>
// MyActivity.kt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_layout) mMediaRouteButton = findViewById<View>(R.id.media_route_button) as MediaRouteButton CastButtonFactory.setUpMediaRouteButton(applicationContext, mMediaRouteButton) mCastContext = CastContext.getSharedInstance(this) }
// MyActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_layout); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), mMediaRouteButton); mCastContext = CastContext.getSharedInstance(this); }
Wie Sie die Darstellung des Cast-Symbols mithilfe eines Designs festlegen, erfahren Sie unter Cast-Symbol anpassen
Geräteerkennung konfigurieren
Die Geräteerkennung wird vollständig vom
CastContext
Bei der Initialisierung von CastContext gibt die Absender-App den Web Receiver an
Anwendungs-ID und kann optional Namespace-Filterung anfordern, indem Sie Folgendes festlegen:
supportedNamespaces
Zoll
CastOptions
CastContext
enthält intern einen Verweis auf die MediaRouter
und wird gestartet.
unter folgenden Bedingungen ausführen:
- Basiert auf einem Algorithmus, der die Latenz bei der Geräteerkennung und Akkunutzung ist, wird die Erkennung gelegentlich automatisch gestartet, geht die Absender-App in den Vordergrund.
- Das Dialogfeld „Streamen“ ist geöffnet.
- Das Cast SDK versucht, eine Cast-Sitzung wiederherzustellen.
Die Erkennung wird beendet, wenn das Cast-Dialogfeld geschlossen oder die die Absender-App in den Hintergrund wechselt.
<ph type="x-smartling-placeholder">class CastOptionsProvider : OptionsProvider { companion object { const val CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace" } override fun getCastOptions(appContext: Context): CastOptions { val supportedNamespaces: MutableList<String> = ArrayList() supportedNamespaces.add(CUSTOM_NAMESPACE) return CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setSupportedNamespaces(supportedNamespaces) .build() } override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? { return null } }
class CastOptionsProvider implements OptionsProvider { public static final String CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace"; @Override public CastOptions getCastOptions(Context appContext) { List<String> supportedNamespaces = new ArrayList<>(); supportedNamespaces.add(CUSTOM_NAMESPACE); CastOptions castOptions = new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setSupportedNamespaces(supportedNamespaces) .build(); return castOptions; } @Override public List<SessionProvider> getAdditionalSessionProviders(Context context) { return null; } }
Funktionsweise der Sitzungsverwaltung
Mit dem Cast SDK wird das Konzept einer Cast-Sitzung eingeführt. Einrichtung, die die Schritte zum Herstellen einer Verbindung mit einem Gerät, dem Starten (oder dem Beitritt) zu einem Web umfasst Receiver-App, die eine Verbindung zu dieser App herstellt und ein Mediensteuerungskanal initialisiert wird. Web Receiver anzeigen Leitfaden zum Lebenszyklus von Anwendungen finden Sie weitere Informationen zu Übertragungssitzungen und zum Lebenszyklus des Web-Receivers.
Sitzungen werden vom Kurs verwaltet
SessionManager
,
auf die Ihre App über
CastContext.getSessionManager()
Einzelne Sitzungen werden durch Unterklassen der Klasse dargestellt.
Session
Beispiel:
CastSession
steht für Sitzungen mit Übertragungsgeräten. Ihre App kann auf die derzeit aktiven
Sitzung streamen über
SessionManager.getCurrentCastSession()
Deine App kann die
SessionManagerListener
zur Überwachung von Sitzungsereignissen wie dem Erstellen, Sperren, Wiederaufnehmen und
Kündigung. Das Framework versucht automatisch,
abnormale/abrupte Beendigung während einer aktiven Sitzung.
Sitzungen werden als Reaktion auf Nutzergesten automatisch erstellt und gelöscht.
aus den MediaRouter
-Dialogfeldern.
Um Fehler beim Starten des Streams besser zu verstehen, können Apps Folgendes verwenden:
CastContext#getCastReasonCodeForCastStatusCode(int)
zum Konvertieren des Sitzungsstartfehlers in
CastReasonCodes
Hinweis: Einige Fehler beim Starten der Sitzung (z.B. CastReasonCodes#CAST_CANCELLED
)
sind beabsichtigt und sollten nicht als Fehler protokolliert werden.
Wenn Sie die Statusänderungen für die Sitzung kennen müssen, können Sie
ein SessionManagerListener
. In diesem Beispiel wird die Verfügbarkeit eines
CastSession
in Activity
.
class MyActivity : Activity() { private var mCastSession: CastSession? = null private lateinit var mCastContext: CastContext private lateinit var mSessionManager: SessionManager private val mSessionManagerListener: SessionManagerListener<CastSession> = SessionManagerListenerImpl() private inner class SessionManagerListenerImpl : SessionManagerListener<CastSession?> { override fun onSessionStarting(session: CastSession?) {} override fun onSessionStarted(session: CastSession?, sessionId: String) { invalidateOptionsMenu() } override fun onSessionStartFailed(session: CastSession?, error: Int) { val castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error) // Handle error } override fun onSessionSuspended(session: CastSession?, reason Int) {} override fun onSessionResuming(session: CastSession?, sessionId: String) {} override fun onSessionResumed(session: CastSession?, wasSuspended: Boolean) { invalidateOptionsMenu() } override fun onSessionResumeFailed(session: CastSession?, error: Int) {} override fun onSessionEnding(session: CastSession?) {} override fun onSessionEnded(session: CastSession?, error: Int) { finish() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mCastContext = CastContext.getSharedInstance(this) mSessionManager = mCastContext.sessionManager mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java) } override fun onResume() { super.onResume() mCastSession = mSessionManager.currentCastSession } override fun onDestroy() { super.onDestroy() mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession::class.java) } }
public class MyActivity extends Activity { private CastContext mCastContext; private CastSession mCastSession; private SessionManager mSessionManager; private SessionManagerListener<CastSession> mSessionManagerListener = new SessionManagerListenerImpl(); private class SessionManagerListenerImpl implements SessionManagerListener<CastSession> { @Override public void onSessionStarting(CastSession session) {} @Override public void onSessionStarted(CastSession session, String sessionId) { invalidateOptionsMenu(); } @Override public void onSessionStartFailed(CastSession session, int error) { int castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error); // Handle error } @Override public void onSessionSuspended(CastSession session, int reason) {} @Override public void onSessionResuming(CastSession session, String sessionId) {} @Override public void onSessionResumed(CastSession session, boolean wasSuspended) { invalidateOptionsMenu(); } @Override public void onSessionResumeFailed(CastSession session, int error) {} @Override public void onSessionEnding(CastSession session) {} @Override public void onSessionEnded(CastSession session, int error) { finish(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCastContext = CastContext.getSharedInstance(this); mSessionManager = mCastContext.getSessionManager(); mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class); } @Override protected void onResume() { super.onResume(); mCastSession = mSessionManager.getCurrentCastSession(); } @Override protected void onDestroy() { super.onDestroy(); mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class); } }
Stream-Übertragung
Die Beibehaltung des Sitzungsstatus ist die Grundlage der Streamübertragung. können Nutzer vorhandene Audio- und Videostreams per Sprachbefehl, über Google Home eine App oder ein Smart Display verwenden. Die Medienwiedergabe wird auf einem Gerät (Quelle) gestoppt und auf einem anderen fortgesetzt (das Ziel). Jedes Übertragungsgerät mit der neuesten Firmware kann als Quelle oder Ziel in einem Streamübertragung.
So rufen Sie das neue Zielgerät während einer Stream-Übertragung oder -Erweiterung ab:
registrieren
Cast.Listener
mithilfe der
CastSession#addCastListener
Rufen Sie dann
CastSession#getCastDevice()
während des onDeviceNameChanged
-Callbacks.
Weitere Informationen finden Sie unter Stream-Übertragung mit Web Receiver .
Automatische Wiederherstellung der Verbindung
Das Framework bietet eine
ReconnectionService
die von der Absender-App aktiviert werden kann, um die erneute Verbindung in vielen subtilen
Sonderfälle wie:
- Wiederherstellung nach einem vorübergehenden WLAN-Ausfall
- Aus Geräte-Ruhemodus wiederherstellen
- Nach Hintergrundwiedergabe wiederherstellen
- Wiederherstellung nach einem Absturz der App
Dieser Dienst ist standardmäßig aktiviert und kann in den
CastOptions.Builder
Dieser Dienst kann bei der automatischen Zusammenführung automatisch mit dem Manifest Ihrer App zusammengeführt werden ist in Ihrer Gradle-Datei aktiviert.
Das Framework startet den Dienst, wenn eine Mediensitzung stattfindet, und beendet ihn wenn die Mediensitzung endet.
So funktioniert die Mediensteuerung
Durch das Cast-Framework wird die
RemoteMediaPlayer
von Cast 2.x zugunsten einer neuen Klasse
RemoteMediaClient
,
die die gleiche Funktionalität in einer Reihe einfacherer APIs bietet.
vermeidet, einen GoogleApiClient übergeben zu müssen.
Wenn Ihre App eine
CastSession
mit einer Web Receiver-App, die den media-Namespace unterstützt, eine Instanz von
RemoteMediaClient
wird vom Framework automatisch erstellt. kann Ihre App
Sie können darauf zugreifen, indem Sie die Methode getRemoteMediaClient()
auf der CastSession
aufrufen.
Instanz.
Alle Methoden von RemoteMediaClient
, die Anfragen an den Web Receiver senden,
gibt ein PendingResult-Objekt zurück, mit dem die Anfrage verfolgt werden kann.
Es wird erwartet, dass die Instanz von RemoteMediaClient
von
Teile deiner App und einige interne Komponenten des
wie die persistenten Mini-Controller und
den Benachrichtigungsdienst.
Zu diesem Zweck unterstützt diese Instanz die Registrierung mehrerer Instanzen von
RemoteMediaClient.Listener
Medienmetadaten festlegen
Die
MediaMetadata
stellt die Informationen zu einem Medienelement dar, das Sie streamen möchten. Die
Im folgenden Beispiel wird eine neue MediaMetadata-Instanz eines Films erstellt und die
Titel, Untertitel und zwei Bilder.
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE) movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle()) movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio()) movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(0)))) movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(1))))
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE); movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle()); movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio()); movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(0)))); movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(1))));
Weitere Informationen finden Sie unter Bildauswahl zur Verwendung von Bildern mit Medienmetadaten.
Medien laden
Ihre App kann Medienelemente laden, wie im folgenden Code gezeigt. Erste Verwendung
MediaInfo.Builder
mit den Metadaten der Medien, um eine
MediaInfo
Instanz. Holen Sie sich
RemoteMediaClient
aus dem aktuellen CastSession
und laden Sie dann MediaInfo
in diese
RemoteMediaClient
. RemoteMediaClient
zum Abspielen, Pausieren und sonstigen Aktionen verwenden
eine auf dem Web Receiver ausgeführte Mediaplayer-App zu steuern.
val mediaInfo = MediaInfo.Builder(mSelectedMedia.getUrl()) .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setContentType("videos/mp4") .setMetadata(movieMetadata) .setStreamDuration(mSelectedMedia.getDuration() * 1000) .build() val remoteMediaClient = mCastSession.getRemoteMediaClient() remoteMediaClient.load(MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build())
MediaInfo mediaInfo = new MediaInfo.Builder(mSelectedMedia.getUrl()) .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setContentType("videos/mp4") .setMetadata(movieMetadata) .setStreamDuration(mSelectedMedia.getDuration() * 1000) .build(); RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); remoteMediaClient.load(new MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build());
Weitere Informationen finden Sie im Abschnitt mithilfe von Media-Tracks.
4K-Videoformat
Um zu prüfen, welches Videoformat Ihre Medien haben, verwenden Sie
getVideoInfo()
in MediaStatus ein, um die aktuelle Instanz von
VideoInfo
Diese Instanz enthält den Typ des HDR-TV-Formats und die Displayhöhe
und Breite in Pixeln. Varianten des 4K-Formats werden durch Konstanten angegeben
HDR_TYPE_*
Ferngesteuerte Benachrichtigungen an mehrere Geräte
Wenn ein Nutzer Inhalte streamt, werden andere Android-Geräte im selben Netzwerk um auch die Wiedergabe zu steuern. Jeder, dessen Gerät solche Benachrichtigungen erhält, können Sie sie in den Einstellungen für dieses Gerät deaktivieren. App bei Google > Google Cast > Fernbedienungs-Benachrichtigungen anzeigen (Die Benachrichtigungen enthalten eine Verknüpfung zur App „Einstellungen“.) Weitere Informationen finden Sie unter Benachrichtigungen zur Cast-Fernsteuerung
Mini-Controller hinzufügen
Gemäß dem Cast-Design Checkliste, sollte eine Absender-App eine dauerhafte Steuerung bieten, die sogenannte Miniversion. Controller die angezeigt werden sollte, wenn der Nutzer von der aktuellen Content-Seite zu Teil der Absender-App. Über den Mini-Controller wird eine sichtbare Erinnerung angezeigt. für den Nutzer der aktuellen Streaming-Sitzung. Durch Tippen auf den Mini-Controller kann der Nutzer zur erweiterten Controller-Vollbildansicht für Cast zurückkehren.
Das Framework bietet die benutzerdefinierte Ansicht MiniControllerFragment, die Sie unten in die Layoutdatei jeder Aktivität, in der Sie die Mini-Controller.
<fragment
android:id="@+id/castMiniController"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="gone"
class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment" />
Wenn die Sender-App einen Video- oder Audio-Livestream wiedergibt, gibt das SDK zeigt automatisch eine Wiedergabe-/Stopp-Schaltfläche anstelle der Wiedergabe-/Pause-Schaltfläche an. im Mini-Controller.
Um die Textdarstellung des Titels und Untertitels dieser benutzerdefinierten Ansicht festzulegen, und zur Auswahl von Schaltflächen Mini-Controller anpassen
Maximierten Controller hinzufügen
Die Checkliste für das Google Cast-Design erfordert, dass eine Sender-App eine erweiterte Version Controller für die Medien, die gestreamt werden. Der erweiterte Controller ist eine Vollbildversion von den Mini-Controller.
Das Cast SDK bietet ein Widget für den erweiterten Controller namens
ExpandedControllerActivity
Dies ist eine abstrakte Klasse, deren Klasse Sie ableiten müssen, um ein Cast-Symbol hinzuzufügen.
Erstellen Sie zuerst eine neue Menüressourcendatei für den erweiterten Controller, damit über das Cast-Symbol:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
</menu>
Erstellen Sie eine neue Klasse, die ExpandedControllerActivity
erweitert.
class ExpandedControlsActivity : ExpandedControllerActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.expanded_controller, menu) CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item) return true } }
public class ExpandedControlsActivity extends ExpandedControllerActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.expanded_controller, menu); CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item); return true; } }
Deklariere jetzt deine neue Aktivität im App-Manifest innerhalb des application
-Tags:
<application>
...
<activity
android:name=".expandedcontrols.ExpandedControlsActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.CastVideosDark"
android:screenOrientation="portrait"
android:parentActivityName="com.google.sample.cast.refplayer.VideoBrowserActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
...
</application>
Bearbeiten Sie die CastOptionsProvider
und ändern Sie NotificationOptions
und
CastMediaOptions
, um die Zielaktivität auf die neue Aktivität festzulegen:
override fun getCastOptions(context: Context): CastOptions? { val notificationOptions = NotificationOptions.Builder() .setTargetActivityClassName(ExpandedControlsActivity::class.java.name) .build() val mediaOptions = CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name) .build() return CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build() }
public CastOptions getCastOptions(Context context) { NotificationOptions notificationOptions = new NotificationOptions.Builder() .setTargetActivityClassName(ExpandedControlsActivity.class.getName()) .build(); CastMediaOptions mediaOptions = new CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .setExpandedControllerActivityClassName(ExpandedControlsActivity.class.getName()) .build(); return new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build(); }
Aktualisieren Sie die LocalPlayerActivity
-Methode loadRemoteMedia
, um Ihre
neue Aktivität, wenn die Remote-Medien geladen werden:
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) { val remoteMediaClient = mCastSession?.remoteMediaClient ?: return remoteMediaClient.registerCallback(object : RemoteMediaClient.Callback() { override fun onStatusUpdated() { val intent = Intent(this@LocalPlayerActivity, ExpandedControlsActivity::class.java) startActivity(intent) remoteMediaClient.unregisterCallback(this) } }) remoteMediaClient.load( MediaLoadRequestData.Builder() .setMediaInfo(mSelectedMedia) .setAutoplay(autoPlay) .setCurrentTime(position.toLong()).build() ) }
private void loadRemoteMedia(int position, boolean autoPlay) { if (mCastSession == null) { return; } final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); if (remoteMediaClient == null) { return; } remoteMediaClient.registerCallback(new RemoteMediaClient.Callback() { @Override public void onStatusUpdated() { Intent intent = new Intent(LocalPlayerActivity.this, ExpandedControlsActivity.class); startActivity(intent); remoteMediaClient.unregisterCallback(this); } }); remoteMediaClient.load(new MediaLoadRequestData.Builder() .setMediaInfo(mSelectedMedia) .setAutoplay(autoPlay) .setCurrentTime(position).build()); }
Wenn die Sender-App einen Video- oder Audio-Livestream wiedergibt, gibt das SDK zeigt automatisch eine Wiedergabe-/Stopp-Schaltfläche anstelle der Wiedergabe-/Pause-Schaltfläche an. im maximierten Controller.
Um die Darstellung mithilfe von Designs festzulegen, wähle die anzuzeigenden Schaltflächen aus. und benutzerdefinierte Schaltflächen hinzufügen, Erweiterten Controller anpassen:
Lautstärkeregelung
Das Framework verwaltet automatisch das Volume für die Absender-App. Das Framework synchronisiert automatisch die Sender- und Web Receiver-Apps, Die Benutzeroberfläche meldet immer die vom Web Receiver angegebene Lautstärke.
Lautstärkeregelung mit physischer Taste
Unter Android können die physischen Tasten am Gerät des Senders verwendet werden, um die Lautstärke der Übertragungssitzung auf dem Web Receiver standardmäßig für alle Geräte mit Jelly Bean oder neuer.
Lautstärkeregelung mit physischer Taste vor Jelly Bean
So regeln Sie die Lautstärke des Web Receiver-Geräts mit den physischen Lautstärketasten:
Bei Android-Geräten, die älter als Jelly Bean sind, sollte die Sender-App
dispatchKeyEvent
in ihren Aktivitäten und rufen Sie
CastContext.onDispatchVolumeKeyEventBeforeJellyBean()
:
class MyActivity : FragmentActivity() { override fun dispatchKeyEvent(event: KeyEvent): Boolean { return (CastContext.getSharedInstance(this) .onDispatchVolumeKeyEventBeforeJellyBean(event) || super.dispatchKeyEvent(event)) } }
class MyActivity extends FragmentActivity { @Override public boolean dispatchKeyEvent(KeyEvent event) { return CastContext.getSharedInstance(this) .onDispatchVolumeKeyEventBeforeJellyBean(event) || super.dispatchKeyEvent(event); } }
Mediensteuerelemente in Benachrichtigungen und Sperrbildschirm hinzufügen
Nur auf Android-Geräten erfordert die Google Cast-Design-Checkliste eine Sender-App,
Mediensteuerung in einem
Benachrichtigung
und im Schloss
Bildschirm,
an die der Absender etwas überträgt, die Absender-App aber nicht im Fokus ist. Die
Framework bietet
MediaNotificationService
und
MediaIntentReceiver
damit die Absender-App Mediensteuerelemente in einer Benachrichtigung und im Schloss erstellen kann
Bildschirm.
MediaNotificationService
wird ausgeführt, wenn der Absender Inhalte streamt, und zeigt eine
Benachrichtigung mit Miniaturansicht und Informationen zum aktuellen Streaming
sowie eine Schaltfläche für Wiedergabe/Pause und eine Stopp-Schaltfläche.
MediaIntentReceiver
ist eine BroadcastReceiver
, die Nutzeraktionen aus
die Benachrichtigung.
Deine App kann die Benachrichtigungs- und Mediensteuerung vom Sperrbildschirm bis zum
NotificationOptions
Ihre App kann konfigurieren, welche Steuerschaltflächen in der Benachrichtigung angezeigt werden, und
Das Activity
, das geöffnet werden soll, wenn der Nutzer auf die Benachrichtigung tippt. Wenn-Aktionen
nicht explizit angegeben sind, werden die Standardwerte,
MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK
und
MediaIntentReceiver.ACTION_STOP_CASTING
wird verwendet.
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting". val buttonActions: MutableList<String> = ArrayList() buttonActions.add(MediaIntentReceiver.ACTION_REWIND) buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK) buttonActions.add(MediaIntentReceiver.ACTION_FORWARD) buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING) // Showing "play/pause" and "stop casting" in the compat view of the notification. val compatButtonActionsIndices = intArrayOf(1, 3) // Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds. // Tapping on the notification opens an Activity with class VideoBrowserActivity. val notificationOptions = NotificationOptions.Builder() .setActions(buttonActions, compatButtonActionsIndices) .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS) .setTargetActivityClassName(VideoBrowserActivity::class.java.name) .build()
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting". List<String> buttonActions = new ArrayList<>(); buttonActions.add(MediaIntentReceiver.ACTION_REWIND); buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK); buttonActions.add(MediaIntentReceiver.ACTION_FORWARD); buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING); // Showing "play/pause" and "stop casting" in the compat view of the notification. int[] compatButtonActionsIndices = new int[]{1, 3}; // Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds. // Tapping on the notification opens an Activity with class VideoBrowserActivity. NotificationOptions notificationOptions = new NotificationOptions.Builder() .setActions(buttonActions, compatButtonActionsIndices) .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS) .setTargetActivityClassName(VideoBrowserActivity.class.getName()) .build();
Die Anzeige der Mediensteuerung für Benachrichtigungen und Sperrbildschirm ist aktiviert von
und kann durch Aufrufen von
setNotificationOptions
mit Null in
CastMediaOptions.Builder
Derzeit ist der Sperrbildschirm aktiviert, solange die Benachrichtigungsfunktion aktiviert ist.
aktiviert ist.
// ... continue with the NotificationOptions built above val mediaOptions = CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .build() val castOptions: CastOptions = Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build()
// ... continue with the NotificationOptions built above CastMediaOptions mediaOptions = new CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .build(); CastOptions castOptions = new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build();
Wenn die Sender-App einen Video- oder Audio-Livestream wiedergibt, gibt das SDK zeigt automatisch eine Wiedergabe-/Stopp-Schaltfläche anstelle der Wiedergabe-/Pause-Schaltfläche an. auf dem Benachrichtigungssteuerelement, aber nicht auf dem Sperrbildschirm.
Hinweis: Um die Steuerelemente für den Sperrbildschirm auf Geräten mit einer älteren Version von Lollipop anzuzeigen,
RemoteMediaClient
fordert automatisch den Audiofokus in deinem Namen an.
Fehler verarbeiten
Absender-Apps müssen alle Fehlerrückrufe verarbeiten und entscheiden, die beste Reaktion für jede Phase des Cast-Lebenszyklus. Die App kann Folgendes anzeigen: wird eine Fehlermeldung angezeigt oder die Verbindung zum Web Receiver.