このデベロッパー ガイドでは、Android デバイスに Google Cast サポートを追加する方法について説明します。 Android Sender SDK を使用して送信側のアプリを
モバイル デバイスまたはノートパソコンが、再生を制御する送信者となり、 Google Cast デバイスは、テレビにコンテンツを表示するレシーバーです。
送信フレームワークは、Cast クラス ライブラリ バイナリを参照し、 リソースが含まれます。送信アプリまたはキャスト アプリ 送信者上でも動作しているアプリを指します。ウェブ レシーバー アプリ Cast 対応デバイスで実行される HTML アプリケーションを指します。
送信者フレームワークは、非同期コールバック設計を使用して送信者に通知します。 イベントのアプリ、キャストアプリの動作状態の切り替え サイクルです。
アプリケーションの流れ
次の手順は、送信者の一般的な実行フローの概要です。 Android アプリ:
- キャスト フレームワークが自動的に起動し、
MediaRouter
Activity
のライフサイクルに基づくデバイスの検出。 - ユーザーがキャスト ボタンをクリックすると、フレームワークによってキャストが表示されます。 ダイアログに、検出されたキャスト デバイスのリストが表示されます。
- ユーザーがキャスト デバイスを選択すると、フレームワークはデバイスの起動を試行します。 キャスト デバイス上のウェブ レシーバー アプリ
- フレームワークは送信側のアプリでコールバックを呼び出して、 レシーバーアプリが起動されました。
- フレームワークが送信者とウェブの間に通信チャネルを作成する レシーバー アプリ
- フレームワークは通信チャネルを使用してメディアを読み込み、制御します。 ウェブレシーバーで再生します。
- フレームワークは、送信側と受信側との間でメディアの再生状態を同期します。 Web Receiver: ユーザーが送信者 UI アクションを実行すると、フレームワークは Web Receiver に送信されたメディア コントロール リクエストと、Web Receiver が メディア ステータスの更新を送信すると、フレームワークは送信側の UI の状態を更新します。
- ユーザーがキャスト ボタンをクリックしてキャスト デバイスとの接続を解除すると、 フレームワークによって、送信者アプリと Web Receiver の接続が解除されます。
Google Cast のすべてのクラス、メソッド、イベントを網羅したリスト 詳しくは、Google Cast Sender API リファレンスの Android。 以下のセクションでは、Android アプリにキャストを追加する手順について説明します。
Android マニフェストを設定する
アプリの AndroidManifest.xml ファイルで次の設定を行う必要があります。 追加しましょう。
uses-sdk
Cast SDK がサポートする最小および対象 Android API レベルを設定します。 現在の最小要件は API レベル 23 で、ターゲットは API レベル 34。
<uses-sdk
android:minSdkVersion="23"
android:targetSdkVersion="34" />
android:theme
Android SDK の最小バージョンに基づいてアプリのテーマを設定します。たとえば
独自のテーマを実装しない場合は、
最小 Android SDK バージョンをターゲットにする場合は Theme.AppCompat
リリースされます。
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat" >
...
</application>
キャスト コンテキストを初期化する
フレームワークには、CastContext
というグローバル シングルトン オブジェクトがあり、
すべてのフレームワークのインタラクションが
記録されます
アプリは
OptionsProvider
インターフェースの初期化に必要なオプションを
CastContext
あります。OptionsProvider
は、
CastOptions
フレームワークの動作に影響するオプションが含まれています。最も
その中でも重要なのが Web Receiver アプリケーション ID です。
キャスト セッションの開始時にウェブ レシーバー アプリを起動できます。
開始しました。
class CastOptionsProvider : OptionsProvider { override fun getCastOptions(context: Context): CastOptions { return Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .build() } override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? { return null } }
public class CastOptionsProvider implements OptionsProvider { @Override public CastOptions getCastOptions(Context context) { CastOptions castOptions = new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .build(); return castOptions; } @Override public List<SessionProvider> getAdditionalSessionProviders(Context context) { return null; } }
実装された OptionsProvider
の完全修飾名を宣言する必要があります。
送信側のアプリの AndroidManifest.xml ファイルにメタデータ フィールドとして指定:
<application>
...
<meta-data
android:name=
"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.foo.CastOptionsProvider" />
</application>
CastContext
は、CastContext.getSharedInstance()
エラーの発生時に遅延初期化される
が呼び出されます。
class MyActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { val castContext = CastContext.getSharedInstance(this) } }
public class MyActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { CastContext castContext = CastContext.getSharedInstance(this); } }
Cast UX ウィジェット
Cast フレームワークは Cast Design に準拠したウィジェットを提供します チェックリスト:
導入オーバーレイ: フレームワークにはカスタムビューがあり、
IntroductoryOverlay
、 キャスト アイコンに注意を向けるために表示される 受信側の最初の 1,000 回という通知が返ってきました送信側アプリは タイトルのテキストと位置をカスタマイズする text です。キャスト アイコン: キャスト アイコンは、キャスト デバイスが利用できるかどうかに関係なく表示されます。 ユーザーが初めてキャスト アイコンをクリックしたときに、キャスト ダイアログが表示されます。 検出されたデバイスのリストが表示されます。ユーザーがキャスト アイコンをクリックしたとき デバイスの接続中は、現在のメディア メタデータ( タイトル、レコーディング スタジオの名前、サムネイル画像)を表示するか、 キャスト デバイスとの接続を解除します。「キャスト アイコン」呼ばれることもある 「キャスト アイコン」を選択します。
ミニ コントローラ: ユーザーがコンテンツをキャスト中で、現在の画面から移動した場合 送信側のアプリで別の画面にコンテンツ ページが開いたら、 ミニ コントローラが表示され、ユーザーは 現在キャスト中のメディアのメタデータを確認したり、再生を操作したりできます。
拡張コントローラ: ユーザーがコンテンツをキャストしているときにメディア通知をクリックしたとき 拡張コントローラが起動し、 現在再生中のメディア メタデータのほか、複数のボタンで 行います。
通知: Android のみ。ユーザーがコンテンツをキャストしているときに 送信側のアプリに対して、現在キャスト中であることを示すメディア通知が表示されます。 再生コントロールなどの機能を利用できます。
ロック画面: Android のみ。ユーザーがコンテンツをキャストしているときに、 ] をタップすると、ロック中にメディアロック画面のコントロールが 現在キャスト中のメディアのメタデータと再生コントロールが表示されます。
以下のガイドでは、これらのウィジェットを 説明します。
キャスト アイコンを追加する
Android
MediaRouter
API は、セカンダリ デバイスでメディアの表示と再生を可能にするように設計されています。
MediaRouter
API を使用する Android アプリには、キャスト アイコンを組み込む必要があります。
ユーザーがメディアを再生するメディアルートを選択できるようになります。
キャスト デバイスなどのセカンダリ デバイスに接続する必要があります。
このフレームワークでは、
MediaRouteButton
として
Cast button
とても簡単です。まず、xml にメニュー項目または MediaRouteButton
を追加する必要があります。
ファイルを定義します。また、
CastButtonFactory
フレームワークに接続する必要があります。
// To add a Cast button, add the following snippet.
// menu.xml
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always" />
<ph type="x-smartling-placeholder">// Then override the onCreateOptionMenu() for each of your activities. // MyActivity.kt override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.main, menu) CastButtonFactory.setUpMediaRouteButton( applicationContext, menu, R.id.media_route_menu_item ) return true }
// Then override the onCreateOptionMenu() for each of your activities. // MyActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.main, menu); CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, R.id.media_route_menu_item); return true; }
次に、Activity
が継承されると、
FragmentActivity
,
追加できる
MediaRouteButton
追加できます。
// activity_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal" >
<androidx.mediarouter.app.MediaRouteButton
android:id="@+id/media_route_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:mediaRouteTypes="user"
android:visibility="gone" />
</LinearLayout>
<ph type="x-smartling-placeholder">// MyActivity.kt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_layout) mMediaRouteButton = findViewById<View>(R.id.media_route_button) as MediaRouteButton CastButtonFactory.setUpMediaRouteButton(applicationContext, mMediaRouteButton) mCastContext = CastContext.getSharedInstance(this) }
// MyActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_layout); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), mMediaRouteButton); mCastContext = CastContext.getSharedInstance(this); }
テーマを使用してキャスト アイコンの外観を設定するには、以下をご覧ください。 キャスト アイコンをカスタマイズします。
デバイスの検出を設定する
デバイスの検出は、
CastContext
。
CastContext を初期化するときに、送信側アプリは Web Receiver を
設定でき、オプションで名前空間フィルタをリクエストすることもできます。その場合は、
supportedNamespaces
インチ
CastOptions
。
CastContext
は MediaRouter
への参照を内部で保持しており、
次の条件下で検出プロセスが実行されます。
- デバイス検出のレイテンシのバランスを取るように設計されたアルゴリズムに基づいています。 自動的に検出が開始すると、 送信側のアプリがフォアグラウンドに入ります。
- キャスト ダイアログが開きます。
- Cast SDK がキャスト セッションの復元を試行しています。
検出プロセスは、キャスト ダイアログを閉じるか 送信側のアプリがバックグラウンドに移ります。
class CastOptionsProvider : OptionsProvider { companion object { const val CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace" } override fun getCastOptions(appContext: Context): CastOptions { val supportedNamespaces: MutableList<String> = ArrayList() supportedNamespaces.add(CUSTOM_NAMESPACE) return CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setSupportedNamespaces(supportedNamespaces) .build() } override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? { return null } }
class CastOptionsProvider implements OptionsProvider { public static final String CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace"; @Override public CastOptions getCastOptions(Context appContext) { List<String> supportedNamespaces = new ArrayList<>(); supportedNamespaces.add(CUSTOM_NAMESPACE); CastOptions castOptions = new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setSupportedNamespaces(supportedNamespaces) .build(); return castOptions; } @Override public List<SessionProvider> getAdditionalSessionProviders(Context context) { return null; } }
セッション管理の仕組み
Cast SDK には、キャスト セッションというコンセプト、 これは、デバイスへの接続、Web ブラウザの起動(またはウェブ レシーバアプリ、そのアプリへの接続、メディア コントロール チャネルの初期化。Web Receiver を確認する アプリケーション ライフサイクル ガイド をご覧ください。
セッションはクラスによって管理される
SessionManager
アプリがアクセスできるようにする
CastContext.getSessionManager()
。
個々のセッションは、クラスのサブクラスで表される
Session
。
たとえば
CastSession
キャスト デバイスによるセッションを表します。アプリは、現在アクティブな
セッションのキャスト方法
SessionManager.getCurrentCastSession()
。
アプリは
SessionManagerListener
クラスを使用してセッション イベント(作成、一時停止、再開、
解除されます。フレームワークは、
セッションがアクティブな間に異常/突然終了した。
セッションはユーザーの操作に応じて自動的に作成、破棄される
MediaRouter
ダイアログから選択します。
キャストの開始エラーを適切に把握するために、アプリは以下を使用できます。
CastContext#getCastReasonCodeForCastStatusCode(int)
セッション開始エラーを
CastReasonCodes
。
なお、一部のセッション開始エラー(CastReasonCodes#CAST_CANCELLED
など)があります。
エラーとして記録すべきではありません。
セッションの状態変化を認識する必要がある場合は、
SessionManagerListener
。この例では、Pod の空き時間をリッスンし、
Activity
内の CastSession
。
class MyActivity : Activity() { private var mCastSession: CastSession? = null private lateinit var mCastContext: CastContext private lateinit var mSessionManager: SessionManager private val mSessionManagerListener: SessionManagerListener<CastSession> = SessionManagerListenerImpl() private inner class SessionManagerListenerImpl : SessionManagerListener<CastSession?> { override fun onSessionStarting(session: CastSession?) {} override fun onSessionStarted(session: CastSession?, sessionId: String) { invalidateOptionsMenu() } override fun onSessionStartFailed(session: CastSession?, error: Int) { val castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error) // Handle error } override fun onSessionSuspended(session: CastSession?, reason Int) {} override fun onSessionResuming(session: CastSession?, sessionId: String) {} override fun onSessionResumed(session: CastSession?, wasSuspended: Boolean) { invalidateOptionsMenu() } override fun onSessionResumeFailed(session: CastSession?, error: Int) {} override fun onSessionEnding(session: CastSession?) {} override fun onSessionEnded(session: CastSession?, error: Int) { finish() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mCastContext = CastContext.getSharedInstance(this) mSessionManager = mCastContext.sessionManager mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java) } override fun onResume() { super.onResume() mCastSession = mSessionManager.currentCastSession } override fun onDestroy() { super.onDestroy() mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession::class.java) } }
public class MyActivity extends Activity { private CastContext mCastContext; private CastSession mCastSession; private SessionManager mSessionManager; private SessionManagerListener<CastSession> mSessionManagerListener = new SessionManagerListenerImpl(); private class SessionManagerListenerImpl implements SessionManagerListener<CastSession> { @Override public void onSessionStarting(CastSession session) {} @Override public void onSessionStarted(CastSession session, String sessionId) { invalidateOptionsMenu(); } @Override public void onSessionStartFailed(CastSession session, int error) { int castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error); // Handle error } @Override public void onSessionSuspended(CastSession session, int reason) {} @Override public void onSessionResuming(CastSession session, String sessionId) {} @Override public void onSessionResumed(CastSession session, boolean wasSuspended) { invalidateOptionsMenu(); } @Override public void onSessionResumeFailed(CastSession session, int error) {} @Override public void onSessionEnding(CastSession session) {} @Override public void onSessionEnded(CastSession session, int error) { finish(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCastContext = CastContext.getSharedInstance(this); mSessionManager = mCastContext.getSessionManager(); mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class); } @Override protected void onResume() { super.onResume(); mCastSession = mSessionManager.getCurrentCastSession(); } @Override protected void onDestroy() { super.onDestroy(); mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class); } }
ストリーミング転送
セッション状態の保持はストリーム転送の基礎であり、 音声コマンドや Google Home を使って、既存の音声ストリームや動画ストリームをデバイス間で移動できます。 アプリ、スマートディスプレイ。メディアの再生を別のデバイス(ソース)で停止し、別のデバイス(ソース)で続行する あります。最新のファームウェアを搭載したキャスト デバイスは、デバイスのソースまたは宛先として機能できます。 ストリーム転送
ストリーミングの転送または拡張中に新しい移行先デバイスを取得するには、次の操作を行います。
登録して
Cast.Listener
使用
CastSession#addCastListener
。
次に呼び出します
CastSession#getCastDevice()
onDeviceNameChanged
コールバック中に発生します。
詳しくは、 ウェブレシーバーでのストリーミング転送 をご覧ください。
自動再接続
このフレームワークでは
ReconnectionService
送信側のアプリでこれを有効にして、さまざまな細かな接続で再接続を
次のような特殊なケース:
- Wi-Fi の一時的な切断から復旧する
- デバイスのスリープからの復帰
- アプリをバックグラウンドから復元する
- アプリがクラッシュした場合を復元する
このサービスはデフォルトでオンになっていますが、オフにすることもできます。
CastOptions.Builder
。
自動マージの場合、このサービスをアプリのマニフェストに自動的にマージできます。 Gradle ファイルで有効にする必要があります。
メディア セッションがあるとフレームワークがサービスを開始し、それを停止します。 通知が送られる場合があります。
メディア コントロールの仕組み
キャスト フレームワークでは、
RemoteMediaPlayer
新しいクラスへの移行を予定しており、
RemoteMediaClient
、
同じ機能を複数のより便利な API で提供します。
GoogleApiClient を渡す必要がなくなります。
アプリが
CastSession
メディア名前空間をサポートする Web Receiver アプリの場合、
RemoteMediaClient
はフレームワークによって自動的に作成されます。アプリは
CastSession
の getRemoteMediaClient()
メソッドを呼び出してアクセスします。
作成します。
Web Receiver にリクエストを発行する RemoteMediaClient
のすべてのメソッドが
そのリクエストのトラッキングに使用できる PendingResult オブジェクトを返します。
RemoteMediaClient
のインスタンスは、
アプリの複数の部分、つまりアプリの内部コンポーネントが
たとえば、永続的なミニ コントローラや
通知サービス。
そのため、このインスタンスでは、インスタンスの複数の
RemoteMediaClient.Listener
。
メディア メタデータを設定する
「
MediaMetadata
クラスは、キャストするメディア アイテムに関する情報を表します。「
次の例では、映画の新しい MediaMetadata インスタンスを作成し、
title、サブタイトル、2 つの画像があります。
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE) movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle()) movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio()) movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(0)))) movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(1))))
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE); movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle()); movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio()); movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(0)))); movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(1))));
詳しくは、 画像の選択 メディア メタデータを含む画像の使用に関する推奨事項をご覧ください。
メディアの読み込み
アプリでは、次のコードに示すように、メディア アイテムを読み込むことができます。初回使用
MediaInfo.Builder
画像にメディア メタデータを
MediaInfo
作成します。こちらの
RemoteMediaClient
CastSession
を選択して、MediaInfo
を
RemoteMediaClient
。RemoteMediaClient
を使用した再生、一時停止など
Web Receiver で実行されているメディア プレーヤー アプリの制御
val mediaInfo = MediaInfo.Builder(mSelectedMedia.getUrl()) .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setContentType("videos/mp4") .setMetadata(movieMetadata) .setStreamDuration(mSelectedMedia.getDuration() * 1000) .build() val remoteMediaClient = mCastSession.getRemoteMediaClient() remoteMediaClient.load(MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build())
MediaInfo mediaInfo = new MediaInfo.Builder(mSelectedMedia.getUrl()) .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setContentType("videos/mp4") .setMetadata(movieMetadata) .setStreamDuration(mSelectedMedia.getDuration() * 1000) .build(); RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); remoteMediaClient.load(new MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build());
「 メディア トラックの使用。
4K 動画形式
メディアの動画形式を確認するには、
getVideoInfo()
現在のインスタンスを取得し、
VideoInfo
。
このインスタンスには、HDR TV 形式のタイプとディスプレイの高さが含まれています。
幅(ピクセル単位)を指定します。4K 形式のバリアントは定数で示される
HDR_TYPE_*
。
複数のデバイスへのリモコン通知
ユーザーのキャスト中は、同じネットワーク上の他の Android デバイスに 通知が表示され、ユーザーは再生を操作できるようになります。デバイスの所有者 このような通知を受信した場合は、[設定] でそのデバイスの通知を OFF にできます。 アプリ >Google Cast >リモコンの通知を表示する。 (通知には、設定アプリへのショートカットが含まれます)。詳しくは、 キャスト リモコンの通知
ミニ コントローラを追加
Cast デザイン チェックリスト 送信側アプリは、mini データ管理者 ユーザーが現在のコンテンツ ページから移動して 送信側のアプリの別の部分です。ミニ コントローラでリマインダーを 現在のキャスト セッションのユーザーに表示されます。ミニ コントローラをタップすると、 全画面表示のキャスト コントローラ ビューに戻ることができます。
フレームワークには、MiniControllerFragment というカスタムビューが用意されています。 各アクティビティのレイアウト ファイルの一番下に、 操作できます。
<fragment
android:id="@+id/castMiniController"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="gone"
class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment" />
送信側アプリが動画や音声のライブ配信を再生しているときに、SDK は 再生/一時停止ボタンの代わりに再生/停止ボタンを自動的に表示する 確認できます。
このカスタムビューのタイトルとサブタイトルのテキストの外観を設定するには、 ボタンを選択するには、 ミニ コントローラをカスタマイズします。
拡張コントローラを追加
Google Cast デザイン チェックリストでは、送信側アプリで拡張 データ管理者 クリックします。拡張コントローラは全画面表示で ミニコントローラです
Cast SDK には、拡張コントローラ用のウィジェットが用意されています。
ExpandedControllerActivity
。
これは、キャスト アイコンを追加するためにサブクラス化する必要がある抽象クラスです。
まず、拡張コントローラ用の新しいメニュー リソース ファイルを作成します。 キャスト アイコンを変更します。
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
</menu>
ExpandedControllerActivity
を拡張する新しいクラスを作成します。
class ExpandedControlsActivity : ExpandedControllerActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.expanded_controller, menu) CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item) return true } }
public class ExpandedControlsActivity extends ExpandedControllerActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.expanded_controller, menu); CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item); return true; } }
次に、アプリ マニフェストの application
タグ内で新しいアクティビティを宣言します。
<application>
...
<activity
android:name=".expandedcontrols.ExpandedControlsActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.CastVideosDark"
android:screenOrientation="portrait"
android:parentActivityName="com.google.sample.cast.refplayer.VideoBrowserActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
...
</application>
CastOptionsProvider
を編集して、NotificationOptions
と
CastMediaOptions
を使用して、ターゲット アクティビティを新しいアクティビティに設定します。
override fun getCastOptions(context: Context): CastOptions? { val notificationOptions = NotificationOptions.Builder() .setTargetActivityClassName(ExpandedControlsActivity::class.java.name) .build() val mediaOptions = CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name) .build() return CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build() }
public CastOptions getCastOptions(Context context) { NotificationOptions notificationOptions = new NotificationOptions.Builder() .setTargetActivityClassName(ExpandedControlsActivity.class.getName()) .build(); CastMediaOptions mediaOptions = new CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .setExpandedControllerActivityClassName(ExpandedControlsActivity.class.getName()) .build(); return new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build(); }
LocalPlayerActivity
loadRemoteMedia
メソッドを更新して、
リモート メディアが読み込まれたときの新しいアクティビティ:
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) { val remoteMediaClient = mCastSession?.remoteMediaClient ?: return remoteMediaClient.registerCallback(object : RemoteMediaClient.Callback() { override fun onStatusUpdated() { val intent = Intent(this@LocalPlayerActivity, ExpandedControlsActivity::class.java) startActivity(intent) remoteMediaClient.unregisterCallback(this) } }) remoteMediaClient.load( MediaLoadRequestData.Builder() .setMediaInfo(mSelectedMedia) .setAutoplay(autoPlay) .setCurrentTime(position.toLong()).build() ) }
private void loadRemoteMedia(int position, boolean autoPlay) { if (mCastSession == null) { return; } final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); if (remoteMediaClient == null) { return; } remoteMediaClient.registerCallback(new RemoteMediaClient.Callback() { @Override public void onStatusUpdated() { Intent intent = new Intent(LocalPlayerActivity.this, ExpandedControlsActivity.class); startActivity(intent); remoteMediaClient.unregisterCallback(this); } }); remoteMediaClient.load(new MediaLoadRequestData.Builder() .setMediaInfo(mSelectedMedia) .setAutoplay(autoPlay) .setCurrentTime(position).build()); }
送信側アプリが動画や音声のライブ配信を再生しているときに、SDK は 再生/一時停止ボタンの代わりに再生/停止ボタンを自動的に表示する 表示されます
テーマを使用して外観を設定するには、表示するボタンを選択します。 カスタム ボタンを追加するには、 拡張コントローラのカスタマイズ
音量調節
フレームワークは送信側アプリの音量を自動的に管理します。フレームワーク は送信者アプリとウェブ受信者アプリを自動的に同期して、 UI では常に、Web Receiver が指定した音量が報告されます。
物理ボタンの音量調節
Android では、送信側のデバイスの物理ボタンを使って を使用するデバイスでは、ウェブ レシーバーでのキャスト セッションの音量がデフォルトで低下します。 Jelly Bean 以降。
Jelly Bean 以前の物理ボタンの音量調節
物理的な音量キーを使用して、Web Receiver デバイスの音量を調整するには
Jelly Bean よりも古い Android デバイスでは、送信側アプリがオーバーライドする必要があります
dispatchKeyEvent
できます。また、
CastContext.onDispatchVolumeKeyEventBeforeJellyBean()
:
class MyActivity : FragmentActivity() { override fun dispatchKeyEvent(event: KeyEvent): Boolean { return (CastContext.getSharedInstance(this) .onDispatchVolumeKeyEventBeforeJellyBean(event) || super.dispatchKeyEvent(event)) } }
class MyActivity extends FragmentActivity { @Override public boolean dispatchKeyEvent(KeyEvent event) { return CastContext.getSharedInstance(this) .onDispatchVolumeKeyEventBeforeJellyBean(event) || super.dispatchKeyEvent(event); } }
通知とロック画面にメディア コントロールを追加する
Google Cast デザイン チェックリスト(Android のみ)では、送信側アプリで次の操作を行う必要があります。
メディア コントロールを
通知
ロックの中
画面、
センダーがキャストしているが、送信側アプリにフォーカスがない場合。「
フレームワークは、
MediaNotificationService
および
MediaIntentReceiver
送信側アプリで通知とロックのメディア コントロールを作成できます
表示されます。
MediaNotificationService
は送信者がキャストしているときに実行され、
画像サムネイルと現在のキャストに関する情報を含む通知
要素、再生/一時停止ボタン、停止ボタンがあります。
MediaIntentReceiver
は、ユーザーによる操作を処理する BroadcastReceiver
です。
表示されます。
アプリはロック画面から通知やメディア コントロールを設定できます。
NotificationOptions
。
アプリでは、通知に表示するコントロール ボタンを設定できます。
ユーザーが通知をタップしたときに開く Activity
。IF アクション
指定されていない場合、デフォルト値
MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK
、
MediaIntentReceiver.ACTION_STOP_CASTING
が使用されます。
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting". val buttonActions: MutableList<String> = ArrayList() buttonActions.add(MediaIntentReceiver.ACTION_REWIND) buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK) buttonActions.add(MediaIntentReceiver.ACTION_FORWARD) buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING) // Showing "play/pause" and "stop casting" in the compat view of the notification. val compatButtonActionsIndices = intArrayOf(1, 3) // Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds. // Tapping on the notification opens an Activity with class VideoBrowserActivity. val notificationOptions = NotificationOptions.Builder() .setActions(buttonActions, compatButtonActionsIndices) .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS) .setTargetActivityClassName(VideoBrowserActivity::class.java.name) .build()
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting". List<String> buttonActions = new ArrayList<>(); buttonActions.add(MediaIntentReceiver.ACTION_REWIND); buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK); buttonActions.add(MediaIntentReceiver.ACTION_FORWARD); buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING); // Showing "play/pause" and "stop casting" in the compat view of the notification. int[] compatButtonActionsIndices = new int[]{1, 3}; // Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds. // Tapping on the notification opens an Activity with class VideoBrowserActivity. NotificationOptions notificationOptions = new NotificationOptions.Builder() .setActions(buttonActions, compatButtonActionsIndices) .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS) .setTargetActivityClassName(VideoBrowserActivity.class.getName()) .build();
通知とロック画面でのメディア コントロールの表示は、
無効にすることもできます。その場合は、
setNotificationOptions
に null を含む
CastMediaOptions.Builder
。
現在、ロック画面機能は、通知が
オンになっています。
// ... continue with the NotificationOptions built above val mediaOptions = CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .build() val castOptions: CastOptions = Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build()
// ... continue with the NotificationOptions built above CastMediaOptions mediaOptions = new CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .build(); CastOptions castOptions = new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build();
送信側アプリが動画や音声のライブ配信を再生しているときに、SDK は 再生/一時停止ボタンの代わりに再生/停止ボタンを自動的に表示する ロック画面のコントロールには表示されない。
注: Lollipop より前のデバイスでロック画面コントロールを表示するには、
RemoteMediaClient
が音声フォーカスを自動的にリクエストします。
エラーを処理する
送信側アプリですべてのエラー コールバックを処理し、 Cast のライフサイクルの各ステージで最適なレスポンスを判断できます。アプリは アプリケーションへの接続を切断したり、 ウェブレシーバー。