Рекламные паузы
Android Sender SDK поддерживает рекламные паузы и сопутствующие объявления в медиаконтенте.
Дополнительную информацию о том, как работают рекламные паузы, можно найти в обзоре рекламных пауз веб-приемника.
Хотя перерывы можно задавать как на отправителе, так и на получателе, мы рекомендуем делать это на веб-получателе и получателе Android TV, чтобы обеспечить единообразное поведение на разных платформах.
На устройствах Android рекламные паузы в команде загрузки задаются с помощью параметров AdBreakClipInfo и 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);
Добавить настраиваемые действия
Приложение отправителя может расширить возможности MediaIntentReceiver, чтобы выполнять настраиваемые действия или переопределять его поведение. Если вы реализовали собственный класс MediaIntentReceiver, добавьте его в манифест и укажите его название в CastMediaOptions. В этом примере показаны настраиваемые действия, которые переопределяют переключение удаленного воспроизведения мультимедиа, нажатие кнопки мультимедиа и другие типы действий.
// 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) { } }
Как добавить специальный канал
Чтобы приложение отправителя могло взаимодействовать с приложением получателя, необходимо создать специальный канал. Отправитель может использовать пользовательский канал для отправки строковых сообщений получателю. Каждый клиентский канал определяется уникальным пространством имен и должен начинаться с префикса urn:x-cast:, например urn:x-cast:com.example.custom. Можно создать несколько пользовательских каналов, у каждого из которых будет уникальное пространство имен. Приложение получателя также может отправлять и получать сообщения, используя то же пространство имен.
Собственный канал реализуется с помощью интерфейса 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); } }
После того как приложение отправителя подключено к приложению получателя, пользовательский канал можно создать с помощью метода setMessageReceivedCallbacks:
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); }
После создания специального канала отправитель может использовать метод sendMessage, чтобы отправлять получателю строковые сообщения по этому каналу:
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); } } }
Поддержка автовоспроизведения
Подробнее об API для автовоспроизведения и добавления в очередь…
Как переопределить выбор изображений для виджетов UX
Различные компоненты фреймворка (диалоговое окно Cast, мини-контроллер и UIMediaController, если он настроен) будут показывать обложку текущего медиаконтента. URL изображений обычно включаются в MediaMetadata для медиафайлов, но у приложения-отправителя может быть альтернативный источник URL.
Класс ImagePicker определяет способ выбора подходящего изображения из списка в MediaMetadata в зависимости от того, как оно будет использоваться, например в качестве значка уведомления или полноэкранного фона. Реализация ImagePicker по умолчанию всегда выбирает первое изображение или возвращает значение null, если в MediaMetadata нет изображений. Ваше приложение может создать подкласс ImagePicker и переопределить метод onPickImage(MediaMetadata, ImageHints), чтобы реализовать альтернативный вариант, а затем выбрать этот подкласс с помощью метода setImagePicker класса CastMediaOptions.Builder.
ImageHints
содержит подсказки для ImagePicker о типе и размере изображения, которое нужно
выбрать для показа в интерфейсе.
Настройка диалоговых окон Cast
Управление жизненным циклом сеанса
SessionManager – это центральный элемент для управления жизненным циклом сеанса. SessionManager отслеживает изменения состояния выбора маршрута в AndroidMediaRouter, чтобы начинать, возобновлять и завершать сеансы. Когда маршрут выбран, SessionManager создает объект Session и пытается запустить или возобновить его. Если маршрут отменен, SessionManager завершит текущий сеанс.
Чтобы SessionManager правильно управлял жизненными циклами сеансов, необходимо обеспечить следующее:
- В диалоговом окне выбора маршрута вызовите
MediaRouter.selectRoute(MediaRouter.RouteInfo), когда пользователь выберет устройство. - В диалоговом окне контроллера маршрута (в подключенном состоянии или состоянии трансляции) вызовите
MediaRouter.unselect(int), когда пользователь остановит трансляцию.
В зависимости от того, как вы создаете диалоговые окна Cast, могут потребоваться дополнительные действия:
- Если вы создаете диалоговые окна Cast с помощью
MediaRouteChooserDialogиMediaRouteControllerDialog, то эти диалоговые окна будут автоматически обновлять выбор маршрута вMediaRouter, поэтому ничего делать не нужно. - Если вы настроили кнопку трансляции с помощью
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)илиCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton), то диалоговые окна создаются с помощьюMediaRouteChooserDialogиMediaRouteControllerDialog, поэтому вам ничего не нужно делать. - В остальных случаях вам нужно будет создать собственные диалоговые окна Cast, поэтому следуйте приведенным выше инструкциям, чтобы обновить состояние выбора маршрута в
MediaRouter.
Состояние "Нет устройств"
Если вы создаете собственные диалоговые окна Cast, то в них
MediaRouteChooserDialog должна быть предусмотрена обработка ситуации, когда не
найдено ни одного устройства. В диалоговом окне должны быть индикаторы, которые показывают пользователям, когда приложение пытается найти устройства, а когда попытка поиска больше не активна.
Если вы используете MediaRouteChooserDialog по умолчанию, то состояние, когда устройств нет, уже обработано.
Дальнейшие действия
Это все функции, которые можно добавить в приложение-отправитель для Android. Теперь вы можете создать приложение-отправитель для другой платформы (iOS или веб-приложение) или веб-приложение-приемник.