Pausas publicitarias
El SDK de remitente de Android ofrece compatibilidad con pausas publicitarias y anuncios complementarios en un flujo de medios determinado.
Consulta la descripción general de las pausas publicitarias del receptor web para obtener más información sobre cómo funcionan.
Si bien se pueden especificar pausas tanto para el remitente como para el receptor, se recomienda que se especifican en el receptor web y el receptor de Android TV para que sea coherente el comportamiento de los usuarios en las plataformas.
En Android, especifica pausas publicitarias en un comando de carga con
AdBreakClipInfo
y AdBreakInfo
:
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);
Agrega acciones personalizadas
Una app del remitente puede extender
MediaIntentReceiver
para controlar acciones personalizadas o anular su comportamiento. Si implementaste
propio MediaIntentReceiver
, debes agregarlo al manifiesto y, además, establecer su
en el CastMediaOptions
. En este ejemplo, se proporcionan acciones personalizadas que
anular activar o desactivar la reproducción remota de contenido multimedia, presionar el botón multimedia y otros tipos
de acciones.
// 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) { } }
Agregar un canal personalizado
Para que la app emisora se comunique con la app receptora, tu app debe
crear un canal personalizado. El remitente puede usar el canal personalizado para enviar una cadena.
mensajes nuevos al receptor. Cada canal personalizado se define por un
y debe comenzar con el prefijo urn:x-cast:
. Por ejemplo,
urn:x-cast:com.example.custom
Es posible tener varias cuentas
canales, cada uno con un espacio de nombres único. La app del receptor también puede enviar y recibir mensajes con el mismo espacio de nombres.
El canal personalizado se implementa con el
Cast.MessageReceivedCallback
:
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); } }
Una vez que se conecta la app emisora con la app receptora, el canal personalizado puede
crearse con
setMessageReceivedCallbacks
método:
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); }
Una vez que se crea el canal personalizado, el remitente puede usar el método sendMessage
para enviar mensajes de cadena al receptor a través de ese canal:
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); } } }
Compatibilidad con la reproducción automática
Consulta la sección APIs de reproducción automática y de cola.
Anular la selección de imágenes para los widgets de UX
Varios componentes del framework (como el diálogo Cast, la interfaz
controlador y UIMediaController, si está configurado) mostrará el material gráfico.
para el contenido que se está transmitiendo. Las URLs del material gráfico de la imagen son, por lo general,
incluido en el MediaMetadata
del contenido multimedia, pero la app emisora puede tener un
fuente alternativa para las URL.
El
ImagePicker
define un medio para seleccionar una imagen apropiada de la lista de imágenes.
en un objeto MediaMetadata
, según el uso de la imagen, por ejemplo, la notificación
miniatura o pantalla completa. La implementación predeterminada de ImagePicker
siempre elige la primera imagen, o devuelve un valor nulo si no hay ninguna imagen disponible en
MediaMetadata
Tu app puede crear la subclase ImagePicker
y anular el
onPickImage(MediaMetadata, ImageHints)
para brindar una implementación alternativa y seleccionar esa subclase
con el
setImagePicker
método de CastMediaOptions.Builder
.
ImageHints
proporciona sugerencias a ImagePicker
sobre el tipo y el tamaño de una imagen que se debe
seleccionados para mostrarse en la IU.
Cómo personalizar los diálogos de transmisión
Cómo administrar el ciclo de vida de la sesión
SessionManager
es el lugar central para administrar
el ciclo de vida de la sesión. SessionManager
reproducciones
a Android
MediaRouter
el estado de selección de ruta cambia para iniciar, reanudar y finalizar sesiones. Cuando una ruta se
seleccionado, SessionManager
creará un
Session
e intenta iniciarlo o reanudarlo. Cuando no se selecciona una ruta,
SessionManager
finalizará la sesión actual.
Por lo tanto, para asegurarte de que SessionManager
administre los ciclos de vida de las sesiones de forma correcta, debes
debe asegurarse de lo siguiente:
- En el diálogo del selector de ruta, llama a
MediaRouter.selectRoute(MediaRouter.RouteInfo)
cuando un usuario seleccione un dispositivo. - En el diálogo del controlador de ruta (ya sea en Connected
estado o
transmisiones
state),
llamar
MediaRouter.unselect(int)
cuando el usuario detenga la transmisión.
Según cómo crees los diálogos de Cast, es posible que debas realizar acciones adicionales:
- Si creas diálogos de Cast con
MediaRouteChooserDialog
yMediaRouteControllerDialog
, estos diálogos actualizarán la selección de ruta enMediaRouter
automáticamente, así que no es necesario hacer nada. - Si configuras el botón para transmitir con
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
oCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
, los diálogos creada conMediaRouteChooserDialog
yMediaRouteControllerDialog
, por lo que tampoco hay que hacer nada. - Para otros casos, crearás diálogos personalizados de Cast, por lo que deberás
sigue las instrucciones anteriores para actualizar el estado de selección de ruta en
MediaRouter
Estado sin dispositivos
Si creas diálogos de Cast personalizados, tu MediaRouteChooserDialog
personalizado debería controlar correctamente el caso de que no se encuentre ningún dispositivo. El diálogo debe tener indicadores que aclaren a los usuarios cuándo
la app aún intenta encontrar dispositivos y cuando el intento de detección no es
por más tiempo.
Si usas el MediaRouteChooserDialog
predeterminado, el estado de cero dispositivos
ya se maneja.
Próximos pasos
Aquí concluye las funciones que puedes agregar a tu app de Android Sender. Ahora puedes compilar una app emisora para otra plataforma (iOS o Web) compilar una app del receptor web