以下程序可讓您將 Android 寄件者應用程式從 將使用 CCL 的 SDK 第 2 版投放到 CAF。CCL 的所有功能 ,因此當您完成遷移後,您就不需要使用 CCL。
Cast CAF 傳送端 SDK 會使用 CastContext 代您管理 GoogleAPIClient。 CastContext 可為您管理生命週期、錯誤和回呼, 簡化投放應用程式的開發程序。
簡介
- 由於 CAF 寄件者設計受到 Cast 隨附程式庫影響,因此 從 CCL 遷移至 CAF 寄件者,大多是一對一的對應作業 類別及其方法
- CAF 寄件者仍是 Google Play 服務的一部分 Android SDK Manager
- 已更新的套件 (
com.google.android.gms.cast.framework.*) 新增至 CAF 寄件者,具備類似 CCL 的功能 在任何情況下都能遵守 Google Cast 設計檢查清單。 - CAF 寄件者提供的小工具符合 Cast 使用者體驗規定。 這些小工具與 CCL 提供的小工具類似
- CAF 寄件者提供與 CCL 類似的非同步回呼,以便追蹤 狀態,並取得資料。與 CCL 不同,CAF 寄件者不提供任何免人工管理 各種介面方法的實作。
在後續章節中,我們會著重說明 使用 CCL 的 VideoCastManager 來顯示應用程式 概念也適用於 DataCastManager
依附元件
CCL 和 CAF 有相同的 AppCompat 支援資料庫依附元件, MediaRouter v7 支援資料庫和 Google Play 服務。不過 就是依賴 Google Play 新推出的 Cast 架構 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 的所有服務、活動和資源都會自動 與應用程式的資訊清單和資源合併
CAF 支援的最低 Android SDK 版本為 9 (Gingerbread);CCL 的最低 Android SDK 版本為 10。
CCL 提供了便利的方法
BaseCastManager.checkGooglePlayServices(activity),即可確認
版本的 Google Play 服務可取得。CAF 不含
作為 Cast SDK 的一部分按照程序操作
確保裝置已安裝 Google Play 服務 APK
確保使用者的
裝置,因為更新可能不會立即提供給所有使用者。
針對應用程式的 主題。
初始化
針對 CCL,VideoCastManager.initialize()必須在
應用程式執行個體的 onCreate() 方法。這個邏輯應該是
從您的 Application 類別代碼中移除。
在 CAF 中,投放內容還必須要有明確的初始化步驟
這個架構的重點在於這包括初始化 CastContext 單例模式,方法是使用
適當的 OptionsProvider 來指定接收器應用程式 ID,以及
或使用其他全域選項CastContext 的作用與 CCL 的
VideoCastManager,提供用戶端互動的單例模式。
OptionsProvider 類似於 CCL 的 CastConfiguration,可讓您
來設定 Cast 架構功能
如果您目前的 CCL CastConfiguration.Builder 顯示如下:
VideoCastManager.initialize(
getApplicationContext(),
new CastConfiguration.Builder(context.getString(R.string.app_id))
.enableWifiReconnection()
.enableAutoReconnect()
.build());
接著在 CAF 中使用 CastOptions.Builder,後續的 CastOptionsProvider
會類似於:
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。
在「application」中宣告 OptionsProvider元素的 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>
延後初始化每個 Activity 的 onCreate 方法中的 CastContext
(而非 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 應該
會從 Activities 的 onResume 和 onPause 方法中移除。
在 CAF 中,探索程序會自動啟動及停止 當應用程式進入前景並進入背景時 。
投放按鈕和投放對話方塊
與 CCL 一樣,這些元件是由 MediaRouter v7 支援提供 資源庫。
MediaRouteButton 仍會實作「投放」按鈕,但您可以新增
使用 ActionBar 或 Toolbar 做為選單項目
。
選單 XML 中的 MediaRouteActionProvider 宣告與
與 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() 方法,但 請使用 CAF 的 CastButtonFactory 屬性,不要使用 CastManager.addMediaRouterButton 來連接 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 中,傳送端應用程式可透過下列方式接收工作階段生命週期事件的通知:
使用 SessionManager 註冊 SessionManagerListener。
SessionManagerListener 回呼會定義所有工作階段的回呼方法
生命週期事件。
下列 SessionManagerListener 方法是從 CCL 的
VideoCastConsumer 介面:
VideoCastConsumer.onApplicationConnected->SessionManagerListener.onSessionStartedVideoCastConsumer.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 類別代表與投放裝置的工作階段。課程中有
控制裝置音量和靜音狀態的方法。
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);
為了明確中斷與投放裝置的連線,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 訊號暫時中斷,或其他網路錯誤。這項程序是在 工作階段層級工作階段可能會在使用者進入「暫停」狀態時連線狀態 並且將切換回 「已連線」連線狀態 已還原。架構會負責重新連線至接收器應用程式 重新連結任何投放頻道
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
分別為 RemoteMediaClient.Listener 的 onStatusUpdated 方法:
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
object;架構就會自動將物件例項化,並註冊
工作階段啟動時的基本媒體管道 (如果接收端應用程式處於
已連結至媒體命名空間。
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。
CCL 的 VideoCastManager 提供處理媒體播放的方法:
VideoCastManager manager = VideoCastManager.getInstance();
if (manager.isRemoteMediaLoaded()) {
manager.pause();
mCurrentPosition = (int) manager.getCurrentMediaPosition();
}
這些項目現已由 CAF 中的 RemoteMediaClient 實作:
if (mRemoteMediaClient.hasMediaSession()) {
mRemoteMediaClient.pause();
mCurrentPosition =
(int)mRemoteMediaClient.getApproximateStreamPosition();
}
在 CAF 中,透過 RemoteMediaClient 發出的所有媒體要求都會傳回
透過 PendingResult 回呼 RemoteMediaClient.MediaChannelResult
狀態可用來追蹤要求進度和最終結果
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 來判斷
「投放」按鈕亮起後,
MediaRouter 設為區域網路:
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();
}
});
}
}
請參閱 範例應用程式 ,找出顯示簡介疊加層的完整有效程式碼。
如要自訂簡介疊加層的樣式,請按照程序操作 自訂簡介疊加層。
迷你控制器
不要在 CCL 的 MiniController 中使用 CAF 的 MiniControllerFragment
您要顯示迷你活動的活動應用程式版面配置檔案
控制器:
<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 不支援 CCL 的 MiniController 支援的手動設定
且不支援 Autoplay 功能
如要自訂迷你控制器的樣式和按鈕,請按照 療程 自訂迷你控制器。
通知和螢幕鎖定
與 CCL 的 VideoCastNotificationService 類似,CAF 提供了
MediaNotificationService:管理媒體通知的顯示方式
。
您需要從資訊清單中移除以下項目:
VideoIntentReceiverVideoCastNotificationService
CCL 支援透過
CastConfiguration.Builder;並未受到 CAF 支援的
考慮使用 CCL 進行下列 CastManager 初始化:
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 並新增「投放」按鈕。
如何自訂展開畫面中顯示的樣式和按鈕 請按照 自訂展開控制器。
音訊焦點
與 CCL 一樣,系統會自動管理音訊焦點。
音量控制項
以 Gingerbread 來說,dispatchKeyEvent 必須與 CCL 一樣。ICS 以上版本
,系統會自動處理 CCL 與 CAF 音量控制的設定。
可運用 CAF 的硬性音量按鈕 進入應用程式活動後,螢幕還會顯示音量列 投放。CAF 也會透過 強制調整音量,即使應用程式位於應用程式前方、處於鎖定狀態,或 關閉。
隱藏式輔助字幕
在 Android KitKat 以上版本裝置上,則可透過字幕自訂字幕 設定位於「設定」>「設定」無障礙設定。舊版 Android 但不具備這項功能CCL 會透過自訂 以及委派給 KitKat 系統設定 以上。
CAF 並未提供變更字幕偏好設定的自訂設定。個人中心
應從資訊清單中移除 CaptionsPreferenceActivity 參照
以及偏好設定 XML
由於變更關閉狀態,因此不再需要 CCL 的 TracksChooserDialog
字幕軌是由展開的控制器使用者介面所處理
隱藏式輔助字幕 API 與第 2 版相同
偵錯記錄功能
CAF 不提供偵錯記錄設定。
其他
CAF 不支援下列 CCL 功能:
- 在播放廣告前先透過提供
MediaAuthService取得授權 - 可設定的 UI 訊息
範例應用程式
請參閱差異,瞭解如何將 Android 通用音樂播放器 (uamp) 範例應用程式從 CCL 遷移至 CAF。
我們也提供程式碼研究室教學課程,以及使用 CAF 的範例應用程式。