1. Обзор
Эта лаборатория научит вас, как изменить существующее видеоприложение Android для трансляции контента на устройство с поддержкой Google Cast .
Что такое Google Cast?
Google Cast позволяет пользователям транслировать контент с мобильного устройства на телевизор. Затем пользователи могут использовать свое мобильное устройство в качестве пульта дистанционного управления для воспроизведения мультимедиа на телевизоре.
Google Cast SDK позволяет расширить возможности вашего приложения для управления телевизором или аудиосистемой. Cast SDK позволяет добавлять необходимые компоненты пользовательского интерфейса на основе контрольного списка Google Cast Design .
Контрольный список Google Cast Design предназначен для того, чтобы сделать использование Cast простым и предсказуемым на всех поддерживаемых платформах.
Что мы собираемся строить?
После завершения этой лабораторной работы у вас будет видеоприложение для Android, которое сможет транслировать видео на устройство с поддержкой Google Cast.
Что вы узнаете
- Как добавить Google Cast SDK в пример приложения для видео.
- Как добавить кнопку Cast для выбора устройства Google Cast.
- Как подключиться к устройству Cast и запустить медиа-ресивер.
- Как скинуть видео.
- Как добавить мини-контроллер Cast в ваше приложение.
- Как поддерживать мультимедийные уведомления и элементы управления экраном блокировки.
- Как добавить расширенный контроллер.
- Как обеспечить вводное наложение.
- Как настроить виджеты Cast.
- Как интегрироваться с Cast Connect
Что вам понадобится
- Последняя версия Android SDK .
- Android-студия версии 3.2+
- Одно мобильное устройство с Android 4.1+ Jelly Bean (уровень API 16).
- USB-кабель для передачи данных для подключения мобильного устройства к компьютеру разработки.
- Устройство Google Cast, например Chromecast или Android TV, с доступом в Интернет.
- Телевизор или монитор с входом HDMI.
- Chromecast с Google TV требуется для проверки интеграции Cast Connect, но не является обязательным для остальной части Codelab. Если у вас его нет, можете пропустить шаг «Добавить поддержку Cast Connect» в конце этого руководства.
Опыт
- Вам потребуются предыдущие знания разработки на Kotlin и Android.
- Вам также потребуются предварительные знания о просмотре телевизора :)
Как вы будете использовать этот урок?
Как бы вы оценили свой опыт создания приложений для Android?
Как бы вы оценили свои впечатления от просмотра телевидения?
2. Получите пример кода
Вы можете загрузить весь пример кода на свой компьютер...
и распакуйте загруженный zip-файл.
3. Запустите пример приложения.
Сначала давайте посмотрим, как выглядит готовый пример приложения. Приложение представляет собой базовый видеоплеер. Пользователь может выбрать видео из списка, а затем воспроизвести его локально на устройстве или транслировать его на устройство Google Cast.
После загрузки кода следующие инструкции описывают, как открыть и запустить готовый пример приложения в Android Studio :
Выберите « Импорт проекта» на экране приветствия или пункты меню «Файл» > «Создать» > «Импортировать проект...» .
Выберите app-done
из папки примера кода и нажмите «ОК».
Нажмите Файл > Синхронизировать проект с файлами Gradle .
Включите отладку по USB на вашем устройстве Android — на Android 4.2 и более поздних версиях экран параметров разработчика по умолчанию скрыт. Чтобы сделать его видимым, перейдите в «Настройки» > «О телефоне» и семь раз нажмите «Номер сборки» . Вернитесь к предыдущему экрану, перейдите в «Система» > «Дополнительно» и нажмите «Параметры разработчика» внизу, затем нажмите «Отладка по USB» , чтобы включить ее.
Подключите свое Android-устройство и нажмите кнопку Кнопка «Выполнить» в Android Studio. Через несколько секунд вы должны увидеть видеоприложение под названием Cast Videos .
Нажмите кнопку Cast в приложении для видео и выберите свое устройство Google Cast.
Выберите видео и нажмите кнопку воспроизведения.
Видео начнет воспроизводиться на вашем устройстве Google Cast.
Отобразится расширенный контроллер. Вы можете использовать кнопку воспроизведения/паузы для управления воспроизведением.
Вернитесь к списку видео.
Мини-контроллер теперь виден в нижней части экрана.
Нажмите кнопку паузы на мини-контроллере, чтобы приостановить видео на ресивере. Нажмите кнопку воспроизведения на мини-контроллере, чтобы продолжить воспроизведение видео еще раз.
Нажмите кнопку «Домой» на мобильном устройстве. Потяните вниз уведомления, и теперь вы должны увидеть уведомление о сеансе трансляции.
Заблокируйте свой телефон, и когда вы его разблокируете, вы увидите уведомление на экране блокировки, позволяющее управлять воспроизведением мультимедиа или остановить трансляцию.
Вернитесь в приложение для видео и нажмите кнопку Cast, чтобы остановить трансляцию на устройстве Google Cast.
Часто задаваемые вопросы
4. Подготовьте стартовый проект
Нам нужно добавить поддержку Google Cast в загруженное вами стартовое приложение. Вот некоторая терминология Google Cast, которую мы будем использовать в этой лаборатории кода:
- приложение- отправитель работает на мобильном устройстве или ноутбуке,
- приложение- приемник работает на устройстве Google Cast.
Теперь вы готовы работать над стартовым проектом с помощью Android Studio:
- Выберите каталог
app-start
из загруженного примера кода (выберите «Импорт проекта» на экране приветствия или пункт меню «Файл» > «Создать» > «Импортировать проект...» ). - Нажмите кнопку Кнопка «Синхронизировать проект с файлами Gradle» .
- Нажмите кнопку Кнопка «Выполнить», чтобы запустить приложение и изучить пользовательский интерфейс.
Дизайн приложения
Приложение получает список видео с удаленного веб-сервера и предоставляет пользователю список для просмотра. Пользователи могут выбрать видео, чтобы просмотреть подробности, или воспроизвести его локально на мобильном устройстве.
Приложение состоит из двух основных действий: VideoBrowserActivity
и LocalPlayerActivity
. Чтобы интегрировать функциональность Google Cast, Activity необходимо наследовать либо от AppCompatActivity
, либо от его родительского объекта FragmentActivity
. Это ограничение существует, поскольку нам нужно будет добавить MediaRouteButton
(предоставленный в библиотеке поддержки MediaRouter ) в качестве MediaRouteActionProvider
, и это будет работать только в том случае, если активность наследуется от вышеупомянутых классов. Библиотека поддержки MediaRouter зависит от библиотеки поддержки AppCompat , которая предоставляет необходимые классы.
ВидеоБраузерАктивность
Это действие содержит Fragment
( VideoBrowserFragment
). Этот список поддерживается ArrayAdapter
( VideoListAdapter
). Список видео и связанные с ним метаданные размещаются на удаленном сервере в виде файла JSON . AsyncTaskLoader
( VideoItemLoader
) извлекает этот JSON и обрабатывает его для создания списка объектов MediaItem
.
Объект MediaItem
моделирует видео и связанные с ним метаданные, такие как заголовок, описание, URL-адрес потока, URL-адрес вспомогательных изображений и связанные текстовые дорожки (для субтитров), если таковые имеются. Объект MediaItem
передается между действиями, поэтому у MediaItem
есть служебные методы для преобразования его в Bundle
и наоборот.
Когда загрузчик создает список MediaItems
, он передает этот список в VideoListAdapter
, который затем представляет список MediaItems
в VideoBrowserFragment
. Пользователю предоставляется список миниатюр видео с кратким описанием каждого видео. Когда элемент выбран, соответствующий MediaItem
преобразуется в Bundle
и передается в LocalPlayerActivity
.
LocalPlayerActivity
Это действие отображает метаданные о конкретном видео и позволяет пользователю воспроизводить видео локально на мобильном устройстве.
В действии размещается VideoView
, некоторые элементы управления мультимедиа и текстовая область для отображения описания выбранного видео. Плеер закрывает верхнюю часть экрана, оставляя место для подробного описания видео ниже. Пользователь может воспроизводить/приостанавливать видео или искать локальное воспроизведение видео.
Зависимости
Поскольку мы используем AppCompatActivity
, нам нужна библиотека поддержки AppCompat. Для управления списком видео и асинхронного получения изображений для списка мы используем библиотеку Volley .
Часто задаваемые вопросы
5. Добавление кнопки трансляции
Приложение с поддержкой Cast отображает кнопку Cast в каждом из своих действий. При нажатии на кнопку Cast отображается список устройств Cast, которые пользователь может выбрать. Если пользователь воспроизводил контент локально на устройстве-отправителе, выбор устройства Cast запускает или возобновляет воспроизведение на этом устройстве Cast. В любой момент во время сеанса Cast пользователь может нажать кнопку Cast и прекратить трансляцию вашего приложения на устройство Cast. Пользователь должен иметь возможность подключаться к устройству Cast или отключаться от него во время любой активности вашего приложения, как описано в контрольном списке Google Cast Design .
Зависимости
Обновите файл приложения build.gradle, включив в него необходимые зависимости библиотеки:
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'androidx.mediarouter:mediarouter:1.3.1'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.google.android.gms:play-services-cast-framework:21.1.0'
implementation 'com.android.volley:volley:1.2.1'
implementation "androidx.core:core-ktx:1.8.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
Синхронизируйте проект, чтобы убедиться, что сборка проекта выполнена без ошибок.
Инициализация
Платформа Cast имеет глобальный одноэлементный объект CastContext
, который координирует все взаимодействия Cast.
Необходимо реализовать интерфейс OptionsProvider
для предоставления CastOptions
необходимых для инициализации синглтона CastContext
. Наиболее важным параметром является идентификатор приложения-приемника, который используется для фильтрации результатов обнаружения устройств Cast и для запуска приложения-приемника при запуске сеанса Cast.
Когда вы разрабатываете собственное приложение с поддержкой Cast, вам необходимо зарегистрироваться в качестве разработчика Cast, а затем получить идентификатор приложения для своего приложения. Для этой лаборатории кода мы будем использовать пример идентификатора приложения.
Добавьте следующий новый файл CastOptionsProvider.kt
в пакет com.google.sample.cast.refplayer
проекта:
package com.google.sample.cast.refplayer
import android.content.Context
import com.google.android.gms.cast.framework.OptionsProvider
import com.google.android.gms.cast.framework.CastOptions
import com.google.android.gms.cast.framework.SessionProvider
class CastOptionsProvider : OptionsProvider {
override fun getCastOptions(context: Context): CastOptions {
return CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.build()
}
override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
return null
}
}
Теперь объявите OptionsProvider
в теге application
файла AndroidManifest.xml
приложения:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />
Лениво инициализируйте CastContext
в методе VideoBrowserActivity
onCreate:
import com.google.android.gms.cast.framework.CastContext
private var mCastContext: CastContext? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.video_browser)
setupActionBar()
mCastContext = CastContext.getSharedInstance(this)
}
Добавьте ту же логику инициализации в LocalPlayerActivity
.
Кнопка трансляции
Теперь, когда CastContext
инициализирован, нам нужно добавить кнопку Cast, чтобы пользователь мог выбрать устройство Cast. Кнопка Cast реализована с помощью MediaRouteButton
из библиотеки поддержки MediaRouter . Как и любой значок действия, который вы можете добавить в свою активность (с помощью ActionBar
или Toolbar
), вам сначала необходимо добавить соответствующий пункт меню в свое меню.
Отредактируйте файл res/menu/browse.xml
и добавьте в меню перед пунктом настроек пункт MediaRouteActionProvider
:
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
Переопределите метод onCreateOptionsMenu()
для VideoBrowserActivity
, используя CastButtonFactory
для подключения MediaRouteButton
к платформе Cast:
import com.google.android.gms.cast.framework.CastButtonFactory
private var mediaRouteMenuItem: MenuItem? = null
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.browse, menu)
mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu,
R.id.media_route_menu_item)
return true
}
Аналогичным образом переопределите onCreateOptionsMenu
в LocalPlayerActivity
.
Нажмите кнопку Кнопка «Выполнить» , чтобы запустить приложение на мобильном устройстве. Вы должны увидеть кнопку Cast на панели действий приложения, и когда вы нажмете на нее, она отобразит список устройств Cast в вашей локальной сети. Обнаружение устройства управляется автоматически с помощью CastContext
. Выберите устройство Cast, и образец приложения-приемника загрузится на устройство Cast. Вы можете переключаться между действиями просмотра и действиями локального игрока, а состояние кнопки трансляции синхронизируется.
Мы не подключили поддержку воспроизведения мультимедиа, поэтому вы пока не можете воспроизводить видео на устройстве Cast. Нажмите кнопку Cast, чтобы отключиться.
6. Кастинг видеоконтента
Мы расширим пример приложения, чтобы он также мог удаленно воспроизводить видео на устройстве Cast. Для этого нам нужно прослушивать различные события, генерируемые средой Cast.
Кастинг СМИ
На высоком уровне, если вы хотите воспроизвести медиафайл на устройстве Cast, вам необходимо сделать следующее:
- Создайте объект
MediaInfo
, который моделирует элемент мультимедиа. - Подключитесь к устройству Cast и запустите приложение-приемник.
- Загрузите объект
MediaInfo
в приемник и воспроизведите контент. - Отслеживайте статус СМИ.
- Отправляйте команды воспроизведения на приемник на основе взаимодействия с пользователем.
Мы уже выполнили Шаг 2 в предыдущем разделе. Шаг 3 легко выполнить с помощью платформы Cast. Шаг 1 представляет собой сопоставление одного объекта с другим; MediaInfo
— это то, что понимает платформа Cast, а MediaItem
— это инкапсуляция нашего приложения для элемента мультимедиа; мы можем легко сопоставить MediaItem
с MediaInfo
.
Пример приложения LocalPlayerActivity
уже различает локальное и удаленное воспроизведение, используя это перечисление:
private var mLocation: PlaybackLocation? = null
enum class PlaybackLocation {
LOCAL, REMOTE
}
enum class PlaybackState {
PLAYING, PAUSED, BUFFERING, IDLE
}
В этой кодовой лаборатории вам не важно точно понимать, как работает вся логика примера проигрывателя. Важно понимать, что медиаплеер вашего приложения необходимо будет изменить, чтобы он одинаково распознавал два места воспроизведения.
В настоящий момент локальный проигрыватель всегда находится в состоянии локального воспроизведения, поскольку он еще ничего не знает о состояниях кастинга. Нам нужно обновить пользовательский интерфейс на основе переходов состояний, которые происходят в среде Cast. Например, если мы начнем трансляцию, нам нужно остановить локальное воспроизведение и отключить некоторые элементы управления. Аналогично, если мы прекратим трансляцию во время этого действия, нам нужно будет перейти к локальному воспроизведению. Чтобы справиться с этим, нам нужно прослушивать различные события, генерируемые средой Cast.
Управление сеансами трансляции
Для платформы Cast сеанс Cast объединяет этапы подключения к устройству, запуска (или присоединения), подключения к приложению-получателю и инициализации канала управления мультимедиа, если это необходимо. Канал управления мультимедиа — это то, как платформа Cast отправляет и получает сообщения от медиаплеера-получателя.
Сеанс трансляции запускается автоматически, когда пользователь выбирает устройство с помощью кнопки трансляции, и автоматически останавливается, когда пользователь отключается. Повторное подключение к сеансу получателя из-за проблем с сетью также автоматически обрабатывается Cast SDK.
Давайте добавим SessionManagerListener
в LocalPlayerActivity
:
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
...
private var mSessionManagerListener: SessionManagerListener<CastSession>? = null
private var mCastSession: CastSession? = null
...
private fun setupCastListener() {
mSessionManagerListener = object : SessionManagerListener<CastSession> {
override fun onSessionEnded(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionResumed(session: CastSession, wasSuspended: Boolean) {
onApplicationConnected(session)
}
override fun onSessionResumeFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionStarted(session: CastSession, sessionId: String) {
onApplicationConnected(session)
}
override fun onSessionStartFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionStarting(session: CastSession) {}
override fun onSessionEnding(session: CastSession) {}
override fun onSessionResuming(session: CastSession, sessionId: String) {}
override fun onSessionSuspended(session: CastSession, reason: Int) {}
private fun onApplicationConnected(castSession: CastSession) {
mCastSession = castSession
if (null != mSelectedMedia) {
if (mPlaybackState == PlaybackState.PLAYING) {
mVideoView!!.pause()
loadRemoteMedia(mSeekbar!!.progress, true)
return
} else {
mPlaybackState = PlaybackState.IDLE
updatePlaybackLocation(PlaybackLocation.REMOTE)
}
}
updatePlayButton(mPlaybackState)
invalidateOptionsMenu()
}
private fun onApplicationDisconnected() {
updatePlaybackLocation(PlaybackLocation.LOCAL)
mPlaybackState = PlaybackState.IDLE
mLocation = PlaybackLocation.LOCAL
updatePlayButton(mPlaybackState)
invalidateOptionsMenu()
}
}
}
В активности LocalPlayerActivity
мы хотим получать информацию, когда мы подключаемся или отключаемся от устройства Cast, чтобы мы могли переключиться на локальный проигрыватель или обратно. Обратите внимание, что соединение может быть нарушено не только из-за запуска экземпляра вашего приложения на вашем мобильном устройстве, но также из-за другого экземпляра вашего (или другого) приложения, запущенного на другом мобильном устройстве.
Текущий активный сеанс доступен как SessionManager.getCurrentSession()
. Сеансы создаются и закрываются автоматически в ответ на взаимодействие пользователя с диалоговыми окнами трансляции.
Нам нужно зарегистрировать прослушиватель сеанса и инициализировать некоторые переменные, которые мы будем использовать в активности. Измените метод LocalPlayerActivity
onCreate
на:
import com.google.android.gms.cast.framework.CastContext
...
private var mCastContext: CastContext? = null
...
override fun onCreate(savedInstanceState: Bundle?) {
...
mCastContext = CastContext.getSharedInstance(this)
mCastSession = mCastContext!!.sessionManager.currentCastSession
setupCastListener()
...
loadViews()
...
val bundle = intent.extras
if (bundle != null) {
....
if (shouldStartPlayback) {
....
} else {
if (mCastSession != null && mCastSession!!.isConnected()) {
updatePlaybackLocation(PlaybackLocation.REMOTE)
} else {
updatePlaybackLocation(PlaybackLocation.LOCAL)
}
mPlaybackState = PlaybackState.IDLE
updatePlayButton(mPlaybackState)
}
}
...
}
Загрузка мультимедиа
В Cast SDK RemoteMediaClient
предоставляет набор удобных API для управления удаленным воспроизведением мультимедиа на приемнике. Для CastSession
, поддерживающего воспроизведение мультимедиа, SDK автоматически создаст экземпляр RemoteMediaClient
. Доступ к нему можно получить, вызвав метод getRemoteMediaClient()
в экземпляре CastSession
. Добавьте следующие методы в LocalPlayerActivity
, чтобы загрузить выбранное в данный момент видео на приемник:
import com.google.android.gms.cast.framework.media.RemoteMediaClient
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaLoadOptions
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.common.images.WebImage
import com.google.android.gms.cast.MediaLoadRequestData
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
if (mCastSession == null) {
return
}
val remoteMediaClient = mCastSession!!.remoteMediaClient ?: return
remoteMediaClient.load( MediaLoadRequestData.Builder()
.setMediaInfo(buildMediaInfo())
.setAutoplay(autoPlay)
.setCurrentTime(position.toLong()).build())
}
private fun buildMediaInfo(): MediaInfo? {
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
mSelectedMedia?.studio?.let { movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, it) }
mSelectedMedia?.title?.let { movieMetadata.putString(MediaMetadata.KEY_TITLE, it) }
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(0))))
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(1))))
return mSelectedMedia!!.url?.let {
MediaInfo.Builder(it)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType("videos/mp4")
.setMetadata(movieMetadata)
.setStreamDuration((mSelectedMedia!!.duration * 1000).toLong())
.build()
}
}
Теперь обновите различные существующие методы, чтобы использовать логику сеанса Cast для поддержки удаленного воспроизведения:
private fun play(position: Int) {
startControllersTimer()
when (mLocation) {
PlaybackLocation.LOCAL -> {
mVideoView!!.seekTo(position)
mVideoView!!.start()
}
PlaybackLocation.REMOTE -> {
mPlaybackState = PlaybackState.BUFFERING
updatePlayButton(mPlaybackState)
//seek to a new position within the current media item's new position
//which is in milliseconds from the beginning of the stream
mCastSession!!.remoteMediaClient?.seek(position.toLong())
}
else -> {}
}
restartTrickplayTimer()
}
private fun togglePlayback() {
...
PlaybackState.IDLE -> when (mLocation) {
...
PlaybackLocation.REMOTE -> {
if (mCastSession != null && mCastSession!!.isConnected) {
loadRemoteMedia(mSeekbar!!.progress, true)
}
}
else -> {}
}
...
}
override fun onPause() {
...
mCastContext!!.sessionManager.removeSessionManagerListener(
mSessionManagerListener!!, CastSession::class.java)
}
override fun onResume() {
Log.d(TAG, "onResume() was called")
mCastContext!!.sessionManager.addSessionManagerListener(
mSessionManagerListener!!, CastSession::class.java)
if (mCastSession != null && mCastSession!!.isConnected) {
updatePlaybackLocation(PlaybackLocation.REMOTE)
} else {
updatePlaybackLocation(PlaybackLocation.LOCAL)
}
super.onResume()
}
Для метода updatePlayButton
измените значение переменной isConnected
:
private fun updatePlayButton(state: PlaybackState?) {
...
val isConnected = (mCastSession != null
&& (mCastSession!!.isConnected || mCastSession!!.isConnecting))
...
}
Теперь нажмите кнопку Кнопка «Выполнить» , чтобы запустить приложение на мобильном устройстве. Подключитесь к устройству Cast и начните воспроизведение видео. Вы должны увидеть видео, воспроизводимое на ресивере.
7. Мини-контроллер
Контрольный список проектирования Cast требует, чтобы все приложения Cast имели мини-контроллер , который появляется, когда пользователь уходит с текущей страницы контента. Мини-контроллер обеспечивает мгновенный доступ и видимое напоминание о текущем сеансе трансляции.
Cast SDK предоставляет настраиваемое представление MiniControllerFragment
, которое можно добавить в файл макета приложения с действиями, в которых вы хотите отобразить мини-контроллер.
Добавьте следующее определение фрагмента в конец файлов res/layout/player_activity.xml
и res/layout/video_browser.xml
:
<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"/>
Нажмите кнопку Кнопка «Выполнить», чтобы запустить приложение и транслировать видео. Когда на приемнике начнется воспроизведение, вы должны увидеть мини-контроллер внизу каждого действия. Управлять дистанционным воспроизведением можно с помощью мини-контроллера. Если вы перемещаетесь между активностью просмотра и активностью локального проигрывателя, состояние мини-контроллера должно оставаться синхронизированным с состоянием воспроизведения мультимедиа-приемника.
8. Экран уведомлений и блокировки.
Контрольный список дизайна Google Cast требует, чтобы приложение-отправитель реализовало элементы управления мультимедиа из уведомления и экрана блокировки .
Cast SDK предоставляет MediaNotificationService
, помогающий приложению-отправителю создавать элементы управления мультимедиа для уведомлений и экрана блокировки. Служба автоматически добавляется в манифест вашего приложения с помощью gradle.
MediaNotificationService
будет работать в фоновом режиме во время трансляции отправителя и отображать уведомление с миниатюрой изображения и метаданными о текущем элементе трансляции, кнопкой воспроизведения/паузы и кнопкой остановки.
Элементы управления уведомлениями и экраном блокировки можно включить с помощью CastOptions
при инициализации CastContext
. Элементы управления мультимедиа для уведомлений и экрана блокировки включены по умолчанию. Функция блокировки экрана включена, пока включено уведомление.
Отредактируйте CastOptionsProvider
и измените реализацию getCastOptions
чтобы она соответствовала этому коду:
import com.google.android.gms.cast.framework.media.CastMediaOptions
import com.google.android.gms.cast.framework.media.NotificationOptions
override fun getCastOptions(context: Context): CastOptions {
val notificationOptions = NotificationOptions.Builder()
.setTargetActivityClassName(VideoBrowserActivity::class.java.name)
.build()
val mediaOptions = CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.build()
return CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.setCastMediaOptions(mediaOptions)
.build()
}
Нажмите кнопку Кнопка «Выполнить» , чтобы запустить приложение на мобильном устройстве. Включите видео и закройте образец приложения. Должно появиться уведомление о видео, воспроизводимом в данный момент на ресивере. Заблокируйте мобильное устройство, и на экране блокировки теперь должны отображаться элементы управления воспроизведением мультимедиа на устройстве Cast.
9. Вводное наложение
Контрольный список дизайна Google Cast требует, чтобы приложение-отправитель представило кнопку Cast существующим пользователям, чтобы сообщить им, что приложение-отправитель теперь поддерживает трансляцию, а также помогает пользователям, впервые использующим Google Cast.
Cast SDK предоставляет настраиваемое представление IntroductoryOverlay
, которое можно использовать для выделения кнопки трансляции, когда она впервые отображается пользователям. Добавьте следующий код в VideoBrowserActivity
:
import com.google.android.gms.cast.framework.IntroductoryOverlay
import android.os.Looper
private var mIntroductoryOverlay: IntroductoryOverlay? = null
private fun showIntroductoryOverlay() {
mIntroductoryOverlay?.remove()
if (mediaRouteMenuItem?.isVisible == true) {
Looper.myLooper().run {
mIntroductoryOverlay = com.google.android.gms.cast.framework.IntroductoryOverlay.Builder(
this@VideoBrowserActivity, mediaRouteMenuItem!!)
.setTitleText("Introducing Cast")
.setSingleTime()
.setOnOverlayDismissedListener(
object : IntroductoryOverlay.OnOverlayDismissedListener {
override fun onOverlayDismissed() {
mIntroductoryOverlay = null
}
})
.build()
mIntroductoryOverlay!!.show()
}
}
}
Теперь добавьте CastStateListener
и вызовите метод showIntroductoryOverlay
, когда устройство Cast доступно, изменив метод onCreate
и переопределив методы onResume
и onPause
, чтобы они соответствовали следующему:
import com.google.android.gms.cast.framework.CastState
import com.google.android.gms.cast.framework.CastStateListener
private var mCastStateListener: CastStateListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.video_browser)
setupActionBar()
mCastStateListener = object : CastStateListener {
override fun onCastStateChanged(newState: Int) {
if (newState != CastState.NO_DEVICES_AVAILABLE) {
showIntroductoryOverlay()
}
}
}
mCastContext = CastContext.getSharedInstance(this)
}
override fun onResume() {
super.onResume()
mCastContext?.addCastStateListener(mCastStateListener!!)
}
override fun onPause() {
super.onPause()
mCastContext?.removeCastStateListener(mCastStateListener!!)
}
Очистите данные приложения или удалите его со своего устройства. Затем нажмите кнопку Нажмите кнопку «Запустить», чтобы запустить приложение на мобильном устройстве, и вы должны увидеть вводное наложение (очистите данные приложения, если наложение не отображается).
10. Расширенный контроллер
Контрольный список проектирования Google Cast требует, чтобы приложение-отправитель предоставляло расширенный контроллер для транслируемого мультимедиа. Расширенный контроллер представляет собой полноэкранную версию мини-контроллера.
Cast SDK предоставляет виджет для расширенного контроллера под названием ExpandedControllerActivity
. Это абстрактный класс, который необходимо создать в качестве подкласса, чтобы добавить кнопку трансляции.
Во-первых, создайте новый файл ресурсов меню с именем expanded_controller.xml
, чтобы расширенный контроллер предоставил кнопку Cast:
<?xml version="1.0" encoding="utf-8"?>
<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>
Создайте новый пакет expandedcontrols
в пакете com.google.sample.cast.refplayer
. Затем создайте новый файл с именем ExpandedControlsActivity.kt
в пакете com.google.sample.cast.refplayer.expandedcontrols
.
package com.google.sample.cast.refplayer.expandedcontrols
import android.view.Menu
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
import com.google.sample.cast.refplayer.R
import com.google.android.gms.cast.framework.CastButtonFactory
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
}
}
Теперь объявите ExpandedControlsActivity
в AndroidManifest.xml
в теге application
над OPTIONS_PROVIDER_CLASS_NAME
:
<application>
...
<activity
android:name="com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.CastVideosDark"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.google.sample.cast.refplayer.VideoBrowserActivity"/>
</activity>
...
</application>
Отредактируйте CastOptionsProvider
и измените NotificationOptions
и CastMediaOptions
, чтобы установить целевое действие на ExpandedControlsActivity
:
import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity
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()
}
Обновите метод loadRemoteMedia
LocalPlayerActivity
, чтобы отображать ExpandedControlsActivity
при загрузке удаленного носителя:
import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
if (mCastSession == null) {
return
}
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(buildMediaInfo())
.setAutoplay(autoPlay)
.setCurrentTime(position.toLong()).build())
}
Нажмите кнопку Кнопка «Запустить», чтобы запустить приложение на мобильном устройстве и транслировать видео. Вы должны увидеть расширенный контроллер. Вернитесь к списку видео, и когда вы нажмете на мини-контроллер, расширенный контроллер загрузится снова. Выйдите из приложения, чтобы увидеть уведомление. Нажмите на изображение уведомления, чтобы загрузить расширенный контроллер.
11. Добавьте поддержку Cast Connect.
Библиотека Cast Connect позволяет существующим приложениям-отправителям взаимодействовать с приложениями Android TV через протокол Cast. Cast Connect построен на основе инфраструктуры Cast, а ваше приложение Android TV выступает в качестве приемника.
Зависимости
Примечание. Для реализации Cast Connect платформа play-services-cast-framework
должна быть 19.0.0
или выше.
Параметры запуска
Чтобы запустить приложение Android TV, также называемое Android-приемником, нам необходимо установить для флага setAndroidReceiverCompatible
значение true в объекте LaunchOptions
. Этот объект LaunchOptions
определяет, как запускается приемник, и передается в CastOptions
возвращаемый классом CastOptionsProvider
. Установка для вышеупомянутого флага значения false
запустит веб-приемник для определенного идентификатора приложения в консоли разработчика Cast.
В файле CastOptionsProvider.kt
добавьте в метод getCastOptions
следующее:
import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
.setAndroidReceiverCompatible(true)
.build()
return new CastOptions.Builder()
.setLaunchOptions(launchOptions)
...
.build()
Установить учетные данные для запуска
На стороне отправителя вы можете указать CredentialsData
, чтобы указать, кто присоединяется к сеансу. credentials
— это строка, которую можно определить пользователем, если ваше приложение ATV ее понимает. CredentialsData
передаются в ваше приложение Android TV только во время запуска или присоединения. Если вы установите его снова, когда вы подключены, он не будет передан в ваше приложение Android TV.
Чтобы установить учетные данные запуска, необходимо определить CredentialsData
и передать их объекту LaunchOptions
. Добавьте следующий код в метод getCastOptions
в файле CastOptionsProvider.kt
:
import com.google.android.gms.cast.CredentialsData
...
val credentialsData = CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build()
val launchOptions = LaunchOptions.Builder()
...
.setCredentialsData(credentialsData)
.build()
Установите учетные данные в LoadRequest
Если ваше приложение веб-приемника и приложение Android TV по-разному обрабатывают credentials
, вам может потребоваться определить отдельные credentials
для каждого из них. Чтобы позаботиться об этом, добавьте следующий код в файл LocalPlayerActivity.kt
в функцию loadRemoteMedia
:
remoteMediaClient.load(MediaLoadRequestData.Builder()
...
.setCredentials("user-credentials")
.setAtvCredentials("atv-user-credentials")
.build())
В зависимости от приложения-получателя, к которому осуществляет трансляцию отправитель, SDK теперь будет автоматически определять, какие учетные данные использовать для текущего сеанса.
Тестирование Cast Connect
Действия по установке APK-файла Android TV на Chromecast с Google TV
- Найдите IP-адрес вашего устройства Android TV. Обычно он доступен в разделе «Настройки» > «Сеть и Интернет» > (имя сети, к которой подключено ваше устройство) . Справа будут показаны подробности и IP-адрес вашего устройства в сети.
- Используйте IP-адрес вашего устройства для подключения к нему через ADB с помощью терминала:
$ adb connect <device_ip_address>:5555
- В окне терминала перейдите в папку верхнего уровня для образцов кодовой лаборатории, которые вы загрузили в начале этой кодовой лаборатории. Например:
$ cd Desktop/android_codelab_src
- Установите файл .apk из этой папки на свой Android TV, выполнив:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Теперь вы сможете увидеть приложение под названием Cast Videos в меню «Ваши приложения» на своем устройстве Android TV.
- Вернитесь в проект Android Studio и нажмите кнопку «Выполнить», чтобы установить и запустить приложение-отправитель на физическом мобильном устройстве. В правом верхнем углу щелкните значок трансляции и выберите свое устройство Android TV из доступных вариантов. Теперь вы должны увидеть приложение Android TV, запущенное на вашем устройстве Android TV, и воспроизведение видео должно позволить вам управлять воспроизведением видео с помощью пульта дистанционного управления Android TV.
12. Настройте виджеты Cast
Вы можете настроить виджеты Cast , задав цвета, стили кнопок, текста и миниатюр, а также выбрав типы отображаемых кнопок.
Обновите res/values/styles_castvideo.xml
<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
...
<item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
<item name="castIntroOverlayStyle">@style/CustomCastIntroOverlay</item>
<item name="castMiniControllerStyle">@style/CustomCastMiniController</item>
<item name="castExpandedControllerStyle">@style/CustomCastExpandedController</item>
<item name="castExpandedControllerToolbarStyle">
@style/ThemeOverlay.AppCompat.ActionBar
</item>
...
</style>
Объявите следующие пользовательские темы:
<!-- Customize Cast Button -->
<style name="CustomMediaRouterTheme" parent="Theme.MediaRouter">
<item name="mediaRouteButtonStyle">@style/CustomMediaRouteButtonStyle</item>
</style>
<style name="CustomMediaRouteButtonStyle" parent="Widget.MediaRouter.Light.MediaRouteButton">
<item name="mediaRouteButtonTint">#EEFF41</item>
</style>
<!-- Customize Introductory Overlay -->
<style name="CustomCastIntroOverlay" parent="CastIntroOverlay">
<item name="castButtonTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Button</item>
<item name="castTitleTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Title</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Button" parent="android:style/TextAppearance">
<item name="android:textColor">#FFFFFF</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Title" parent="android:style/TextAppearance.Large">
<item name="android:textColor">#FFFFFF</item>
</style>
<!-- Customize Mini Controller -->
<style name="CustomCastMiniController" parent="CastMiniController">
<item name="castShowImageThumbnail">true</item>
<item name="castTitleTextAppearance">@style/TextAppearance.AppCompat.Subhead</item>
<item name="castSubtitleTextAppearance">@style/TextAppearance.AppCompat.Caption</item>
<item name="castBackground">@color/accent</item>
<item name="castProgressBarColor">@color/orange</item>
</style>
<!-- Customize Expanded Controller -->
<style name="CustomCastExpandedController" parent="CastExpandedController">
<item name="castButtonColor">#FFFFFF</item>
<item name="castPlayButtonDrawable">@drawable/cast_ic_expanded_controller_play</item>
<item name="castPauseButtonDrawable">@drawable/cast_ic_expanded_controller_pause</item>
<item name="castStopButtonDrawable">@drawable/cast_ic_expanded_controller_stop</item>
</style>
13. Поздравления
Теперь вы знаете, как включить поддержку Cast в видеоприложении с помощью виджетов Cast SDK на Android.
Дополнительные сведения см. в руководстве разработчика Android Sender .
1. Обзор
Эта лаборатория научит вас, как изменить существующее видеоприложение Android для трансляции контента на устройство с поддержкой Google Cast .
Что такое Google Cast?
Google Cast позволяет пользователям транслировать контент с мобильного устройства на телевизор. Затем пользователи могут использовать свое мобильное устройство в качестве пульта дистанционного управления для воспроизведения мультимедиа на телевизоре.
Google Cast SDK позволяет расширить возможности вашего приложения для управления телевизором или аудиосистемой. Cast SDK позволяет добавлять необходимые компоненты пользовательского интерфейса на основе контрольного списка Google Cast Design .
Контрольный список Google Cast Design предназначен для того, чтобы сделать использование Cast простым и предсказуемым на всех поддерживаемых платформах.
Что мы собираемся строить?
После завершения этой лабораторной работы у вас будет видеоприложение для Android, которое сможет транслировать видео на устройство с поддержкой Google Cast.
Что вы узнаете
- Как добавить Google Cast SDK в пример приложения для видео.
- Как добавить кнопку Cast для выбора устройства Google Cast.
- Как подключиться к устройству Cast и запустить медиа-ресивер.
- Как скинуть видео.
- Как добавить мини-контроллер Cast в ваше приложение.
- Как поддерживать мультимедийные уведомления и элементы управления экраном блокировки.
- Как добавить расширенный контроллер.
- Как обеспечить вводное наложение.
- Как настроить виджеты Cast.
- Как интегрироваться с Cast Connect
Что вам понадобится
- Последняя версия Android SDK .
- Android-студия версии 3.2+
- Одно мобильное устройство с Android 4.1+ Jelly Bean (уровень API 16).
- USB-кабель для передачи данных для подключения мобильного устройства к компьютеру разработки.
- Устройство Google Cast, например Chromecast или Android TV, с доступом в Интернет.
- Телевизор или монитор с входом HDMI.
- Chromecast с Google TV требуется для проверки интеграции Cast Connect, но не является обязательным для остальной части Codelab. Если у вас его нет, можете пропустить шаг «Добавить поддержку Cast Connect» в конце этого руководства.
Опыт
- Вам потребуются предыдущие знания разработки на Kotlin и Android.
- Вам также потребуются предварительные знания о просмотре телевизора :)
Как вы будете использовать этот урок?
Как бы вы оценили свой опыт создания приложений для Android?
Как бы вы оценили свои впечатления от просмотра телевидения?
2. Получите пример кода
Вы можете загрузить весь пример кода на свой компьютер...
и распакуйте загруженный zip-файл.
3. Запустите пример приложения.
Сначала давайте посмотрим, как выглядит готовый пример приложения. Приложение представляет собой базовый видеоплеер. Пользователь может выбрать видео из списка, а затем воспроизвести его локально на устройстве или транслировать его на устройство Google Cast.
После загрузки кода следующие инструкции описывают, как открыть и запустить готовый пример приложения в Android Studio :
Выберите « Импорт проекта» на экране приветствия или пункты меню «Файл» > «Создать» > «Импортировать проект...» .
Выберите app-done
из папки примера кода и нажмите «ОК».
Нажмите Файл > Синхронизировать проект с файлами Gradle .
Включите отладку по USB на вашем устройстве Android — на Android 4.2 и выше экран параметров разработчика по умолчанию скрыт. Чтобы сделать его видимым, перейдите в «Настройки» > «О телефоне» и семь раз нажмите «Номер сборки» . Вернитесь к предыдущему экрану, перейдите в «Система» > «Дополнительно» и нажмите «Параметры разработчика» внизу, затем нажмите «Отладка по USB» , чтобы включить ее.
Подключите свое Android-устройство и нажмите кнопку Кнопка «Выполнить» в Android Studio. Через несколько секунд вы должны увидеть видеоприложение под названием Cast Videos .
Нажмите кнопку Cast в приложении для видео и выберите свое устройство Google Cast.
Выберите видео и нажмите кнопку воспроизведения.
Видео начнет воспроизводиться на вашем устройстве Google Cast.
Отобразится расширенный контроллер. Вы можете использовать кнопку воспроизведения/паузы для управления воспроизведением.
Вернитесь к списку видео.
Мини-контроллер теперь виден в нижней части экрана.
Нажмите кнопку паузы на мини-контроллере, чтобы приостановить видео на ресивере. Нажмите кнопку воспроизведения на мини-контроллере, чтобы продолжить воспроизведение видео еще раз.
Нажмите кнопку «Домой» на мобильном устройстве. Потяните вниз уведомления, и теперь вы должны увидеть уведомление о сеансе трансляции.
Заблокируйте свой телефон, и когда вы его разблокируете, вы увидите уведомление на экране блокировки, позволяющее управлять воспроизведением мультимедиа или остановить трансляцию.
Вернитесь в приложение для видео и нажмите кнопку Cast, чтобы остановить трансляцию на устройстве Google Cast.
Часто задаваемые вопросы
4. Подготовьте стартовый проект
Нам нужно добавить поддержку Google Capt в приложение Start, которое вы скачали. Вот некоторая терминология Google Cast, которую мы будем использовать в этом CodeLab:
- Приложение отправителя работает на мобильном устройстве или ноутбуке,
- Приложение приемника работает на устройстве Google Cast.
Теперь вы готовы построить на вершине стартового проекта с помощью Android Studio:
- Выберите Справочник
app-start
из вашего примера загрузки кода (выберите Project Import на экране приветствия или в файле> New> Import Project ... Menu Option). - Нажмите кнопку Sync Project с кнопкой Gradle Files .
- Нажмите кнопку Запустите кнопку, чтобы запустить приложение и исследовать пользовательский интерфейс.
Приложение дизайн
Приложение получает список видео с удаленного веб -сервера и предоставляет список для пользователя для просмотра. Пользователи могут выбрать видео, чтобы увидеть детали или воспроизводить видео на мобильном устройстве.
Приложение состоит из двух основных видов деятельности: VideoBrowserActivity
и LocalPlayerActivity
. Чтобы интегрировать функциональность Google Cast, действия должны наследовать либо от AppCompatActivity
, либо с его родителем FragmentActivity
. Это ограничение существует, так как нам нужно добавить MediaRouteButton
(предоставленную в библиотеке поддержки Mediarouter ) в качестве MediaRouteActionProvider
, и это будет работать только в том случае, если деятельность наследует от вышеупомянутых классов. Библиотека поддержки Mediarouter зависит от библиотеки поддержки AppCompat , которая предоставляет требуемые классы.
VideoBrowserActivity
Это действие содержит Fragment
( VideoBrowserFragment
). Этот список подкреплен ArrayAdapter
( VideoListAdapter
). Список видео и связанные с ними метаданные размещаются на удаленном сервере в качестве файла JSON . AsyncTaskLoader
( VideoItemLoader
) приносит этот JSON и обрабатывает его для составления списка объектов MediaItem
.
Объект MediaItem
моделирует видео и связанные с ним метаданные, такие как его название, описание, URL -адрес потока, URL для поддерживающих изображений и связанные текстовые треки (для закрытых подписей), если таковые имеются. Объект MediaItem
проходит между действиями, поэтому MediaItem
имеет методы утилиты для преобразования его в Bundle
и наоборот.
Когда загрузчик создает список MediaItems
, он передает этот список в VideoListAdapter
, который затем представляет список MediaItems
в VideoBrowserFragment
. Пользователю представлен список миниатюр видео с кратким описанием для каждого видео. Когда элемент выбран, соответствующий MediaItem
конвертируется в Bundle
и передается в LocalPlayerActivity
.
LocalPlayerActivity
Эта деятельность отображает метаданные о конкретном видео и позволяет пользователю воспроизводить видео локально на мобильном устройстве.
В мероприятии проводятся VideoView
, некоторые элементы управления носителями и текстовую область, чтобы показать описание выбранного видео. Игрок покрывает верхнюю часть экрана, оставляя место для подробного описания видео внизу. Пользователь может воспроизводить/сделать паузу или искать локальное воспроизведение видео.
Зависимости
Поскольку мы используем AppCompatActivity
, нам нужна библиотека поддержки AppCompat. Для управления списком видео и асинхронного получения изображений для списка мы используем библиотеку Volley .
Часто задаваемые вопросы
5. Добавление кнопки листа
Приложение с поддержкой литой отображает кнопку литой в каждой из своих действий. Нажатие на кнопку CAST отображает список отличных устройств, которые может выбрать пользователь. Если пользователь локально воспроизводил контент на устройстве отправителя, выбирая запуска листового устройства или возобновляет воспроизведение на этом отличном устройстве. В любое время во время актеров пользователь может нажать на кнопку CAST и прекратить отдавать ваше приложение на листовое устройство. Пользователь должен быть в состоянии подключаться к или отключать от литого устройства, находясь в любом случае вашего приложения, как описано в контрольном списке Design Design Google .
Зависимости
Обновите файл приложения build.gradle, чтобы включить необходимые библиотечные зависимости:
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'androidx.mediarouter:mediarouter:1.3.1'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.google.android.gms:play-services-cast-framework:21.1.0'
implementation 'com.android.volley:volley:1.2.1'
implementation "androidx.core:core-ktx:1.8.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
Синхронизируйте проект, чтобы подтвердить сборки проекта без ошибок.
Инициализация
В актерской структуре есть глобальный объект Singleton, CastContext
, который координирует все ликовые взаимодействия.
Вы должны реализовать интерфейс OptionsProvider
для подачи CastOptions
необходимых для инициализации CastContext
Singleton. Наиболее важным вариантом является идентификатор приложения приемника, который используется для фильтрации результатов обнаружения устройства листа и для запуска приложения приемника при запуске литого сеанса.
Когда вы разрабатываете собственное приложение с поддержкой, вы должны зарегистрироваться в качестве разработчика, а затем получить идентификатор приложения для вашего приложения. Для этого CodeLab мы будем использовать пример идентификатора приложения.
Добавьте следующий новый файл CastOptionsProvider.kt
в пакет com.google.sample.cast.refplayer
проекта:
package com.google.sample.cast.refplayer
import android.content.Context
import com.google.android.gms.cast.framework.OptionsProvider
import com.google.android.gms.cast.framework.CastOptions
import com.google.android.gms.cast.framework.SessionProvider
class CastOptionsProvider : OptionsProvider {
override fun getCastOptions(context: Context): CastOptions {
return CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.build()
}
override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
return null
}
}
Теперь объявите OptionsProvider
в теге « application
» файла AndroidManifest.xml
:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />
Лениво инициализируйте CastContext
в методе VideoBrowserActivity
Oncreate:
import com.google.android.gms.cast.framework.CastContext
private var mCastContext: CastContext? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.video_browser)
setupActionBar()
mCastContext = CastContext.getSharedInstance(this)
}
Добавьте ту же логику инициализации в LocalPlayerActivity
.
Кнопка листа
Теперь, когда CastContext
инициализируется, нам нужно добавить кнопку CAST, чтобы пользователь выбирал отличное устройство. Кнопка актеров реализована MediaRouteButton
из библиотеки поддержки Mediarouter . Как и любой значок действия, который вы можете добавить в свою деятельность (с помощью ActionBar
или панели Toolbar
), вам сначала необходимо добавить соответствующий пункт меню в свое меню.
Измените файл res/menu/browse.xml
и добавьте элемент MediaRouteActionProvider
в меню перед элементом настроек:
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
CastButtonFactory
MediaRouteButton
VideoBrowserActivity
onCreateOptionsMenu()
import com.google.android.gms.cast.framework.CastButtonFactory
private var mediaRouteMenuItem: MenuItem? = null
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.browse, menu)
mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu,
R.id.media_route_menu_item)
return true
}
Переопределить onCreateOptionsMenu
в LocalPlayerActivity
аналогично.
Нажмите кнопку Запустите кнопку, чтобы запустить приложение на вашем мобильном устройстве. Вы должны увидеть кнопку отлив в панели действий приложения, и когда вы нажимаете на нее, в ней будут перечислены устройства актеров в вашей локальной сети. Обнаружение устройства управляется автоматически CastContext
. Выберите ваше отличное устройство, и приложение для приемника примеров будет загружено на отличное устройство. Вы можете перемещаться между активностью просмотра и активностью локального игрока, а состояние кнопки листа синхронизируется.
Мы не подключили какую -либо поддержку воспроизведения медиа, поэтому вы не можете воспроизводить видео на устройстве актеров. Нажмите на кнопку CAST, чтобы отключить.
6. Casting Video Content
Мы расширим приложение примеров, чтобы также удаленно воспроизводить видео на листовом устройстве. Для этого нам нужно выслушать различные события, генерируемые актером.
Кастинг СМИ
На высоком уровне, если вы хотите сыграть носитель на листовом устройстве, вам нужно делать эти вещи:
- Создайте объект
MediaInfo
, который моделирует медиа -элемент. - Подключитесь к литому устройству и запустите приложение приемника.
- Загрузите объект
MediaInfo
в свой приемник и воспроизводите контент. - Отслеживать статус медиа.
- Отправить команды воспроизведения в приемник на основе взаимодействия с пользователем.
Мы уже сделали шаг 2 в предыдущем разделе. Шаг 3 легко сделать с актерскими рамками. Шаг 1 составляет отображение одного объекта с другим; MediaInfo
- это то, что понимает фреймворк, а MediaItem
- это инкапсуляция нашего приложения для медиа -элемента; Мы можем легко составить на карту MediaItem
в MediaInfo
.
Образец приложения LocalPlayerActivity
уже различает локальный против удаленного воспроизведения, используя это перечисление:
private var mLocation: PlaybackLocation? = null
enum class PlaybackLocation {
LOCAL, REMOTE
}
enum class PlaybackState {
PLAYING, PAUSED, BUFFERING, IDLE
}
В этом CodeLab не важно понять, как именно работает все выборки игроков. Важно понимать, что медиаплеера вашего приложения будет изменен, чтобы знать о двух местах воспроизведения аналогичным образом.
На данный момент местный игрок всегда находится в местном состоянии воспроизведения, поскольку он еще ничего не знает о кастинговых состояниях. Нам нужно обновить пользовательский интерфейс на основе переходов состояния, которые происходят в актерской структуре. Например, если мы начнем кастинг, нам нужно остановить локальное воспроизведение и отключить некоторые элементы управления. Точно так же, если мы перестаем кастироваться, когда мы находимся в этой деятельности, нам нужно перейти к локальному воспроизведению. Чтобы справиться с этим, нам нужно выслушать различные события, созданные актером.
Управление сессиями
Для литой фреймворта сеанс актеров объединяет шаги подключения к устройству, запуска (или соединения), подключению к приложению приемника и инициализации канала управления носителем, если это необходимо. Канал управления медиа -управлением - это то, как Cast Framework отправляет и получает сообщения от Media Player Receiver.
Сессия актеров будет запущено автоматически, когда пользователь выбирает устройство из кнопки CAST и будет автоматически остановлен, когда пользователь отключается. Восстановление с сеансом приемника из -за проблем с сетью также автоматически обрабатывается Cast SDK.
Давайте добавим SessionManagerListener
в LocalPlayerActivity
:
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
...
private var mSessionManagerListener: SessionManagerListener<CastSession>? = null
private var mCastSession: CastSession? = null
...
private fun setupCastListener() {
mSessionManagerListener = object : SessionManagerListener<CastSession> {
override fun onSessionEnded(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionResumed(session: CastSession, wasSuspended: Boolean) {
onApplicationConnected(session)
}
override fun onSessionResumeFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionStarted(session: CastSession, sessionId: String) {
onApplicationConnected(session)
}
override fun onSessionStartFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionStarting(session: CastSession) {}
override fun onSessionEnding(session: CastSession) {}
override fun onSessionResuming(session: CastSession, sessionId: String) {}
override fun onSessionSuspended(session: CastSession, reason: Int) {}
private fun onApplicationConnected(castSession: CastSession) {
mCastSession = castSession
if (null != mSelectedMedia) {
if (mPlaybackState == PlaybackState.PLAYING) {
mVideoView!!.pause()
loadRemoteMedia(mSeekbar!!.progress, true)
return
} else {
mPlaybackState = PlaybackState.IDLE
updatePlaybackLocation(PlaybackLocation.REMOTE)
}
}
updatePlayButton(mPlaybackState)
invalidateOptionsMenu()
}
private fun onApplicationDisconnected() {
updatePlaybackLocation(PlaybackLocation.LOCAL)
mPlaybackState = PlaybackState.IDLE
mLocation = PlaybackLocation.LOCAL
updatePlayButton(mPlaybackState)
invalidateOptionsMenu()
}
}
}
В активности LocalPlayerActivity
мы заинтересованы в том, чтобы быть информированным, когда мы подключаемся или отключены от литого устройства, чтобы мы могли переключаться на локального игрока или от локального игрока. Обратите внимание, что подключение может быть нарушено не только экземпляром вашего приложения, работающего на вашем мобильном устройстве, но также может быть нарушено другим экземпляром вашего (или другого) приложения, работающего на другом мобильном устройстве.
В настоящее время активная сессия доступна как SessionManager.getCurrentSession()
. Сеансы создаются и разорваны автоматически в ответ на взаимодействие с пользователями с диалогами CAST.
Нам нужно зарегистрировать наш прослушиватель сеанса и инициализировать некоторые переменные, которые мы будем использовать в деятельности. Измените метод LocalPlayerActivity
onCreate
на:
import com.google.android.gms.cast.framework.CastContext
...
private var mCastContext: CastContext? = null
...
override fun onCreate(savedInstanceState: Bundle?) {
...
mCastContext = CastContext.getSharedInstance(this)
mCastSession = mCastContext!!.sessionManager.currentCastSession
setupCastListener()
...
loadViews()
...
val bundle = intent.extras
if (bundle != null) {
....
if (shouldStartPlayback) {
....
} else {
if (mCastSession != null && mCastSession!!.isConnected()) {
updatePlaybackLocation(PlaybackLocation.REMOTE)
} else {
updatePlaybackLocation(PlaybackLocation.LOCAL)
}
mPlaybackState = PlaybackState.IDLE
updatePlayButton(mPlaybackState)
}
}
...
}
Загрузка носителя
В актерском составе SDK RemoteMediaClient
предоставляет набор удобных API для управления удаленным воспроизведением медиа на приемнике. Для CastSession
, которая поддерживает воспроизведение медиа, экземпляр RemoteMediaClient
будет создан автоматически SDK. Доступ к нему можно получить, вызывая метод getRemoteMediaClient()
в экземпляре CastSession
. Добавьте следующие методы в LocalPlayerActivity
, чтобы загрузить в настоящее время выбранное видео на приемник:
import com.google.android.gms.cast.framework.media.RemoteMediaClient
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaLoadOptions
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.common.images.WebImage
import com.google.android.gms.cast.MediaLoadRequestData
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
if (mCastSession == null) {
return
}
val remoteMediaClient = mCastSession!!.remoteMediaClient ?: return
remoteMediaClient.load( MediaLoadRequestData.Builder()
.setMediaInfo(buildMediaInfo())
.setAutoplay(autoPlay)
.setCurrentTime(position.toLong()).build())
}
private fun buildMediaInfo(): MediaInfo? {
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
mSelectedMedia?.studio?.let { movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, it) }
mSelectedMedia?.title?.let { movieMetadata.putString(MediaMetadata.KEY_TITLE, it) }
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(0))))
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(1))))
return mSelectedMedia!!.url?.let {
MediaInfo.Builder(it)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType("videos/mp4")
.setMetadata(movieMetadata)
.setStreamDuration((mSelectedMedia!!.duration * 1000).toLong())
.build()
}
}
Теперь обновляйте различные существующие методы для использования логики актеров для поддержки удаленного воспроизведения:
private fun play(position: Int) {
startControllersTimer()
when (mLocation) {
PlaybackLocation.LOCAL -> {
mVideoView!!.seekTo(position)
mVideoView!!.start()
}
PlaybackLocation.REMOTE -> {
mPlaybackState = PlaybackState.BUFFERING
updatePlayButton(mPlaybackState)
//seek to a new position within the current media item's new position
//which is in milliseconds from the beginning of the stream
mCastSession!!.remoteMediaClient?.seek(position.toLong())
}
else -> {}
}
restartTrickplayTimer()
}
private fun togglePlayback() {
...
PlaybackState.IDLE -> when (mLocation) {
...
PlaybackLocation.REMOTE -> {
if (mCastSession != null && mCastSession!!.isConnected) {
loadRemoteMedia(mSeekbar!!.progress, true)
}
}
else -> {}
}
...
}
override fun onPause() {
...
mCastContext!!.sessionManager.removeSessionManagerListener(
mSessionManagerListener!!, CastSession::class.java)
}
override fun onResume() {
Log.d(TAG, "onResume() was called")
mCastContext!!.sessionManager.addSessionManagerListener(
mSessionManagerListener!!, CastSession::class.java)
if (mCastSession != null && mCastSession!!.isConnected) {
updatePlaybackLocation(PlaybackLocation.REMOTE)
} else {
updatePlaybackLocation(PlaybackLocation.LOCAL)
}
super.onResume()
}
Для метода updatePlayButton
измените значение isConnected
Varia:
private fun updatePlayButton(state: PlaybackState?) {
...
val isConnected = (mCastSession != null
&& (mCastSession!!.isConnected || mCastSession!!.isConnecting))
...
}
Теперь нажмите Запустите кнопку, чтобы запустить приложение на вашем мобильном устройстве. Подключитесь к своему устройству актеров и начните воспроизводить видео. Вы должны увидеть видео, воспроизводя на приемнике.
7. мини -контроллер
Контрольный список дизайна актеров требует, чтобы все приложения CAST предоставили мини -контроллер , который появляется, когда пользователь отступает от текущей страницы контента. Mini Controller обеспечивает мгновенный доступ и видимое напоминание для текущего сессии.
Cast SDK предоставляет пользовательский вид MiniControllerFragment
, который может быть добавлен в файл макета приложения действий, в которых вы хотите показать мини -контроллер.
Добавьте следующее определение фрагмента в нижнюю часть обоих res/layout/player_activity.xml
и res/layout/video_browser.xml
:
<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"/>
Нажмите кнопку Запустите кнопку, чтобы запустить приложение и разыграть видео. Когда воспроизведение начинается на приемнике, вы должны увидеть, как мини -контроллер появляется в нижней части каждого действия. Вы можете управлять удаленным воспроизведением, используя мини -контроллер. Если вы перемещаетесь между активностью просмотра и активностью локального игрока, состояние Mini Controller должно оставаться в синхронизации со статусом воспроизведения воспроизведения приемника.
8. Экран уведомления и блокировки
Контрольный список Design Design Google требует приложения для отправителя для реализации элементов управления мультимедиа из уведомления и экрана блокировки .
Cast SDK обеспечивает MediaNotificationService
, чтобы помочь приложению приложения для отправителя построить средства управления носителями для уведомления и блокировки экрана. Сервис автоматически объединяется в манифест вашего приложения Gradle.
MediaNotificationService
будет работать на заднем плане, когда отправитель будет кастингом, и покажет уведомление с миниатюрной нормой изображения и метаданными о текущем элементе листа, кнопке воспроизведения/паузы и кнопкой остановки.
Уведомления и управления экраном уведомления и блокировки могут быть включены с помощью CastOptions
при инициализации CastContext
. Управление среды для экрана уведомления и блокировки включается по умолчанию. Функция экрана блокировки включается до тех пор, пока уведомление включено.
Отредактируйте CastOptionsProvider
и измените реализацию getCastOptions
чтобы соответствовать этому коду:
import com.google.android.gms.cast.framework.media.CastMediaOptions
import com.google.android.gms.cast.framework.media.NotificationOptions
override fun getCastOptions(context: Context): CastOptions {
val notificationOptions = NotificationOptions.Builder()
.setTargetActivityClassName(VideoBrowserActivity::class.java.name)
.build()
val mediaOptions = CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.build()
return CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.setCastMediaOptions(mediaOptions)
.build()
}
Нажмите кнопку Запустите кнопку, чтобы запустить приложение на вашем мобильном устройстве. Отмените видео и выходите из приложения. Должно быть уведомление для видео, которое в настоящее время играет на приемнике. Заблокируйте мобильное устройство, и теперь экран блокировки должен отображать элементы управления для воспроизведения носителя на личном устройстве.
9. Вводное наложение
Контрольный список Design Design Google требует, чтобы приложение отправителя представила кнопку CAST существующим пользователям, чтобы они знали, что приложение Sender теперь поддерживает кастинг, а также помогает пользователям новым в Google Cast.
CAST SDK предоставляет пользовательское представление, IntroductoryOverlay
, которое можно использовать для выделения кнопки листа, когда она впервые показана пользователям. Добавьте следующий код в VideoBrowserActivity
:
import com.google.android.gms.cast.framework.IntroductoryOverlay
import android.os.Looper
private var mIntroductoryOverlay: IntroductoryOverlay? = null
private fun showIntroductoryOverlay() {
mIntroductoryOverlay?.remove()
if (mediaRouteMenuItem?.isVisible == true) {
Looper.myLooper().run {
mIntroductoryOverlay = com.google.android.gms.cast.framework.IntroductoryOverlay.Builder(
this@VideoBrowserActivity, mediaRouteMenuItem!!)
.setTitleText("Introducing Cast")
.setSingleTime()
.setOnOverlayDismissedListener(
object : IntroductoryOverlay.OnOverlayDismissedListener {
override fun onOverlayDismissed() {
mIntroductoryOverlay = null
}
})
.build()
mIntroductoryOverlay!!.show()
}
}
}
Теперь добавьте CastStateListener
и вызовите метод showIntroductoryOverlay
, когда отличное устройство доступно путем изменения метода onCreate
и переопределить методы onResume
и onPause
чтобы соответствовать следующему:
import com.google.android.gms.cast.framework.CastState
import com.google.android.gms.cast.framework.CastStateListener
private var mCastStateListener: CastStateListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.video_browser)
setupActionBar()
mCastStateListener = object : CastStateListener {
override fun onCastStateChanged(newState: Int) {
if (newState != CastState.NO_DEVICES_AVAILABLE) {
showIntroductoryOverlay()
}
}
}
mCastContext = CastContext.getSharedInstance(this)
}
override fun onResume() {
super.onResume()
mCastContext?.addCastStateListener(mCastStateListener!!)
}
override fun onPause() {
super.onPause()
mCastContext?.removeCastStateListener(mCastStateListener!!)
}
Очистите данные приложения или удалите приложение с вашего устройства. Затем нажмите Кнопка запустить , чтобы запустить приложение на вашем мобильном устройстве, и вы должны увидеть вводное наложение (очистить данные приложения, если наложение не отображается).
10. Расширенный контроллер
Контрольный список Design Design Google требует приложения для отправителя для предоставления расширенного контроллера для составления медиа. Расширенный контроллер - это полная версия мини -контроллера.
Cast SDK обеспечивает виджет для расширенного контроллера, называемого ExpandedControllerActivity
. Это абстрактный класс, который вы должны подключиться к добавлению кнопки листа.
Во -первых, создайте новый файл ресурса меню с именем expanded_controller.xml
для расширенного контроллера, чтобы предоставить кнопку литой:
<?xml version="1.0" encoding="utf-8"?>
<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>
Создайте новый пакет expandedcontrols
в пакете com.google.sample.cast.refplayer
. Далее создайте новый файл с именем ExpandedControlsActivity.kt
в пакете com.google.sample.cast.refplayer.expandedcontrols
.
package com.google.sample.cast.refplayer.expandedcontrols
import android.view.Menu
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
import com.google.sample.cast.refplayer.R
import com.google.android.gms.cast.framework.CastButtonFactory
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
}
}
Теперь объявите ExpandedControlsActivity
в AndroidManifest.xml
в теге application
выше OPTIONS_PROVIDER_CLASS_NAME
:
<application>
...
<activity
android:name="com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.CastVideosDark"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.google.sample.cast.refplayer.VideoBrowserActivity"/>
</activity>
...
</application>
Редактировать CastOptionsProvider
и изменения NotificationOptions
и CastMediaOptions
чтобы установить целевую деятельность на ExpandedControlsActivity
:
import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity
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()
}
Обновите метод LocalPlayerActivity
loadRemoteMedia
, чтобы отобразить ExpandedControlsActivity
при загрузке удаленного носителя:
import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
if (mCastSession == null) {
return
}
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(buildMediaInfo())
.setAutoplay(autoPlay)
.setCurrentTime(position.toLong()).build())
}
Нажмите кнопку Запустите кнопку, чтобы запустить приложение на вашем мобильном устройстве и разыграйте видео. Вы должны увидеть расширенный контроллер. Перейдите обратно в список видео, и когда вы нажимаете на мини -контроллер, расширенный контроллер будет загружен снова. Отходите от приложения, чтобы увидеть уведомление. Нажмите на изображение уведомления, чтобы загрузить расширенный контроллер.
11. Добавить поддержку CAST Connect
Библиотека Cast Connect позволяет существующим приложениям отправителя взаимодействовать с приложениями Android TV через протокол актеров. Cast Connect Builds в верхней части актеров инфраструктуры, а ваше приложение для Android TV действует в качестве приемника.
Зависимости
Примечание. Для реализации CAST Connect, play-services-cast-framework
должны быть 19.0.0
или выше.
Запуски
Чтобы запустить приложение Android TV, также называемое приемником Android, нам необходимо установить флаг setAndroidReceiverCompatible
на True в объекте LaunchOptions
. Этот объект LaunchOptions
диктует, как запускается приемник, и передается в CastOptions
возвращенные классом CastOptionsProvider
. Установка вышеупомянутого флага на false
, запустит веб -приемник для определенного идентификатора приложения в консоли Cast Developer.
В файле CastOptionsProvider.kt
добавьте следующее в метод getCastOptions
:
import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
.setAndroidReceiverCompatible(true)
.build()
return new CastOptions.Builder()
.setLaunchOptions(launchOptions)
...
.build()
Установите учетные данные запуска
На стороне отправителя вы можете указать CredentialsData
, чтобы представить, кто присоединяется к сеансу. credentials
-это строка, которая может быть определена пользователем, если ваше приложение ATV может понять это. CredentialsData
передается только в ваше приложение Android TV во время запуска или времени присоединения. Если вы установите его снова во время подключения, оно не будет передано в ваше приложение Android TV.
Чтобы установить запуск учетных данных, CredentialsData
должны быть определены и переданы в объект LaunchOptions
. Добавьте следующий код для метода getCastOptions
в вашем файле CastOptionsProvider.kt
:
import com.google.android.gms.cast.CredentialsData
...
val credentialsData = CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build()
val launchOptions = LaunchOptions.Builder()
...
.setCredentialsData(credentialsData)
.build()
Установить учетные данные на LoadRequest
В случае, если ваше приложение для веб -приемника и ваше приложение для Android TV и по -разному обрабатывают credentials
, вам может потребоваться определить отдельные credentials
для каждого. Чтобы позаботиться об этом, добавьте следующий код в свой файл LocalPlayerActivity.kt
в рамках функции loadRemoteMedia
:
remoteMediaClient.load(MediaLoadRequestData.Builder()
...
.setCredentials("user-credentials")
.setAtvCredentials("atv-user-credentials")
.build())
В зависимости от приложения приемника, к которому находится ваш отправитель, SDK теперь автоматически обрабатывает, какие учетные данные использовать для текущего сеанса.
Тестирование подключения к лицу
Шаги по установке Android TV APK на Chromecast с Google TV
- Найдите IP -адрес вашего устройства Android TV. Обычно он доступен в настройках> «Сеть и Интернет»> (имя сети подключено к вашему устройству) . Справа он покажет детали и IP -адрес вашего устройства в сети.
- Используйте IP -адрес для вашего устройства, чтобы подключиться к нему через ADB с помощью терминала:
$ adb connect <device_ip_address>:5555
- В окне вашего терминала перейдите в папку верхнего уровня для образцов CodeLab, которые вы загрузили в начале этого CodeLab. Например:
$ cd Desktop/android_codelab_src
- Установите файл .apk в эту папку в свой Android TV, работая:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Теперь вы должны увидеть приложение по имени видео в меню ваших приложений на вашем устройстве Android TV.
- Вернитесь в свой проект Android Studio и нажмите кнопку «Запустить», чтобы установить и запустить приложение Sender на вашем физическом мобильном устройстве. В верхнем правом углу нажмите значок актера и выберите устройство Android TV из доступных параметров. Теперь вам следует увидеть приложение Android TV, запущенное на вашем устройстве Android TV, и воспроизведение видео должно позволить вам управлять воспроизведением видео с помощью вашего Android TV Remote.
12. Настройка виджетов актеров
Вы можете настраивать виджеты актеров , установив цвета, стилизированные кнопки, текст и миниатюрный вид, и выбирая типы кнопок для отображения.
Обновление res/values/styles_castvideo.xml
<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
...
<item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
<item name="castIntroOverlayStyle">@style/CustomCastIntroOverlay</item>
<item name="castMiniControllerStyle">@style/CustomCastMiniController</item>
<item name="castExpandedControllerStyle">@style/CustomCastExpandedController</item>
<item name="castExpandedControllerToolbarStyle">
@style/ThemeOverlay.AppCompat.ActionBar
</item>
...
</style>
Объявить следующие пользовательские темы:
<!-- Customize Cast Button -->
<style name="CustomMediaRouterTheme" parent="Theme.MediaRouter">
<item name="mediaRouteButtonStyle">@style/CustomMediaRouteButtonStyle</item>
</style>
<style name="CustomMediaRouteButtonStyle" parent="Widget.MediaRouter.Light.MediaRouteButton">
<item name="mediaRouteButtonTint">#EEFF41</item>
</style>
<!-- Customize Introductory Overlay -->
<style name="CustomCastIntroOverlay" parent="CastIntroOverlay">
<item name="castButtonTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Button</item>
<item name="castTitleTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Title</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Button" parent="android:style/TextAppearance">
<item name="android:textColor">#FFFFFF</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Title" parent="android:style/TextAppearance.Large">
<item name="android:textColor">#FFFFFF</item>
</style>
<!-- Customize Mini Controller -->
<style name="CustomCastMiniController" parent="CastMiniController">
<item name="castShowImageThumbnail">true</item>
<item name="castTitleTextAppearance">@style/TextAppearance.AppCompat.Subhead</item>
<item name="castSubtitleTextAppearance">@style/TextAppearance.AppCompat.Caption</item>
<item name="castBackground">@color/accent</item>
<item name="castProgressBarColor">@color/orange</item>
</style>
<!-- Customize Expanded Controller -->
<style name="CustomCastExpandedController" parent="CastExpandedController">
<item name="castButtonColor">#FFFFFF</item>
<item name="castPlayButtonDrawable">@drawable/cast_ic_expanded_controller_play</item>
<item name="castPauseButtonDrawable">@drawable/cast_ic_expanded_controller_pause</item>
<item name="castStopButtonDrawable">@drawable/cast_ic_expanded_controller_stop</item>
</style>
13. Поздравляю
Теперь вы знаете, как разыграть видео приложение, используя виджеты CAST SDK на Android.
Для получения более подробной информации см. Руководство по разработчику Android Sender .