將 CCL 寄件者應用程式遷移至 Cast 應用程式架構 (CAF)

以下程序可讓您將 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 服務中繼資料:

<metadata 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>

延後初始化每個 ActivityonCreate 方法中的 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 incrementUiCounterdecrementUiCounter 應該 會從 ActivitiesonResumeonPause 方法中移除。

在 CAF 中,探索程序會自動啟動及停止 當應用程式進入前景並進入背景時 。

投放按鈕和投放對話方塊

與 CCL 一樣,這些元件是由 MediaRouter v7 支援提供 資源庫。

MediaRouteButton 仍會實作「投放」按鈕,但您可以新增 使用 ActionBarToolbar 做為選單項目 。

選單 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.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 類別代表與投放裝置的工作階段。課程中有 控制裝置音量和靜音狀態的方法。 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"/>

您也不需要在資訊清單中使用以下權限: 重新連線邏輯:

<usespermission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<usespermission 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」和「onRemoteMediaPlayerStatusUpdatedVideoCastConsumer 的方法會對應至 onMetadataUpdated 分別為 RemoteMediaClient.ListeneronStatusUpdated 方法:

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 都會使用 MediaInfoMediaMetadata 類別來代表 媒體項目及載入媒體

如要在 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:管理媒體通知的顯示方式 。

您需要從資訊清單中移除以下項目:

  • VideoIntentReceiver
  • VideoCastNotificationService

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 incrementUiCounterdecrementUiCounter 呼叫 )。

如要自訂通知中顯示的按鈕,請按照 療程 在通知和螢幕鎖定畫面中加入媒體控制項

展開的控制器

CCL 提供 VideoCastControllerActivityVideoCastControllerFragment 在投放媒體時顯示展開的控制器。

您可以移除資訊清單中的 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 的範例應用程式