將 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 服務中繼資料:

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

延後初始化每個 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"/>

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

<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」和「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 的範例應用程式