Ce guide du développeur explique comment rendre votre appareil compatible avec Google Cast l'application émettrice à l'aide du SDK Android Sender.
L'appareil mobile ou l'ordinateur portable est l'expéditeur qui contrôle la lecture. L'appareil Google Cast est le récepteur qui affiche le contenu sur le téléviseur.
Le framework expéditeur fait référence au binaire de la bibliothèque de classes Cast et ressources présentes au moment de l'exécution sur l'émetteur. L'application émettrice ou l'application Cast fait référence à une application en cours d’exécution sur l’expéditeur. L'application Web Receiver fait référence à l'application HTML exécutée sur l'appareil compatible Cast.
Le framework de l'expéditeur utilise une conception de rappel asynchrone pour informer l'expéditeur application d'événements et de transition entre différents états de l'application Cast d'un cycle.
Déroulement des opérations de l'application
Les étapes suivantes décrivent le flux d'exécution de haut niveau classique pour un expéditeur Application Android:
- Le framework Cast démarre automatiquement
MediaRouter
la détection d'appareils selon le cycle de vie deActivity
. - Lorsque l'utilisateur clique sur l'icône Cast, le framework affiche l'icône Cast. contenant la liste des appareils Cast détectés.
- Lorsque l'utilisateur sélectionne un appareil Cast, le framework tente de lancer l' Web Receiver sur l'appareil Cast.
- Le framework invoque des rappels dans l'application émettrice pour vérifier que le navigateur L'application réceptrice a été lancée.
- Le framework crée un canal de communication entre l'expéditeur et le Web Applications réceptrices.
- Le framework utilise le canal de communication pour charger et contrôler les contenus multimédias la lecture sur le Web Receiver.
- Le framework synchronise l'état de lecture des contenus multimédias entre l'émetteur et Web Receiver: lorsque l'utilisateur effectue des actions dans l'interface utilisateur de l'expéditeur, le framework transmet ces requêtes de contrôle multimédia au Web Receiver, et lorsque ce récepteur Web envoie des mises à jour de l'état du contenu multimédia, le framework met à jour l'état de l'UI de l'émetteur.
- Lorsque l'utilisateur clique sur l'icône Cast pour se déconnecter de l'appareil Cast, le framework déconnectera l'application émettrice du récepteur Web.
Pour obtenir la liste complète des classes, méthodes et événements de Google Cast, Android SDK, consultez la documentation de référence de l'API Google Cast Sender pour Android Les sections suivantes décrivent les étapes à suivre pour ajouter Cast à votre application Android.
Configurer le fichier manifeste Android
Le fichier AndroidManifest.xml de votre application nécessite que vous configuriez les éléments suivants pour le SDK Cast:
uses-sdk
Définissez les niveaux d'API Android minimaux et cibles compatibles avec le SDK Cast. Actuellement, le niveau d'API minimal est 23 et la cible est Niveau d'API 34.
<uses-sdk
android:minSdkVersion="23"
android:targetSdkVersion="34" />
android:theme
Définissez le thème de votre application en fonction de la version minimale du SDK Android. Par exemple, si
vous n'implémentez pas votre propre thème, vous devez utiliser une variante
Theme.AppCompat
lorsque vous ciblez une version minimale du SDK Android qui est
avant Lollipop.
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat" >
...
</application>
Initialiser le contexte Cast
Le framework comporte un objet singleton global, CastContext
, qui coordonne
toutes les interactions du framework.
Votre application doit implémenter
OptionsProvider
pour fournir les options nécessaires à l'initialisation
CastContext
singleton. OptionsProvider
fournit une instance de
CastOptions
qui contient des options qui affectent le comportement du framework. Les plus
le plus important est l'ID d'application Web Receiver, qui sert à filtrer
et de lancer l'application Web Receiver lorsqu'une session Cast est
pour commencer.
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; } }
Vous devez déclarer le nom complet du OptionsProvider
implémenté
en tant que champ de métadonnées dans le fichier AndroidManifest.xml de l'application émettrice:
<application>
...
<meta-data
android:name=
"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.foo.CastOptionsProvider" />
</application>
CastContext
est initialisé en différé lorsque CastContext.getSharedInstance()
est appelé.
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); } }
Widgets Cast de l'expérience utilisateur
Le framework Cast fournit les widgets conformes à la conception Cast. Checklist:
Superposition d'introduction: Le framework fournit une vue personnalisée,
IntroductoryOverlay
pour attirer l'attention de l'utilisateur sur l'icône Cast. la première fois qu'un récepteur est disponible. L'application Expéditeur peut personnaliser le texte et la position du titre texte.Icône Cast: L'icône Cast est visible, quelle que soit la disponibilité des appareils Cast. Lorsque l'utilisateur clique pour la première fois sur l'icône Cast, une boîte de dialogue Cast s'affiche. qui liste les appareils détectés. Lorsque l'utilisateur clique sur l'icône Cast lorsque l'appareil est connecté, les métadonnées multimédias actuelles (comme titre, nom du studio d'enregistrement et une miniature) ou permet à l'utilisateur pour vous déconnecter de l'appareil Cast. L'icône Cast est parfois appelé comme l'icône Cast.
Mini-télécommande: Lorsque l'utilisateur caste du contenu et a quitté la page ou la télécommande agrandie sur un autre écran de l'application émettrice, le la mini-télécommande est affichée en bas de l'écran pour permettre à l'utilisateur de pour voir les métadonnées de contenus multimédias en cours de diffusion et contrôler la lecture.
Contrôleur étendu: Lorsque l'utilisateur caste du contenu, s'il clique sur la notification multimédia ou mini-télécommande, la télécommande agrandie se lance et affiche métadonnées multimédias en cours de lecture et propose plusieurs boutons la lecture du contenu multimédia.
Notification: Android seulement. Lorsque l'utilisateur caste du contenu et quitte la page l'application émettrice, une notification multimédia s'affiche, indiquant l'appareil en cours de diffusion des métadonnées multimédias et des commandes de lecture.
Écran de verrouillage: Android seulement. Lorsque l'utilisateur caste du contenu et lance la navigation (ou l'appareil s'affiche) à l'écran de verrouillage, une commande d'écran de verrouillage multimédia s'affiche. affiche les métadonnées et les commandes de lecture en cours de diffusion.
Le guide suivant décrit comment ajouter ces widgets à votre application.
Ajouter une icône Cast
Android
MediaRouter
Les API sont conçues pour permettre l'affichage et la lecture de contenus multimédias sur des appareils secondaires.
Les applications Android qui utilisent l'API MediaRouter
doivent inclure une icône Cast.
de leur interface utilisateur, pour leur permettre de sélectionner l'itinéraire de lecture des contenus multimédias
un appareil secondaire, comme un appareil Cast.
Le framework permet d'ajouter
MediaRouteButton
en tant que
Cast button
très facile. Vous devez d'abord ajouter un élément de menu ou un élément MediaRouteButton
dans le fichier XML
qui définit votre menu, et utilisez
CastButtonFactory
pour la relier à la structure.
// 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; }
Ensuite, si votre Activity
hérite de
FragmentActivity
,
vous pouvez ajouter
MediaRouteButton
à votre mise en page.
// 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); }
Pour définir l'apparence de l'icône Cast à l'aide d'un thème, consultez Personnaliser l'icône Cast
Configurer la détection d'appareils
La détection d'appareils est entièrement gérée
CastContext
Lors de l'initialisation de CastContext, l'application émettrice spécifie le récepteur Web
et peut éventuellement demander le filtrage des espaces de noms en définissant
supportedNamespaces
po
CastOptions
CastContext
contient une référence à MediaRouter
en interne et commencera
le processus de découverte dans les conditions suivantes:
- Basé sur un algorithme conçu pour équilibrer la latence de détection des appareils et l'utilisation de la batterie, la détection sera parfois lancée automatiquement l'application émettrice passe au premier plan.
- La boîte de dialogue "Caster" est ouverte.
- Le SDK Cast tente de récupérer une session Cast.
Le processus de détection est interrompu lorsque la boîte de dialogue "Caster" est fermée ou lorsque l'icône l'application émettrice passe en arrière-plan.
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; } }
Fonctionnement de la gestion des sessions
Le SDK Cast introduit le concept de session Cast, établissement qui combine les étapes de connexion à un appareil, de lancement (ou de connexion) à un Web l'application réceptrice, la connexion à cette application et l'initialisation d'un canal de commande multimédia. Voir le récepteur Web Guide sur le cycle de vie des applications pour en savoir plus sur les sessions Cast et le cycle de vie du récepteur Web.
Les sessions sont gérées par la classe
SessionManager
auquel votre application peut accéder via
CastContext.getSessionManager()
Les sessions individuelles sont représentées par des sous-classes de la classe
Session
Par exemple :
CastSession
représente les sessions avec des appareils Cast. Votre application peut accéder aux paramètres
Caster la session via
SessionManager.getCurrentCastSession()
Votre application peut utiliser
SessionManagerListener
pour surveiller les événements de session, tels que la création, la suspension, la reprise et
cessation. Le framework tente automatiquement de reprendre
arrêt anormal ou abrupt pendant qu'une session était active.
Les sessions sont créées et supprimées automatiquement en réponse aux gestes de l'utilisateur
à partir des boîtes de dialogue MediaRouter
.
Pour mieux comprendre les erreurs de démarrage de Cast, les applications peuvent utiliser
CastContext#getCastReasonCodeForCastStatusCode(int)
pour convertir l'erreur de début de session en
CastReasonCodes
Veuillez noter que certaines erreurs de démarrage de session (par exemple, CastReasonCodes#CAST_CANCELLED
)
sont prévus et ne doivent pas être consignés comme des erreurs.
Si vous devez être conscient des changements d'état de la session, vous pouvez implémenter
un SessionManagerListener
. Cet exemple écoute la disponibilité
CastSession
dans un 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); } }
Transfert de diffusion
La préservation de l'état de la session est la base du transfert de flux, où les utilisateurs peuvent déplacer des flux audio et vidéo existants d'un appareil à un autre à l'aide de commandes vocales, de Google Home des applications ou des écrans connectés. La lecture du contenu multimédia s'arrête sur un appareil (la source) et continue sur un autre (le destination). N'importe quel appareil Cast équipé du dernier micrologiciel peut servir de source ou de destination dans un le transfert de diffusion.
Pour obtenir le nouvel appareil de destination lors d'un transfert ou d'une extension de la diffusion, procédez comme suit :
enregistrer un
Cast.Listener
à l'aide du
CastSession#addCastListener
Appelez ensuite
CastSession#getCastDevice()
lors du rappel onDeviceNameChanged
.
Voir Transfert de diffusion sur Web Receiver pour en savoir plus.
Reconnexion automatique
Le framework fournit
ReconnectionService
qui peut être activée par l'application émettrice pour gérer la reconnexion de nombreuses manières
des cas particuliers, tels que:
- Se remettre d'une perte temporaire de connexion Wi-Fi
- Récupérer après une mise en veille de l'appareil
- Récupérer après la mise en arrière-plan de l'application
- Récupérer en cas de plantage de l'application
Ce service est activé par défaut et peut être désactivé dans
CastOptions.Builder
Ce service peut être fusionné automatiquement avec le fichier manifeste de votre appli si cette fonctionnalité est activée est activé dans votre fichier Gradle.
Le framework démarre le service lors d'une session multimédia, puis l'arrête. à la fin de la session multimédia.
Fonctionnement des commandes multimédias
Le framework Cast rend obsolète
RemoteMediaPlayer
de Cast 2.x en faveur d'une nouvelle classe
RemoteMediaClient
qui fournit les mêmes fonctionnalités dans un ensemble d'API plus pratiques.
évite d'avoir à transmettre un GoogleApiClient.
Lorsque votre application établit un
CastSession
avec une application Web Receiver compatible avec l'espace de noms multimédia, une instance de
RemoteMediaClient
sera automatiquement créé par le framework. votre application peut
y accéder en appelant la méthode getRemoteMediaClient()
sur CastSession
Compute Engine.
Toutes les méthodes de RemoteMediaClient
qui envoient des requêtes au Web Receiver
renvoyer un objet PendingResult qui peut être utilisé pour suivre cette requête.
L'instance de RemoteMediaClient
peut être partagée par
plusieurs parties de l'application, dont certains composants internes
tel que les mini-télécommandes persistantes et
le service de notification.
À cette fin, cette instance prend en charge l'enregistrement de plusieurs instances
RemoteMediaClient.Listener
Définir les métadonnées multimédias
La
MediaMetadata
représente les informations sur un élément multimédia que vous souhaitez caster. La
L'exemple suivant crée une instance MediaMetadata d'un film et définit le paramètre
un titre, un sous-titre et deux images.
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))));
Voir Sélection d'images sur l'utilisation d'images avec des métadonnées multimédias.
Charger le média
Votre application peut charger un élément multimédia, comme indiqué dans le code suivant. Première utilisation
MediaInfo.Builder
avec les métadonnées du média
MediaInfo
Compute Engine. Téléchargez le
RemoteMediaClient
à partir du CastSession
actuel, puis chargez le MediaInfo
dans ce
RemoteMediaClient
Utilisez RemoteMediaClient
pour lire, mettre en pause, etc.
contrôler une application de lecteur multimédia exécutée sur Web Receiver.
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());
Consultez également la section sur à l'aide de pistes multimédias.
Format vidéo 4K
Pour connaître le format vidéo de votre contenu multimédia, utilisez
getVideoInfo()
dans MediaStatus pour obtenir l'instance actuelle
VideoInfo
Cette instance contient le type de format de téléviseur HDR et la hauteur de l'écran
et la largeur en pixels. Les variantes du format 4K sont indiquées par des constantes
HDR_TYPE_*
Contrôler l'envoi de notifications à plusieurs appareils à distance
Lorsqu'un utilisateur caste du contenu, les autres appareils Android connectés au même réseau reçoivent une notification pour lui permettre de contrôler la lecture. Toute personne dont l'appareil reçoit ces notifications peuvent les désactiver pour cet appareil dans les Paramètres sur Google > Google Cast > Afficher les notifications relatives à la télécommande (Les notifications incluent un raccourci vers l'application Paramètres.) Pour en savoir plus, consultez Notifications avec la télécommande Cast
Ajouter une mini-télécommande
Selon l'architecture Cast, Checklist, une application émettrice doit fournir un contrôle persistant, appelé Mini manette qui doit s'afficher lorsque l'utilisateur quitte la page de contenu actuelle pour une autre partie de l’application émettrice. La mini-télécommande affiche un rappel visible à l'utilisateur de la session Cast en cours. En appuyant sur la mini-télécommande, l'utilisateur peut revenir à l'affichage plein écran étendu de la télécommande.
Le framework fournit une vue personnalisée, MiniControllerFragment, que vous pouvez ajouter au bas du fichier de mise en page de chaque activité dans laquelle vous souhaitez afficher mini-télécommande.
<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" />
Lorsque l'application émettrice lit un flux vidéo ou audio en direct, le SDK affiche automatiquement un bouton lecture/arrêt à la place du bouton lecture/pause. dans la mini-télécommande.
Pour définir l'apparence du texte du titre et du sous-titre de cette vue personnalisée, et pour choisir des boutons, consultez Personnalisez la mini-télécommande.
Ajouter une télécommande agrandie
La checklist de conception de Google Cast exige qu'une application émettrice fournisse une version étendue manette pour le contenu multimédia casté. La télécommande agrandie est une version plein écran de la mini-télécommande.
Le SDK Cast fournit un widget pour la télécommande agrandie appelé
ExpandedControllerActivity
Il s'agit d'une classe abstraite que vous devez sous-classer pour ajouter une icône Cast.
Commencez par créer un fichier de ressources de menu que le contrôleur étendu fournira l'icône Cast:
<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>
Créez une classe qui étend ExpandedControllerActivity
.
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; } }
À présent, déclarez votre nouvelle activité dans le fichier manifeste de l'application, dans la balise application
:
<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>
Modifiez CastOptionsProvider
, puis remplacez NotificationOptions
et
CastMediaOptions
pour définir l'activité cible sur votre nouvelle activité:
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(); }
Mettez à jour la méthode loadRemoteMedia
LocalPlayerActivity
pour afficher votre
nouvelle activité lors du chargement du contenu multimédia distant:
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()); }
Lorsque l'application émettrice lit un flux vidéo ou audio en direct, le SDK affiche automatiquement un bouton lecture/arrêt à la place du bouton lecture/pause. dans la télécommande agrandie.
Pour définir l'apparence à l'aide de thèmes, choisissez les boutons à afficher, et ajouter des boutons personnalisés, consultez Personnaliser le contrôleur étendu
Réglage du volume
Le framework gère automatiquement le volume pour l'application émettrice. Le cadre synchronise automatiquement l'appli de l'expéditeur et celle du récepteur Web, de sorte que l'expéditeur L'interface utilisateur indique toujours le volume spécifié par Web Receiver.
Bouton physique de contrôle du volume
Sur Android, vous pouvez utiliser les boutons physiques de l'appareil émetteur pour modifier de la session Cast sur le Web Receiver par défaut pour tous les appareils utilisant Jelly Bean ou version ultérieure
Bouton physique de contrôle du volume avant Jelly Bean
Utiliser les touches de volume physiques pour contrôler le volume de l'appareil Web Receiver sur
Appareils Android antérieurs à Jelly Bean, l'appli émettrice devrait ignorer
dispatchKeyEvent
dans leurs activités, et appeler
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); } }
Ajouter des commandes multimédias aux notifications et à l'écran de verrouillage
Sur Android uniquement, la checklist de conception Google Cast exige qu'une application émettrice soit
mettre en œuvre des commandes multimédias
notification
et que la serrure est verrouillée.
écran,
où l'expéditeur diffuse du contenu, mais que l'appli de l'émetteur n'est pas active. La
vous offre
MediaNotificationService
et
MediaIntentReceiver
pour aider l'application émettrice à créer des commandes multimédias dans une notification et dans la serrure
l'écran.
MediaNotificationService
s'exécute lorsque l'expéditeur diffuse du contenu et affiche un
notification avec une miniature de l'image et des informations sur la diffusion en cours
un élément, un bouton lecture/pause et un bouton d’arrêt.
MediaIntentReceiver
est un BroadcastReceiver
qui gère les actions des utilisateurs depuis
la notification.
Votre application peut configurer le contrôle des notifications et des contenus multimédias depuis l'écran de verrouillage via
NotificationOptions
Votre application peut configurer les boutons de commande à afficher dans les notifications.
Activity
à ouvrir lorsque l'utilisateur appuie sur la notification. Actions si
ne sont pas fournies explicitement, les valeurs par défaut,
MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK
et
MediaIntentReceiver.ACTION_STOP_CASTING
sera utilisé.
// 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();
L'affichage des commandes multimédias depuis les notifications et l'écran de verrouillage est activé par
par défaut. Vous pouvez le désactiver en appelant
setNotificationOptions
avec null dans
CastMediaOptions.Builder
Actuellement, la fonctionnalité de l'écran de verrouillage est activée tant que les notifications sont
est activé.
// ... 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();
Lorsque l'application émettrice lit un flux vidéo ou audio en direct, le SDK affiche automatiquement un bouton lecture/arrêt à la place du bouton lecture/pause. sur la commande de notification, mais pas sur celle de l'écran de verrouillage.
Remarque: Pour afficher les commandes de l'écran de verrouillage sur les appareils antérieurs à Lollipop,
RemoteMediaClient
demandera automatiquement la priorité audio en votre nom.
Gérer les erreurs
Il est très important que les applications émettrices gèrent tous les rappels d'erreur et décident la meilleure réponse à chaque étape du cycle de vie de Cast. L'application peut afficher d'erreur à l'utilisateur ou il peut décider de supprimer la connexion Web Receiver.