Следующая процедура позволяет преобразовать приложение Android-отправителя из Cast SDK v2 с CCL в CAF. Все функции CCL реализованы в CAF, поэтому после миграции вам больше не понадобится использовать CCL.
SDK Cast CAF Sender использует CastContext для управления GoogleAPIClient от вашего имени. CastContext управляет жизненными циклами, ошибками и обратными вызовами, что значительно упрощает разработку приложения Cast.
Введение
- Поскольку на дизайн CAF Sender повлияла Cast Companion Library, переход от CCL к CAF Sender включает в себя в основном однозначное сопоставление классов и их методов.
- CAF Sender по-прежнему распространяется как часть сервисов Google Play с помощью менеджера Android SDK.
- Новые пакеты (
com.google.android.gms.cast.framework.*
), добавленные в CAF Sender, с функциональностью, аналогичной CCL, берут на себя ответственность за соответствие контрольному списку Google Cast Design . - CAF Sender предоставляет виджеты, соответствующие требованиям Cast UX; эти виджеты аналогичны виджетам, предоставляемым CCL.
- CAF Sender предоставляет асинхронные обратные вызовы, аналогичные CCL, для отслеживания состояний и получения данных. В отличие от CCL, CAF Sender не предоставляет никаких неоперативных реализаций различных методов интерфейса.
В следующих разделах мы в основном сосредоточимся на видеоприложениях, основанных на VideoCastManager от CCL, но во многих случаях те же концепции применимы и к DataCastManager.
Зависимости
CCL и CAF имеют одинаковые зависимости от библиотеки поддержки AppCompat, библиотеки поддержки MediaRouter v7 и сервисов Google Play. Однако разница в том, что CAF зависит от новой платформы Cast, доступной в сервисах Google Play 9.2.0 или более поздней версии.
В файле build.gradle удалите зависимости от com.google.android.gms:play-services-cast
и com.google.android.libraries.cast.companionlibrary:ccl
, затем добавьте новую платформу Cast:
dependencies {
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:mediarouter-v7:23.4.0'
compile 'com.google.android.gms:play-services-cast-framework:9.4.0'
}
Вы также можете удалить метаданные сервиса Google Play:
<meta‐data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>
Любые службы, действия и ресурсы, являющиеся частью CAF, автоматически объединяются с манифестом и ресурсами вашего приложения.
Минимальная версия Android SDK, которую поддерживает CAF, — 9 (Gingerbread); Минимальная версия Android SDK CCL — 10.
CCL предоставляет удобный метод BaseCastManager.checkGooglePlayServices(activity)
для проверки доступности совместимой версии сервисов Google Play на устройстве. CAF не предоставляет это как часть Cast SDK. Выполните процедуру «Убедитесь, что на устройствах установлен APK-файл служб Google Play», чтобы убедиться, что на устройстве пользователя установлен правильный APK-файл служб Google Play, поскольку обновления могут не доходить до всех пользователей сразу.
Вам по-прежнему необходимо использовать вариант Theme.AppCompat для темы приложения.
Инициализация
Для CCL необходимо было вызвать VideoCastManager.initialize()
в методе onCreate()
экземпляра Applications. Эту логику следует удалить из кода класса приложения.
В CAF для платформы Cast также требуется явный этап инициализации. Это включает в себя инициализацию синглтона CastContext
с использованием соответствующего OptionsProvider
для указания идентификатора приложения-получателя и любых других глобальных параметров. CastContext
играет аналогичную роль VideoCastManager
CCL, предоставляя синглтон, с которым взаимодействуют клиенты. OptionsProvider
аналогичен CastConfiguration
CCL и позволяет вам настраивать функции платформы Cast.
Если ваш текущий CCL CastConfiguration.Builder
выглядит так:
VideoCastManager.initialize(
getApplicationContext(),
new CastConfiguration.Builder(context.getString(R.string.app_id))
.enableWifiReconnection()
.enableAutoReconnect()
.build());
Тогда в CAF следующий CastOptionsProvider
использующий CastOptions.Builder
, будет аналогичен:
public class CastOptionsProvider implements OptionsProvider {
@Override
public CastOptions getCastOptions(Context context) {
return new CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.build();
}
@Override
public List<SessionProvider> getAdditionalSessionProviders(
Context context) {
return null;
}
}
Взгляните на наш пример приложения , чтобы увидеть полную реализацию OptionsProvider.
Объявите OptionsProvider в элементе application файла AndroidManifest.xml:
<application>
...
<meta-data
android:name=
"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.sample.cast.refplayer.CastOptionsProvider"
/>
</application>
Лениво инициализируйте CastContext
в каждом методе onCreate
Activity
(а не в экземпляре Application
):
private CastContext mCastContext;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.video_browser);
setupActionBar();
mCastContext = CastContext.getSharedInstance(this);
}
Для доступа к синглтону CastContext
используйте:
mCastContext = CastContext.getSharedInstance(this);
Обнаружение устройств
CCL VideoCastManager
и incrementUiCounter
decrementUiCounter
быть удалены из методов onResume
и onPause
ваших Activities
.
В CAF процесс обнаружения запускается и останавливается платформой автоматически, когда приложение переходит на передний план и переходит в фоновый режим соответственно.
Кнопка трансляции и диалоговое окно трансляции
Как и в случае с CCL, эти компоненты предоставляются библиотекой поддержки MediaRouter v7.
Кнопка Cast по-прежнему реализуется с помощью MediaRouteButton
и может быть добавлена в вашу активность (с помощью ActionBar
или Toolbar
) в качестве пункта меню в вашем меню.
Объявление MediaRouteActionProvider
в меню xml такое же, как и в CCL:
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"
app:showAsAction="always"/>
Подобно CCL, переопределите метод onCreateOptionMenu() каждого действия, но вместо использования CastManager.addMediaRouterButton используйте CastButtonFactory CAF для подключения MediaRouteButton к платформе Cast:
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.browse, menu);
CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
menu,
R.id.media_route_menu_item);
return true;
}
Управление устройством
Как и в CCL, в CAF управление устройствами в основном осуществляется платформой. Приложению-отправителю не нужно обрабатывать (и не должно пытаться это делать) подключение к устройству и запуск приложения-получателя с помощью GoogleApiClient
.
Взаимодействие между отправителем и получателем теперь представлено как «сессия». Класс SessionManager
управляет жизненным циклом сеанса и автоматически запускает и останавливает сеансы в ответ на жесты пользователя: сеанс запускается, когда пользователь выбирает устройство трансляции в диалоговом окне трансляции, и завершается, когда пользователь нажимает кнопку «Остановить трансляцию» в диалоговом окне трансляции. диалоговое окно или когда само приложение-отправитель завершает работу.
В CCL вам необходимо расширить класс VideoCastConsumerImpl
, чтобы отслеживать состояние сеанса трансляции:
private final VideoCastConsumer mCastConsumer = new VideoCastConsumerImpl() {
public void onApplicationConnected(ApplicationMetadata appMetadata,
String sessionId,
boolean wasLaunched) {}
public void onDisconnectionReason(int reason) {}
public void onDisconnected() {}
}
В CAF приложение-отправитель может быть уведомлено о событиях жизненного цикла сеанса, зарегистрировав SessionManagerListener
с помощью SessionManager
. Обратные вызовы SessionManagerListener определяют методы обратного вызова для всех событий жизненного цикла сеанса.
Следующие методы SessionManagerListener
отображаются из интерфейса VideoCastConsumer
CCL:
-
VideoCastConsumer.onApplicationConnected
->SessionManagerListener.onSessionStarted
-
VideoCastConsumer.onDisconnected
->SessionManagerListener.onSessionEnded
Объявите класс, реализующий интерфейс SessionManagerListener
, и переместите логику VideoCastConsumerImpl
в соответствующие методы:
private class CastSessionManagerListener implements SessionManagerListener<CastSession> {
public void onSessionEnded(CastSession session, int error) {}
public void onSessionStarted(CastSession session, String sessionId) {}
public void onSessionEnding(CastSession session) {}
...
}
Класс CastSession
представляет сеанс с устройством Cast. В классе есть методы для управления громкостью устройства и состояниями отключения звука, что CCL делает в BaseCastManager
.
Вместо использования CCL VideoCastManager
для добавления потребителя:
VideoCastManager.getInstance().addVideoCastConsumer(mCastConsumer);
Теперь зарегистрируйте свой SessionManagerListener
:
mCastSessionManager =
CastContext.getSharedInstance(this).getSessionManager();
mCastSessionManagerListener = new CastSessionManagerListener();
mCastSessionManager.addSessionManagerListener(mCastSessionManagerListener,
CastSession.class);
Чтобы прекратить прослушивание событий в CCL:
VideoCastManager.getInstance().removeVideoCastConsumer(mCastConsumer);
Теперь используйте SessionManager
, чтобы прекратить прослушивание событий сеанса:
mCastSessionManager.removeSessionManagerListener(mCastSessionManagerListener,
CastSession.class);
Чтобы явно отключиться от устройства Cast, CCL использовал:
VideoCastManager.disconnectDevice(boolean stopAppOnExit,
boolean clearPersistedConnectionData,
boolean setDefaultRoute)
Для CAF используйте SessionManager
:
CastContext.getSharedInstance(this).getSessionManager()
.endCurrentSession(true);
Чтобы определить, подключен ли отправитель к получателю, CCL предоставляет VideoCastManager.getInstance().isConnected()
, но в CAF используйте SessionManager
:
public boolean isConnected() {
CastSession castSession = CastContext.getSharedInstance(mAppContext)
.getSessionManager()
.getCurrentCastSession();
return (castSession != null && castSession.isConnected());
}
В CAF уведомления об изменении состояния громкости/отключения звука по-прежнему доставляются через методы обратного вызова в Cast.Listener
; эти прослушиватели зарегистрированы в CastSession
. Все остальные уведомления о состоянии устройства доставляются через обратные вызовы CastStateListener
; эти прослушиватели зарегистрированы в CastSession
. Убедитесь, что вы по-прежнему отменяете регистрацию прослушивателей, когда связанные фрагменты, действия или приложения переходят в фоновый режим.
Логика переподключения
CAF пытается восстановить сетевые соединения, потерянные из-за временной потери сигнала Wi-Fi или других сетевых ошибок. Теперь это делается на уровне сеанса; сеанс может перейти в «приостановленное» состояние при потере соединения и вернуться в «подключенное» состояние при восстановлении соединения. Платформа заботится о повторном подключении к приложению-приемнику и повторном подключении всех каналов Cast в рамках этого процесса.
CAF предоставляет собственную службу переподключения, поэтому вы можете удалить CCL ReconnectionService
из своего манифеста:
<service android:name="com.google.android.libraries.cast.companionlibrary.cast.reconnection.ReconnectionService"/>
Вам также не нужны следующие разрешения в вашем манифесте для логики повторного подключения:
<uses‐permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses‐permission android:name="android.permission.ACCESS_WIFI_STATE"/>
Служба переподключения CAF включена по умолчанию, но ее можно отключить с помощью CastOptions
.
Кроме того, CAF также добавляет автоматическое возобновление сеанса, которое включено по умолчанию (и может быть отключено с помощью CastOptions
). Если приложение-отправитель отправляется в фоновый режим или завершается (путем смахивания или из-за сбоя) во время сеанса трансляции, платформа попытается возобновить этот сеанс, когда приложение-отправитель вернется на передний план или перезапустится; это автоматически обрабатывается SessionManager
, который выдает соответствующие обратные вызовы для всех зарегистрированных экземпляров SessionManagerListener
.
Регистрация пользовательского канала
CCL предоставляет два способа создания пользовательского канала сообщений для получателя:
-
CastConfiguration
позволяет вам указать несколько пространств имен, и CCL затем создаст для вас канал. -
DataCastManager
похож на VideoCastManager, но ориентирован на случаи использования, не связанные с мультимедиа.
Ни один из этих способов создания пользовательского канала не поддерживается CAF — вместо этого вам необходимо выполнить процедуру «Добавление пользовательского канала для вашего приложения-отправителя».
Как и в случае с CCL, для мультимедийных приложений нет необходимости явно регистрировать канал управления мультимедиа.
Контроль СМИ
В CAF класс RemoteMediaClient
эквивалентен медиа-методам VideoCastManager
. RemoteMediaClient.Listener
эквивалентен методам VideoCastConsumer
. В частности, методы onRemoteMediaPlayerMetadataUpdated
и onRemoteMediaPlayerStatusUpdated
объекта VideoCastConsumer
сопоставляются с методами onMetadataUpdated
и onStatusUpdated
объекта RemoteMediaClient.Listener
соответственно:
private class CastMediaClientListener implements RemoteMediaClient.Listener {
@Override
public void onMetadataUpdated() {
setMetadataFromRemote();
}
@Override
public void onStatusUpdated() {
updatePlaybackState();
}
@Override
public void onSendingRemoteMediaRequest() {
}
@Override
public void onQueueStatusUpdated() {
}
@Override
public void onPreloadStatusUpdated() {
}
}
Нет необходимости явно инициализировать или регистрировать объект RemoteMediaClient
; платформа автоматически создаст экземпляр объекта и зарегистрирует базовый медиаканал во время начала сеанса, если приложение-получатель, к которому подключается соединение, поддерживает пространство имен мультимедиа.
Доступ RemoteMediaClient
можно получить как метод getRemoteMediaClient
объекта CastSession
.
CastSession castSession = CastContext.getSharedInstance(mAppContext)
.getSessionManager()
.getCurrentCastSession();
mRemoteMediaClient = castSession.getRemoteMediaClient();
mRemoteMediaClientListener = new CastMediaClientListener();
Вместо CCL:
VideoCastManager.getInstance().addVideoCastConsumer(mCastConsumer);
Теперь используйте CAF:
mRemoteMediaClient.addListener(mRemoteMediaClientListener);
В RemoteMediaClient
можно зарегистрировать любое количество прослушивателей, что позволяет нескольким компонентам-отправителям совместно использовать один экземпляр RemoteMediaClient
, связанный с сеансом.
VideoCastManager
CCL предоставляет методы для управления воспроизведением мультимедиа:
VideoCastManager manager = VideoCastManager.getInstance();
if (manager.isRemoteMediaLoaded()) {
manager.pause();
mCurrentPosition = (int) manager.getCurrentMediaPosition();
}
Теперь они реализованы RemoteMediaClient в CAF:
if (mRemoteMediaClient.hasMediaSession()) {
mRemoteMediaClient.pause();
mCurrentPosition =
(int)mRemoteMediaClient.getApproximateStreamPosition();
}
В CAF все медиа-запросы, отправленные на RemoteMediaClient
возвращают RemoteMediaClient.MediaChannelResult
через обратный вызов PendingResult
, который можно использовать для отслеживания хода выполнения и конечного результата запроса.
И CCL, и CAF используют классы MediaInfo
и MediaMetadata
для представления элементов мультимедиа и загрузки мультимедиа.
Для загрузки медиа в CCL используется VideoCastManager
:
VideoCastManager.getInstance().loadMedia(media, autoPlay, mCurrentPosition, customData);
В CAF RemoteMediaClient
используется для загрузки носителя:
mRemoteMediaClient.load(media, autoPlay, mCurrentPosition, customData);
Чтобы получить информацию Media
и статус текущего сеанса мультимедиа на приемнике, CCL использует VideoCastManager
:
MediaInfo mediaInfo = VideoCastManager.getInstance()
.getRemoteMediaInformation();
int status = VideoCastManager.getInstance().getPlaybackStatus();
int idleReason = VideoCastManager.getInstance().getIdleReason();
В CAF используйте RemoteMediaClient
для получения той же информации:
MediaInfo mediaInfo = mRemoteMediaClient.getMediaInfo();
int status = mRemoteMediaClient.getPlayerState();
int idleReason = mRemoteMediaClient.getIdleReason();
Вводное наложение
Подобно CCL, CAF предоставляет настраиваемое представление IntroductoryOverlay
для выделения кнопки трансляции, когда она впервые отображается пользователям.
Вместо использования метода CCL VideoCastConsumer
onCastAvailabilityChanged
чтобы знать, когда отображать наложение, объявите CastStateListener
, чтобы определить, когда кнопка Cast станет видимой после того, как MediaRouter
обнаружит устройства Cast в локальной сети:
private IntroductoryOverlay mIntroductoryOverlay;
private MenuItem mMediaRouteMenuItem;
protected void onCreate(Bundle savedInstanceState) {
...
mCastStateListener = new CastStateListener() {
@Override
public void onCastStateChanged(int newState) {
if (newState != CastState.NO_DEVICES_AVAILABLE) {
showIntroductoryOverlay();
}
}
};
mCastContext = CastContext.getSharedInstance(this);
mCastContext.registerLifecycleCallbacksBeforeIceCreamSandwich(this,
savedInstanceState);
}
protected void onResume() {
mCastContext.addCastStateListener(mCastStateListener);
...
}
protected void onPause() {
mCastContext.removeCastStateListener(mCastStateListener);
...
}
Отслеживайте экземпляр MediaRouteMenuItem
:
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.browse, menu);
mMediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(
getApplicationContext(), menu,
R.id.media_route_menu_item);
showIntroductoryOverlay();
return true;
}
Проверьте, отображается ли MediaRouteButton
, чтобы можно было отобразить вводное наложение:
private void showIntroductoryOverlay() {
if (mIntroductoryOverlay != null) {
mIntroductoryOverlay.remove();
}
if ((mMediaRouteMenuItem != null) && mMediaRouteMenuItem.isVisible()) {
new Handler().post(new Runnable() {
@Override
public void run() {
mIntroductoryOverlay = new IntroductoryOverlay.Builder(
VideoBrowserActivity.this, mMediaRouteMenuItem)
.setTitleText(getString(R.string.introducing_cast))
.setOverlayColor(R.color.primary)
.setSingleTime()
.setOnOverlayDismissedListener(
new IntroductoryOverlay
.OnOverlayDismissedListener() {
@Override
public void onOverlayDismissed() {
mIntroductoryOverlay = null;
}
})
.build();
mIntroductoryOverlay.show();
}
});
}
}
Взгляните на наш пример приложения , чтобы увидеть полный рабочий код для отображения вводного наложения.
Чтобы настроить стиль вводного наложения, выполните процедуру «Настройка вводного наложения» .
Мини-контроллер
Вместо MiniController
CCL используйте MiniControllerFragment
CAF в файле макета приложения для действий, в которых вы хотите отобразить мини-контроллер:
<fragment
android:id="@+id/cast_mini_controller"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:castShowImageThumbnail="true"
android:visibility="gone"
class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment" />
CAF не поддерживает ручную настройку, поддерживаемую MiniController
CCL, а также не поддерживает функцию Autoplay
.
Чтобы настроить стиль и кнопки мини-контроллера, выполните процедуру «Настройка мини-контроллера» .
Уведомления и экран блокировки
Подобно VideoCastNotificationService
CCL, CAF предоставляет MediaNotificationService
для управления отображением мультимедийных уведомлений при трансляции.
Вам необходимо удалить из манифеста следующее:
-
VideoIntentReceiver
-
VideoCastNotificationService
CCL поддерживает предоставление настраиваемой службы уведомлений с помощью CastConfiguration.Builder
; это не поддерживается CAF.
Рассмотрим следующую инициализацию CastManager
с использованием CCL:
VideoCastManager.initialize(
getApplicationContext(),
new CastConfiguration.Builder(
context.getString(R.string.app_id))
.addNotificationAction(
CastConfiguration.NOTIFICATION_ACTION_PLAY_PAUSE,true)
.addNotificationAction(
CastConfiguration.NOTIFICATION_ACTION_DISCONNECT,true)
.build());
Для эквивалентной конфигурации в CAF SDK предоставляет NotificationsOptions.Builder
, который поможет вам создать элементы управления мультимедиа для уведомлений и экрана блокировки в приложении отправителя. Элементы управления уведомлениями и экраном блокировки можно включить с помощью CastOptions
при инициализации CastContext
.
public CastOptions getCastOptions(Context context) {
NotificationOptions notificationOptions =
new NotificationOptions.Builder()
.setActions(Arrays.asList(
MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK,
MediaIntentReceiver.ACTION_STOP_CASTING), new int[]{0, 1})
.build();
CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.build();
return new CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.setCastMediaOptions(mediaOptions)
.build();
}
Уведомления и элементы управления экраном блокировки всегда включены в CAF. Также обратите внимание, что кнопки воспроизведения/паузы и остановки трансляции предусмотрены по умолчанию. CAF будет автоматически отслеживать видимость действий, чтобы решить, когда отображать мультимедийное уведомление, за исключением Gingerbread. (Для Gingerbread см. предыдущее примечание об использовании registerLifecycleCallbacksBeforeIceCreamSandwich()
; вызовы CCL VideoCastManager
incrementUiCounter
и decrementUiCounter
должны быть удалены.)
Чтобы настроить кнопки, отображаемые в уведомлениях, выполните процедуру «Добавление элементов управления мультимедиа на экран уведомлений и блокировки» .
Расширенный контроллер
CCL предоставляет VideoCastControllerActivity
и VideoCastControllerFragment
для отображения расширенного контроллера при трансляции мультимедиа.
Вы можете удалить объявление VideoCastControllerActivity
в манифесте.
В CAF вам придется расширить ExpandedControllerActivity и добавить кнопку Cast .
Чтобы настроить стили и кнопки, отображаемые в расширенном контроллере, выполните процедуру «Настройка расширенного контроллера» .
Аудио фокус
Как и в случае с CCL, фокус звука управляется автоматически.
Регулятор громкости
Для Gingerbread требуется dispatchKeyEvent
, как и для CCL. В ICS и выше для CCL и CAF регулировка громкости осуществляется автоматически.
CAF позволяет управлять громкостью трансляции с помощью жесткой кнопки громкости на телефоне в действиях ваших приложений, а также отображает визуальную панель громкости при трансляции в поддерживаемых версиях. CAF также обрабатывает изменение громкости с помощью жесткого тома, даже если ваше приложение не на переднем плане, заблокировано или даже если экран выключен.
Скрытые субтитры
В Android KitKat и более поздних версиях подписи можно настроить в настройках подписей, которые находятся в разделе «Настройки» > «Доступность». Однако более ранние версии Android не имеют такой возможности. CCL решает эту проблему, предоставляя пользовательские настройки для более ранних версий и делегируя их системным настройкам в KitKat и выше.
CAF не предоставляет пользовательских настроек для изменения предпочтений подписей. Вам следует удалить ссылки CaptionsPreferenceActivity
в своем манифесте и XML-файле настроек.
TracksChooserDialog
CCL больше не нужен, поскольку изменение дорожек субтитров обрабатывается расширенным пользовательским интерфейсом контроллера.
API субтитров в CAF аналогичен версии 2.
Ведение журнала отладки
CAF не предоставляет настройки ведения журнала отладки.
Разное
Следующие функции CCL не поддерживаются в CAF:
- Получение авторизации перед воспроизведением путем предоставления
MediaAuthService
- Настраиваемые сообщения пользовательского интерфейса
Примеры приложений
Взгляните на разницу при переносе нашего примера приложения Universal Music Player для Android (uamp) из CCL в CAF.
У нас также есть учебные пособия по кодированию и примеры приложений , использующих CAF.