Добавьте расширенные функции в свое приложение для 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

Различные компоненты фреймворка (а именно диалог Cast, мини-контроллер и 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, могут потребоваться дополнительные действия:

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

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

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

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

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

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

,

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

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

Различные компоненты фреймворка (а именно диалог Cast, мини-контроллер и 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, могут потребоваться дополнительные действия:

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

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

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

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

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

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