Google Cast — это технология, которая позволяет пользователям отправлять онлайн-контент на устройства, такие как Chromecast или Android TV, подключенные к телевизору. Как только контент будет доступен на телевидении, пользователи смогут управлять им со своего мобильного устройства или компьютера.
В этом руководстве вы узнаете, как создать базовое приложение с поддержкой Cast для Android с использованием Cast SDK v3, анонсированного во время конференции Google I / O 2016 года.
Настройка Cast Console
В состав Google Cast входят два компонента: получатель, который, по сути, представляет собой веб-страницу, отображаемую на устройстве кастинга с вашим контентом, и отправитель, который является клиентской программой, которая запрашивает мультимедиа и управляет воспроизведением.
Прежде чем вы сможете создать приложение отправителя, вам необходимо зарегистрировать учетную запись в консоли разработчика Google Cast , а затем создать и настроить новое приложение получателя. Чтобы зарегистрировать аккаунт, вам нужно будет заплатить единовременный сбор в размере 5 долларов США. После создания учетной записи вы можете нажать на красную кнопку «Добавить новое приложение», чтобы создать новое приложение получателя.
Далее у вас будет три варианта: Пользовательский приемник, Стилизованный медиаресивер и Удаленный дисплейный приемник. Для простоты в этом руководстве вы будете использовать Styled Media Receiver.
На следующем экране вы сможете выбрать некоторые основные настройки для вашего приемника, такие как имя приложения, необязательный URL-адрес для таблицы стилей CSS, чтобы настроить внешний вид приемника , а также возможность включить гостевой режим и аудио. только кастинг.
После того, как вы нажмете синюю кнопку Сохранить , вы увидите экран, который покажет вам основные детали вашего нового приложения приемника. Вы заметите, что этот экран также содержит ваш новый идентификатор приложения . Вам нужно будет использовать это значение в вашем приложении Android.
Стоит отметить, что, несмотря на то, что приложение-получатель создано, обнаружение приложения-отправителя может занять несколько часов.
Чтобы протестировать, вам нужно внести в белый список хотя бы одно устройство для литья. Это можно сделать из консоли разработчика Google Cast, нажав красную кнопку ДОБАВИТЬ НОВОЕ УСТРОЙСТВО . На появившемся экране вы можете ввести серийный номер вашего устройства и описание, чтобы внести его в белый список для тестирования с приложением вашего приемника.
На этом этапе у вас должен быть создан приемник и тестовое устройство, занесенное в белый список, так что все готово для создания приложения отправителя Android. Создав и опубликовав свое приложение в Play Store, вы захотите вернуться в Cast Developer Console, чтобы опубликовать свой получатель, позволяя использовать любое устройство приведения с вашим приложением-отправителем.
Настройка Android
Первое, что вам нужно сделать в своем приложении для Android, — это включить библиотеки Cast Framework и Media Router под узлом dependencies
в файле build.gradle .
1
2
|
compile ‘com.android.support:mediarouter-v7:24.1.1’
compile ‘com.google.android.gms:play-services-cast-framework:9.4.0’
|
Затем вы захотите сохранить идентификатор приложения, который вы получили при создании получателя, в файле strings.xml .
1
|
<string name=»cast_app_id»>(your ID goes here)</string>
|
Последний шаг в процессе установки включает в себя интернет-разрешение для вашего приложения. Откройте AndroidManifest.xml и добавьте следующую строку перед узлом application
.
1
|
<uses-permission android:name=»android.permission.INTERNET» />
|
Теперь, когда настройка завершена, вы можете перейти к включению кнопки медиа-маршрута в ваше приложение.
Отображение кнопки маршрутизации и подключение к устройствам Cast
Кнопка маршрутизации — это значок на панели инструментов приложения, который обычно означает, что приложение поддерживает приведение для пользователя.
Чтобы эта кнопка появилась на Toolbar
вашего приложения, проще всего включить ее в XML-файл меню для вашего Activity
(также рекомендуется, чтобы это было включено в каждое действие в вашем приложении).
1
2
3
4
5
6
7
8
9
|
<?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=»Cast»
app:actionProviderClass=»android.support.v7.app.MediaRouteActionProvider»
app:showAsAction=»always» />
</menu>
|
Затем вам нужно будет инициализировать этот новый MenuItem
в методе onCreateOptionsMenu
вашей Activity
.
1
2
3
4
5
6
7
8
9
|
@Override public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_main, menu);
mMediaRouterButton = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
menu,
R.id.media_route_menu_item);
return true;
}
|
После инициализации кнопки медиа-маршрута вы захотите добавить слушатели состояния в ваше приложение для приведения.
Доступные слушатели
В то время как доступно несколько прослушивателей, есть три, которые стоит обсудить, когда вы начнете использовать каркас Google Cast.
-
CastStateListener
: этот слушатель контролирует текущее состояние приведения приложения. Это срабатывает, когда приложение переключилось наCONNECTING
,NOT_CONNECTED
,NO_DEVICES_AVAILABLE
илиNO_DEVICES_AVAILABLE
. -
AppVisibilityListener
: у этого слушателя есть два метода:onAppEnteredForeground
иonAppEnteredBackground
. Эти методы вызываются, когда ваше приложение было фоновым для вашего пользователя, или когда пользователь снова открыл ваше приложение, соответственно. -
SessionManagerListener
: последний слушатель, которого мы пройдем, также самый многословный.Session
— это жизненный цикл взаимодействия пользователя с устройством преобразования, начинающийся, когда пользователь подключился к устройству, поддерживаемый посредством преобразования и заканчивающийся, когда пользователь отключен. Платформа Google Cast Android взаимодействует сSession
через объектSessionManager
.
Эти три слушателя могут быть связаны с платформой Google Cast следующим образом, где в данном примере это Activity
, в которой реализован каждый из вышеуказанных интерфейсов.
1
2
3
|
CastContext.getSharedInstance(this).addCastStateListener(this);
CastContext.getSharedInstance(this).addAppVisibilityListener(this);
CastContext.getSharedInstance(this).getSessionManager().addSessionManagerListener(this);
|
Возможно, вы также заметили, что вы SessionManager
доступ к SessionManager
и платформе Cast, используя CastContext.getSharedInstance(Context)
. Это потому, что CastContext
, основная точка взаимодействия между вашим приложением и платформой Cast, лениво инициализируется для повышения производительности приложения.
Когда ваша Activity
больше не активна, вам нужно помнить, чтобы удалить этих слушателей.
1
2
3
|
CastContext.getSharedInstance(this).removeAppVisibilityListener(this);
CastContext.getSharedInstance(this).removeCastStateListener(this);
CastContext.getSharedInstance(this).getSessionManager().removeSessionManagerListener(this);
|
Создание OptionsProvider
Чтобы сделать что-либо с платформой Cast, вам нужно создать новый класс, который расширяет OptionsProvider
. В этом классе вы сможете настроить различные параметры для своего приложения отправителя.
Мы пока оставим это простым и просто CastOptions
объект CastOptions
из метода getCastOptions
, который позволит возобновить сохраненные сеансы и повторно подключиться к сеансам, которые уже выполняются (хотя оба они уже включены по умолчанию, они представлены здесь как Примеры).
Объект CastOptions
также является тем, где идентификатор приложения получателя связан с вашим отправителем. Хотя метод getAdditionalSessionProviders
должен быть объявлен в этом классе, мы можем смело игнорировать его для наших целей.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
public class CastOptionsProvider implements OptionsProvider {
@Override
public CastOptions getCastOptions(Context context) {
CastOptions castOptions = new CastOptions.Builder()
.setResumeSavedSession(true)
.setEnableReconnectionService(true)
.setReceiverApplicationId(context.getString(R.string.cast_app_id))
.build();
return castOptions;
}
@Override
public List<SessionProvider> getAdditionalSessionProviders(Context context) {
return null;
}
}
|
Вам также нужно будет включить этот класс в файл AndroidManifest.xml в тег meta-data
под узлом application
.
1
2
3
|
<meta-data
android:name=»com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME»
android:value=»com.tutsplus.googlecastv3.CastOptionsProvider» />
|
На этом этапе ваше приложение должно быть в состоянии найти любые литейные устройства из белого списка и подключиться к ним через ваше приложение.
Стиль Диалога Маршрутизации
В зависимости от темы, которую вы используете в своем приложении (например, Theme.AppCompat.Light.NoActionBar
), вы могли заметить некоторые странные поведения с цветами в диалоговом окне устройства приведения, такие как белый шрифт и значки на белом фоне.
Вы также можете решить, что хотите настроить внешний вид диалога в соответствии с вашим приложением. Вы можете сделать это, переопределив два стиля, используемых для диалога Cast: Theme.MediaRouter.Light.DarkControlPanel
и Theme.MediaRouter.LightControlPanel
. Например, если вы используете белый шрифт на белом фоне, вы можете включить следующий код в свой файл styles.xml, чтобы изменить значки и цвет шрифта на черный на белом фоне.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<style name=»Theme.MediaRouter.Light.DarkControlPanel»>
<item name=»mediaRoutePlayDrawable»>@drawable/mr_ic_play_light</item>
<item name=»mediaRoutePauseDrawable»>@drawable/mr_ic_pause_light</item>
<item name=»mediaRouteCastDrawable»>@drawable/mr_ic_cast_dark</item>
<item name=»mediaRouteAudioTrackDrawable»>@drawable/ic_audiotrack_light</item>
<item name=»mediaRouteControllerPrimaryTextStyle»>@style/MediaRouteControllerTextColor</item>
<item name=»mediaRouteControllerSecondaryTextStyle»>@style/MediaRouteControllerTextColor</item>
</style>
<style name=»MediaRouteControllerTextColor»>
<item name=»android:textColor»>#000000</item>
<item name=»android:textSize»>14sp</item>
</style>
|
Содержание кастинга
После подключения к устройству кастинга вы, вероятно, захотите разрешить своим пользователям транслировать контент на него. К счастью, Cast SDK делает это невероятно простым. В вашем приложении вы захотите определить, подключен ли ваш пользователь к устройству, что можно сделать, убедившись, что SessionManager
имеет текущий Session
и что текущий Session
имеет связанный с ним объект RemoteMediaClient
.
1
2
|
if( CastContext.getSharedInstance(this).getSessionManager().getCurrentCastSession() != null
&& CastContext.getSharedInstance(this).getSessionManager().getCurrentCastSession().getRemoteMediaClient() != null ) {
|
Как только вы узнаете, что приложение связано с RemoteMediaClient
, вы захотите создать объект MediaInfo
, содержащий ссылку на удаленный контент, который вы хотите воспроизвести, а также типы потоков и контента для вашего мультимедиа. Когда MediaInfo
создан и заполнен, вы можете вызвать метод load в RemoteMediaClient
чтобы начать приведение содержимого. Например, следующий код переведет видео файл на телевизор.
1
2
3
4
5
6
7
8
9
|
RemoteMediaClient remoteMediaClient = CastContext.getSharedInstance(this).getSessionManager().getCurrentCastSession().getRemoteMediaClient();
MediaInfo mediaInfo = new MediaInfo.Builder(getString(R.string.movie_link))
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType(«videos/mp4»)
.build();
remoteMediaClient.load(mediaInfo, true, 0);
|
Метаданные
Компоненты приемника и пользовательского интерфейса в Cast SDK используют объект MediaMetadata
для хранения и ссылки на информацию о медиафайлах, которые воспроизводятся в данный момент. Вы можете добавлять значения к этому объекту, используя ключи, предоставленные классом, и вы можете добавлять URL-адреса изображений, используя метод addImage
.
1
2
3
4
5
|
MediaMetadata metadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
metadata.putString(MediaMetadata.KEY_TITLE, «Title»);
metadata.putString(MediaMetadata.KEY_SUBTITLE, «Subtitle»);
metadata.addImage(new WebImage(Uri.parse(getString(R.string.movie_poster))));
|
Как MediaMetadata
объект MediaMetadata
создан, вы можете связать его с MediaInfo
содержимого.
1
2
3
4
5
|
MediaInfo mediaInfo = new MediaInfo.Builder(getString(R.string.movie_link))
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType(«videos/mp4»)
.setMetadata(metadata)
.build();
|
UI Компоненты
Хотя Cast SDK обрабатывает логику подключения и трансляции контента на телевизор, он также предоставляет несколько компонентов пользовательского интерфейса, которые помогают разработчикам соответствовать рекомендациям по проектированию Casting UI .
Вводный оверлей
Когда ваш пользователь впервые открывает ваше приложение, рекомендуется сообщить ему, что вы поддерживаете Google Cast. Вы можете сделать это, включив IntroductoryOverlay
, который подсвечивает кнопку приведения, когда она становится доступной в первый раз.
Чтобы включить IntroductoryOverlay
, первое, что вам нужно сделать, это добавить его в качестве переменной-члена в верхней части вашего основного действия.
1
|
private IntroductoryOverlay mIntroductoryOverlay;
|
Если у вас есть общий объект для наложения, вы можете создать метод, который будет проверять, отображается ли кнопка медиа-маршрутизатора, и, если он отображается, отображает наложение.
Этот компонент реализован с использованием простого шаблона компоновщика, который принимает String
для текста, идентификатор ресурса цвета и несколько других атрибутов настройки. Чаще всего вы также захотите убедиться, что вы вызываете setSingleTime()
, чтобы наложение отображалось только один раз для пользователя.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
private void showIntroductoryOverlay() {
if (mIntroductoryOverlay != null) {
mIntroductoryOverlay.remove();
}
if ((mMediaRouterButton != null) && mMediaRouterButton.isVisible()) {
new Handler().post(new Runnable() {
@Override
public void run() {
mIntroductoryOverlay = new IntroductoryOverlay.Builder(
MainActivity.this, mMediaRouterButton)
.setTitleText(«Introduction text»)
.setOverlayColor(R.color.colorPrimary)
.setSingleTime()
.setOnOverlayDismissedListener(
new IntroductoryOverlay.OnOverlayDismissedListener() {
@Override
public void onOverlayDismissed() {
mIntroductoryOverlay = null;
}
})
.build();
mIntroductoryOverlay.show();
}
});
}
}
|
Теперь, когда у вас есть метод, созданный для отображения наложения, вам просто нужно будет вызвать его. Есть два момента, где вы должны добавить этот метод: в onCreateOptionsMenu
и в onCastStateChanged
из вашего CastStateListener
когда состояние не NO_DEVICES_AVAILABLE
. Это позволит справиться с обоими непредвиденными обстоятельствами появления кнопки маршрутизации.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
@Override
public void onCastStateChanged(int newState) {
if (newState != CastState.NO_DEVICES_AVAILABLE) {
showIntroductoryOverlay();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_main, menu);
mMediaRouterButton = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
menu,
R.id.media_route_menu_item);
showIntroductoryOverlay();
return true;
}
|
На этом этапе вы сможете запустить свое приложение и увидеть наложение, как показано на следующем рисунке. Если вам нужно увидеть его снова в целях тестирования, вы можете очистить данные своего приложения и снова открыть.
Расширенное управление
Во время трансляции вы захотите предоставить простой виджет пользовательского интерфейса для управления контентом на телевизоре пользователя. Google упростил это, предоставив класс ExpandedControllerActivity
в Cast SDK.
Чтобы использовать это, создайте новый класс Java и расширьте ExpandedControllerActivity
. Этот учебник создаст один с именем ExpandedControlsActivity
. Как только ваша деятельность будет создана, обновите onCreateOptionsMenu
чтобы включить кнопку маршрутизации приведения на панель инструментов.
01
02
03
04
05
06
07
08
09
10
|
public class ExpandedControlsActivity extends ExpandedControllerActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_main, menu);
CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item);
return true;
}
}
|
Затем откройте ваш класс OptionsProvider
. Вы захотите перейти в метод getCastOptions
и создать объект CastMediaOptions
который связан с вашим ExpandedControllerActivity
. Как только ваш объект CastMediaOptions
создан, вы можете связать его с элементом CastOptions
который возвращается методом.
01
02
03
04
05
06
07
08
09
10
11
12
|
CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
.setExpandedControllerActivityClassName(ExpandedControlsActivity.class.getName())
.build();
CastOptions castOptions = new CastOptions.Builder()
.setResumeSavedSession(true)
.setEnableReconnectionService(true)
.setReceiverApplicationId(context.getString(R.string.cast_app_id))
.setCastMediaOptions(mediaOptions)
.build();
return castOptions;
|
Наконец, чтобы получить работающий ExpandedControllerActivity
, вам нужно будет включить его в AndroidManifest.xml , вот так.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<activity
android:name=».ExpandedControlsActivity»
android:label=»@string/app_name»
android:theme=»@style/ExpandedCastControlsStyle»
android:launchMode=»singleTask»
android:screenOrientation=»portrait»>
<intent-filter>
<action android:name=»android.intent.action.MAIN»/>
</intent-filter>
<meta-data
android:name=»android.support.PARENT_ACTIVITY»
android:value=».MainActivity»/>
</activity>
|
Вы должны заметить, что для узла activity
установлен набор свойств theme
. Этот стиль используется для дополнительной настройки ExpandedControllerActivity
и отображаемых кнопок.
Контроллер состоит из четырех настраиваемых слотов кнопок, с переключателем воспроизведения / паузы в середине. Используя новый стиль и ресурсы массива, вы можете настроить, какие кнопки будут отображаться. В arrays.xml я добавил новый array
котором слот 1 становится пустым, слот 2 — 30-секундной кнопкой перемотки назад, слот 3 (первый элемент справа от переключателя воспроизведения / паузы) — для быстрой перемотки вперед на 30 секунд и последний слот для размещения отключения звука.
1
2
3
4
5
6
7
8
9
|
<?xml version=»1.0″ encoding=»utf-8″?>
<resources>
<array name=»cast_expanded_controller_control_buttons»>
<item>@id/cast_button_type_empty</item>
<item>@id/cast_button_type_rewind_30_seconds</item>
<item>@id/cast_button_type_forward_30_seconds</item>
<item>@id/cast_button_type_mute_toggle</item>
</array>
</resources>
|
Затем вы можете связать этот array
с вашим Activity
, создав новый ресурс style
и переопределив значение castExpandedControllerStyle
новым style
который расширяет CastExpandedController
.
1
2
3
4
5
6
7
|
<style name=»ExpandedCastControlsStyle» parent=»Theme.AppCompat.NoActionBar»>
<item name=»castExpandedControllerStyle»>@style/CustomCastExpandedController</item>
</style>
<style name=»CustomCastExpandedController» parent=»CastExpandedController»>
<item name=»castControlButtons»>@array/cast_expanded_controller_control_buttons</item>
</style>
|
На этом этапе вы должны иметь возможность щелкнуть изображение в диалоговом окне маршрутизатора, чтобы вставить носитель, чтобы открыть новый контроллер Activity
, или запустить его из приложения самостоятельно с помощью простого вызова startActivity
.
1
|
startActivity(new Intent(this, ExpandedControlsActivity.class));
|
Элементы управления уведомлением / блокировкой экрана
Когда пользователь загружает контент на свой телевизор, есть большая вероятность, что он не будет держать ваше приложение на переднем плане или его телефон разблокирован. Когда они уходят от вашего приложения, вы захотите предоставить им простой способ управления содержимым вашего приложения. Вы можете сделать это, добавив уведомление в свое приложение, когда оно не находится на переднем плане для устройств Lollipop и выше, и Cast SDK будет обрабатывать создание экрана блокировки RemoteControlClient
для KitKat и более ранних устройств.
getCastOptions
элементы управления уведомлением / блокировкой экрана довольно просто, поскольку все это обрабатывается в методе getCastOptions
вашего OptionsProvider
( CastOptionsProvider.java для этого урока).
Во-первых, вам нужно будет создать ArrayList
строк, который будет содержать кнопки, которые вы хотите использовать для своих элементов управления. Затем вы можете создать массив int
который будет содержать индексы кнопок, которые вы хотите отобразить, когда уведомление находится в компактном режиме.
Создав два массива, вы создадите объект NotificationOptions
который привязывает действия к новому уведомлению и назначит действие, которое будет открыто при выборе уведомления. Для этого примера мы просто будем использовать ExpandedControlsActivity
который мы создали в последнем разделе.
Наконец, вы можете добавить уведомление в ваши CastMediaOptions
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
List<String> buttonActions = new ArrayList<>();
buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK);
buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING);
int[] compatButtonActionsIndicies = new int[]{ 0, 1 };
NotificationOptions notificationOptions = new NotificationOptions.Builder()
.setActions(buttonActions, compatButtonActionsIndicies)
.setTargetActivityClassName(ExpandedControlsActivity.class.getName())
.build();
CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.setExpandedControllerActivityClassName(ExpandedControlsActivity.class.getName())
.build();
|
Теперь, когда ваши пользователи загружают контент на свои телевизоры и блокируют экран или уходят от вашего приложения, появляется уведомление, позволяющее им контролировать контент на большом экране, продолжая взаимодействовать со своим телефоном. Нажатие на уведомление вне элементов управления вернет ваше приложение на передний план с ExpandedControlsActivity
, предоставляя вашим пользователям более детальный контроль над их впечатлениями от просмотра.
Мини контроллер
Последний виджет пользовательского интерфейса, о котором вы узнаете в этом руководстве, — это MiniControllerFragment
. Этот элемент может быть помещен в файлы макета ваших действий, и когда ваше приложение будет транслировать контент, он автоматически станет видимым и предоставит легко доступный контроллер для ваших пользователей при просмотре вашего приложения. Хотя это последний компонент, который мы обсудим, он также является самым простым в реализации. Вам просто нужно включить его в файлы макета, вот так.
1
2
3
4
5
6
7
|
<fragment
android:id=»@+id/castMiniController»
android:layout_width=»match_parent»
android:layout_height=»wrap_content»
android:layout_alignParentBottom=»true»
android:visibility=»gone»
class=»com.google.android.gms.cast.framework.media.widget.MiniControllerFragment» />
|
Когда вы щелкнете по этому элементу в любом месте за пределами переключателя воспроизведения / паузы, откроется ваша ExtendedControllerActivity
, предоставляя вашим пользователям легкий доступ к контенту на их телевизоре.
Вывод
В этом руководстве вы узнали много нового о новом Google Cast SDK для Android, предоставляемых в нем компонентах пользовательского интерфейса и о том, как создать базовое приложение-приемник для кастинга. То, что вы рассмотрели здесь, поможет вам создавать наиболее распространенные типы приложений для кастинга, хотя Google также предоставляет функции, которые позволят вам быстро создавать игры с поддержкой Cast и пользовательские приложения-получатели .