Android アプリにキャストを統合する

このデベロッパー ガイドでは、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 です。 キャスト セッションの開始時にウェブ レシーバー アプリを起動できます。 開始しました。

Kotlin
で確認できます。
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
    }
}
Java
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() エラーの発生時に遅延初期化される が呼び出されます。

Kotlin
で確認できます。
class MyActivity : FragmentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val castContext = CastContext.getSharedInstance(this)
    }
}
Java
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">
</ph> <ph type="x-smartling-placeholder">
</ph>
Kotlin
で確認できます。
// 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
}
Java
// 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">
</ph> <ph type="x-smartling-placeholder">
</ph>
Kotlin
で確認できます。
// 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)
}
Java
// 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 インチ CastOptionsCastContextMediaRouter への参照を内部で保持しており、 次の条件下で検出プロセスが実行されます。

  • デバイス検出のレイテンシのバランスを取るように設計されたアルゴリズムに基づいています。 自動的に検出が開始すると、 送信側のアプリがフォアグラウンドに入ります。
  • キャスト ダイアログが開きます。
  • Cast SDK がキャスト セッションの復元を試行しています。

検出プロセスは、キャスト ダイアログを閉じるか 送信側のアプリがバックグラウンドに移ります。

Kotlin
で確認できます。
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
    }
}
Java
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

Kotlin
で確認できます。
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
    }

    override fun onResume() {
        super.onResume()
        mCastSession = mSessionManager.currentCastSession
        mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java)
    }

    override fun onPause() {
        super.onPause()
        mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession::class.java)
        mCastSession = null
    }
}
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();
    }
    @Override
    protected void onResume() {
        super.onResume();
        mCastSession = mSessionManager.getCurrentCastSession();
        mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class);
    }
    @Override
    protected void onPause() {
        super.onPause();
        mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class);
        mCastSession = null;
    }
}

ストリーミング転送

セッション状態の保持はストリーム転送の基礎であり、 音声コマンドや Google Home を使って、既存の音声ストリームや動画ストリームをデバイス間で移動できます。 アプリ、スマートディスプレイ。メディアの再生を別のデバイス(ソース)で停止し、別のデバイス(ソース)で続行する あります。最新のファームウェアを搭載したキャスト デバイスは、デバイスのソースまたは宛先として機能できます。 ストリーム転送

ストリーミングの転送または拡張中に新しい移行先デバイスを取得するには、次の操作を行います。 登録して Cast.Listener 使用 CastSession#addCastListener。 次に呼び出します CastSession#getCastDevice() onDeviceNameChanged コールバック中に発生します。

詳しくは、 ウェブレシーバーでのストリーミング転送 をご覧ください。

自動再接続

このフレームワークでは ReconnectionService 送信側のアプリでこれを有効にして、さまざまな細かな接続で再接続を 次のような特殊なケース:

  • Wi-Fi の一時的な切断から復旧する
  • デバイスのスリープからの復帰
  • アプリをバックグラウンドから復元する
  • アプリがクラッシュした場合を復元する

このサービスはデフォルトでオンになっていますが、オフにすることもできます。 CastOptions.Builder

自動マージの場合、このサービスをアプリのマニフェストに自動的にマージできます。 Gradle ファイルで有効にする必要があります。

メディア セッションがあるとフレームワークがサービスを開始し、それを停止します。 通知が送られる場合があります。

メディア コントロールの仕組み

キャスト フレームワークでは、 RemoteMediaPlayer 新しいクラスへの移行を予定しており、 RemoteMediaClient、 同じ機能を複数のより便利な API で提供します。 GoogleApiClient を渡す必要がなくなります。

アプリが CastSession メディア名前空間をサポートする Web Receiver アプリの場合、 RemoteMediaClient はフレームワークによって自動的に作成されます。アプリは CastSessiongetRemoteMediaClient() メソッドを呼び出してアクセスします。 作成します。

Web Receiver にリクエストを発行する RemoteMediaClient のすべてのメソッドが そのリクエストのトラッキングに使用できる PendingResult オブジェクトを返します。

RemoteMediaClient のインスタンスは、 アプリの複数の部分、つまりアプリの内部コンポーネントが たとえば、永続的なミニ コントローラ通知サービス。 そのため、このインスタンスでは、インスタンスの複数の RemoteMediaClient.Listener

メディア メタデータを設定する

MediaMetadata クラスは、キャストするメディア アイテムに関する情報を表します。「 次の例では、映画の新しい MediaMetadata インスタンスを作成し、 title、サブタイトル、2 つの画像があります。

Kotlin
で確認できます。
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))))
Java
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 を選択して、MediaInfoRemoteMediaClientRemoteMediaClient を使用した再生、一時停止など Web Receiver で実行されているメディア プレーヤー アプリの制御

Kotlin
で確認できます。
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())
Java
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 を拡張する新しいクラスを作成します。

Kotlin
で確認できます。
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
    }
}
Java
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 を編集して、NotificationOptionsCastMediaOptions を使用して、ターゲット アクティビティを新しいアクティビティに設定します。

Kotlin
で確認できます。
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()
}
Java
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 メソッドを更新して、 リモート メディアが読み込まれたときの新しいアクティビティ:

Kotlin
で確認できます。
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()
    )
}
Java
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():

Kotlin
で確認できます。
class MyActivity : FragmentActivity() {
    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        return (CastContext.getSharedInstance(this)
            .onDispatchVolumeKeyEventBeforeJellyBean(event)
                || super.dispatchKeyEvent(event))
    }
}
Java
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_PLAYBACKMediaIntentReceiver.ACTION_STOP_CASTING が使用されます。

Kotlin
で確認できます。
// 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()
Java
// 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。 現在、ロック画面機能は、通知が オンになっています。

Kotlin
で確認できます。
// ... 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()
Java
// ... 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 のライフサイクルの各ステージで最適なレスポンスを判断できます。アプリは アプリケーションへの接続を切断したり、 ウェブレシーバー。