Добавьте расширенные функции в свое приложение для Android

Рекламные паузы

Android Sender SDK обеспечивает поддержку рекламных пауз и сопутствующей рекламы в заданном медиапотоке.

Дополнительную информацию о работе рекламных пауз см. в разделе Обзор рекламных пауз Web Receiver .

Хотя перерывы можно указывать как на стороне отправителя, так и на стороне получателя, рекомендуется указывать их на стороне веб-приемника и приемника 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-виджетов

Различные компоненты фреймворка (а именно диалоговое окно трансляции, мини-контроллер и UIMediaController, если он настроен) будут отображать обложку для текущего транслируемого медиаконтента. URL-адреса обложки обычно включены в MediaMetadata медиаконтента, но у приложения-отправителя может быть альтернативный источник URL-адресов.

Класс ImagePicker определяет способ выбора подходящего изображения из списка в MediaMetadata , исходя из его назначения, например, в качестве миниатюры уведомления или полноэкранного фона. Реализация ImagePicker по умолчанию всегда выбирает первое изображение или возвращает null, если в MediaMetadata изображение отсутствует. Ваше приложение может создать подкласс ImagePicker и переопределить метод onPickImage(MediaMetadata, ImageHints) для предоставления альтернативной реализации, а затем выбрать этот подкласс с помощью метода setImagePicker из CastMediaOptions.Builder . ImageHints предоставляет подсказки ImagePicker о типе и размере изображения, которое будет выбрано для отображения в пользовательском интерфейсе.

Настройка диалоговых окон Cast

Управление жизненным циклом сеанса

SessionManager — это центральное место управления жизненным циклом сеанса. SessionManager отслеживает изменения состояния выбора маршрута Android MediaRouter для запуска, возобновления и завершения сеансов. При выборе маршрута SessionManager создаёт объект Session и пытается запустить или возобновить его. Если маршрут не выбран, SessionManager завершает текущий сеанс.

Поэтому, чтобы SessionManager правильно управлял жизненными циклами сеансов, необходимо убедиться, что:

В зависимости от способа создания диалоговых окон Cast могут потребоваться дополнительные действия:

  • Если вы создаете диалоговые окна Cast с помощью MediaRouteChooserDialog и MediaRouteControllerDialog , то эти диалоговые окна автоматически обновят выбор маршрута в MediaRouter , поэтому ничего делать не нужно.
  • Если вы настраиваете кнопку Cast с помощью CastButtonFactory.setUpMediaRouteButton(Context, Menu, int) или CastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton) , то диалоговые окна фактически создаются с помощью MediaRouteChooserDialog и MediaRouteControllerDialog , поэтому ничего делать не нужно.
  • В других случаях вы будете создавать пользовательские диалоговые окна Cast, поэтому вам необходимо следовать приведенным выше инструкциям, чтобы обновить состояние выбора маршрута в MediaRouter .

Состояние нулевых устройств

Если вы создаёте пользовательские диалоговые окна Cast, ваш пользовательский диалог MediaRouteChooserDialog должен корректно обрабатывать ситуацию, когда не найдено ни одного устройства. В диалоговом окне должны быть индикаторы, которые будут чётко указывать пользователям, когда приложение всё ещё пытается найти устройства, а когда попытка обнаружения уже завершена.

Если вы используете MediaRouteChooserDialog по умолчанию, то нулевое состояние устройств уже обрабатывается.

Следующие шаги

На этом мы завершаем список функций, которые можно добавить в приложение Android Sender. Теперь вы можете создать приложение Sender для другой платформы ( iOS или веб-приложение ) или создать приложение Web Receiver .