Android 送信者アプリを CCL を含む Cast SDK v2 から CAF に変換する手順は次のとおりです。CCL のすべての機能は CAF に実装されているため、移行後は CCL を使用する必要はありません。
Cast CAF Sender SDK は CastContext を使用して GoogleAPIClient を管理します。CastContext はライフサイクル、エラー、コールバックを管理し、Cast アプリの開発を大幅に簡素化します。
はじめに
- CAF Sender の設計は Cast コンパニオン ライブラリの影響を受けたため、CCF から CAF Sender に移行する場合、ほとんどの場合、クラスとそのメソッドを 1 対 1 でマッピングします。
- CAF Sender は引き続き Android SDK Manager を使用して Google Play 開発者サービスの一部として配布されます。
- CCL と同様の機能を備えた CAF Sender に追加された新しいパッケージ(
com.google.android.gms.cast.framework.*
)は、Google Cast Design チェックリストを遵守する責任があります。 - CAF センダーは、キャスト UX の要件を遵守するウィジェットを提供します。これらのウィジェットは CCL のウィジェットに似ています。
- CAF 送信者は、状態を追跡してデータを取得するために、CCL に似た非同期コールバックを提供します。CCL とは異なり、CAF Sender は、さまざまなインターフェース メソッドの no-op 実装を提供していません。
以降のセクションでは、主に CCL の VideoCastManager に基づく動画中心のアプリケーションに焦点を当てていますが、多くの場合、同じ概念が DataCastManager にも適用されます。
依存関係
CCL と CAF の依存関係は、AppCompat サポート ライブラリ、MediaRouter v7 サポート ライブラリ、Google Play 開発者サービスで同じです。ただし、CAF は、Google Play 開発者サービス 9.2.0 以降で利用可能な新しいキャスト フレームワークに依存する点が異なります。
build.gradle ファイルで、com.google.android.gms:play-services-cast
と com.google.android.libraries.cast.companionlibrary:ccl
への依存関係を削除してから、新しいキャスト フレームワークを追加します。
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 には、デバイスで Google Play 開発者サービスの互換バージョンを利用できることを確認するためのコンビニエンス メソッド BaseCastManager.checkGooglePlayServices(activity)
が用意されています。CAF は Cast SDK の一部としてこれを提供していません。デバイスに Google Play 開発者サービスの APK があることを確認するの手順に沿って、アップデートがすべてのユーザーにすぐに届くわけではないため、ユーザーのデバイスに正しい Google Play 開発者サービス APK がインストールされていることを確認します。
アプリのテーマには、Theme.AppCompat のバリアントを使用する必要があります。
初期化
CCL の場合、VideoCastManager.initialize()
をアプリケーション インスタンスの onCreate()
メソッドで呼び出す必要がありました。このロジックは、アプリケーション クラスコードから削除する必要があります。
CAF では、Cast フレームワークにも明示的な初期化手順が必要です。これには、適切な OptionsProvider
を使用してレシーバ アプリケーション ID とその他のグローバル オプションを指定する CastContext
シングルトンを初期化する必要があります。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 の完全な実装については、サンプルアプリをご覧ください。
AndroidManifest.xml ファイルの「application」要素で OptionsProvider を宣言します。
<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
メソッド(Application
インスタンスではない)で CastContext
を遅延初期化します。
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() メソッドをオーバーライドします。ただし、CastManager.addMediaRouterButton を使用する代わりに、CAF の CastButtonFactory を使用して MediaRouteButton をキャスト フレームワークに接続します。
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 が行うように、デバイスの音量とミュート状態を制御するメソッドが用意されています。
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
によって自動的に処理されます。
カスタム チャンネル登録
CCL には、受信者へのカスタム メッセージ チャネルを作成するための 2 つの方法が用意されています。
CastConfiguration
を使用すると複数の名前空間を指定すると、CCL によってチャンネルが作成されます。DataCastManager
は VideoCastManager に似ていますが、メディア以外のユースケースに焦点を当てています。
カスタム チャネルを作成する方法はどちらも CAF でサポートされておらず、送信者のアプリのカスタム チャネルの追加の手順を行う必要があります。
CCL と同様に、メディアアプリの場合、メディア コントロール チャンネルを明示的に登録する必要はありません。
メディア コントロール
CAF では、RemoteMediaClient
クラスは VideoCastManager
メディア メソッドと同等です。RemoteMediaClient.Listener
は VideoCastConsumer
メソッドと同等です。特に、VideoCastConsumer
の onRemoteMediaPlayerMetadataUpdated
メソッドと onRemoteMediaPlayerStatusUpdated
メソッドは、それぞれ RemoteMediaClient.Listener
の onMetadataUpdated
メソッドと 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
オブジェクトを明示的に初期化または登録する必要はありません。レシーバー アプリが接続されていて、メディア名前空間をサポートしている場合、フレームワークは自動的にオブジェクトをインスタンス化し、基盤となるメディア チャンネルを登録します。
RemoteMediaClient
には、CastSession
オブジェクトの getRemoteMediaClient
メソッドとしてアクセスできます。
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();
}
これらは Remote MediaClient によって CAF で実装されます。
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);
CCL は、レシーバ上の現在のメディア セッションの Media
情報とステータスを取得するために、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 が SDK に用意されています。通知とロック画面のコントロールは、CastContext
を初期化する際に CastOptions
で有効にできます。
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 では、CCL と同様、dispatchKeyEvent
が必要です。ICS 以降では、CCL と CAF の両方の音量コントロールが自動的に処理されます。
CAF を使用すると、アプリのアクティビティ内でスマートフォンのハード ボリューム ボタンを使用してキャスト ボリュームを制御できます。また、サポートされているバージョンでキャストする際に視覚的な音量バーが表示されます。CAF は、アプリが前面にない場合でも、ロックされていても、画面がオフの場合でも、ハード ボリュームを介して音量の変更を処理します。
字幕
Android KitKat 以降では、[設定] > [ユーザー補助] にある [字幕設定] で字幕をカスタマイズできます。ただし、以前のバージョンの Android にはこの機能はありません。CCL は、以前のバージョンにカスタム設定を行い、KitKat 以降のシステム設定に委任することで、この処理を行います。
CAF には、字幕設定を変更するためのカスタム設定はありません。マニフェストと設定 XML から CaptionsPreferenceActivity
参照を削除する必要があります。
字幕トラックの変更は拡張コントローラ UI で処理されるため、CCL の TracksChooserDialog
は不要になりました。
CAF のクローズド キャプション API は v2 に似ています。
デバッグ ロギング
CAF にはデバッグ ロギングの設定が提供されません。
その他
CAF では、次の CCL 機能はサポートされていません。
MediaAuthService
を提供して再生前に承認を取得する- 設定可能な UI メッセージ
サンプルアプリ
Android 用ユニバーサル ミュージック プレーヤー(uamp)サンプルアプリを CCL から CAF に移行するための差分を確認する。
CAF を使用する Codelab チュートリアルとサンプルアプリもあります。