このページには、コード スニペットと利用可能な機能の説明が掲載されています。 Android TV Receiver アプリをカスタマイズします。
ライブラリの構成
Android TV アプリで Cast Connect API を利用できるようにするには:
<ph type="x-smartling-placeholder">-
アプリ モジュール ディレクトリ内の
build.gradle
ファイルを開きます。 -
リストされた
repositories
にgoogle()
が含まれていることを確認します。repositories { google() }
-
アプリの対象デバイスタイプに応じて、最新バージョンを追加してください
依存関係に追加します。
<ph type="x-smartling-placeholder">
- </ph>
-
Android Receiver アプリの場合:
dependencies { implementation 'com.google.android.gms:play-services-cast-tv:21.1.0' implementation 'com.google.android.gms:play-services-cast:21.5.0' }
-
Android の送信者アプリの場合:
dependencies { implementation 'com.google.android.gms:play-services-cast:21.1.0' implementation 'com.google.android.gms:play-services-cast-framework:21.5.0' }
-
Android Receiver アプリの場合:
-
変更を保存して [
Sync Project with Gradle Files
] をクリックします。 をクリックします。
-
Podfile
がgoogle-cast-sdk
4.8.3 をターゲットにしていることを確認してください 以上 -
iOS 14 以降がターゲットであること。リリースノートをご覧ください。
をご覧ください。
platform: ios, '14' def target_pods pod 'google-cast-sdk', '~>4.8.3' end
- Chromium ブラウザ バージョン M87 以降が必要です。
-
Web Sender API ライブラリをプロジェクトに追加する
<script src="//www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
AndroidX の要件
新しいバージョンの Google Play 開発者サービスを使用するには、アプリを更新する必要があります
androidx
Namespace。手順については、
AndroidX への移行をご覧ください。
Android TV アプリ - 前提条件
Android TV アプリで Cast Connect をサポートするには、 イベントをサポートしています。メディア セッションによって提供されるデータ 再生状態などの基本情報を 確認できます。メディア セッションは Cast Connect ライブラリによっても使用されます を使用して、送信者から特定のメッセージ(一時停止など)を受け取ったことを通知します。
メディア セッションとメディア セッションを初期化する方法について詳しくは、 詳しくは、 メディア セッション ガイドをご覧ください。
メディア セッションのライフサイクル
再生の開始時にアプリでメディア セッションを作成し、再生が開始されたらメディア セッションを解放する必要があります。 制御できなくなります。たとえば、アプリが動画アプリの場合、 は、ユーザーが再生アクティビティを終了したときにセッションを解放する必要があります。 [戻る] を選択して他のコンテンツをブラウジングしたり、アプリをバックグラウンドで実行したりできます。お使いの アプリが音楽アプリの場合は、アプリで再生されなくなったらリリースする必要があります。 できます。
セッションのステータスを更新しています
メディア セッションのデータは、 表示されます。たとえば、再生が一時停止している場合は、再生を更新して サポートされているアクションを定義します。次の表に、 常に最新の状態に保つ責任はお客様にあります。
MediaMetadataCompat
メタデータ フィールド | 説明 |
---|---|
METADATA_KEY_TITLE (必須) | メディアのタイトル。 |
METADATA_KEY_DISPLAY_SUBTITLE | サブタイトル。 |
METADATA_KEY_DISPLAY_ICON_URI | アイコンの URL。 |
METADATA_KEY_DURATION (必須) | メディアの時間。 |
METADATA_KEY_MEDIA_URI | Content ID。 |
METADATA_KEY_ARTIST | アーティスト。 |
METADATA_KEY_ALBUM | アルバム。 |
PlaybackStateCompat
必須のメソッド | 説明 |
---|---|
setActions() | サポートされているメディア コマンドを設定します。 |
setState() | 再生状態と現在の位置を設定します。 |
MediaSessionCompat
必須のメソッド | 説明 |
---|---|
setRepeatMode() | リピートモードを設定します。 |
setShuffleMode() | シャッフル モードを設定します。 |
setMetadata() | メディアのメタデータを設定します。 |
setPlaybackState() | 再生状態を設定します。 |
private fun updateMediaSession() { val metadata = MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title") .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "subtitle") .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, mMovie.getCardImageUrl()) .build() val playbackState = PlaybackStateCompat.Builder() .setState( PlaybackStateCompat.STATE_PLAYING, player.getPosition(), player.getPlaybackSpeed(), System.currentTimeMillis() ) .build() mediaSession.setMetadata(metadata) mediaSession.setPlaybackState(playbackState) }
private void updateMediaSession() { MediaMetadataCompat metadata = new MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title") .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "subtitle") .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI,mMovie.getCardImageUrl()) .build(); PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder() .setState( PlaybackStateCompat.STATE_PLAYING, player.getPosition(), player.getPlaybackSpeed(), System.currentTimeMillis()) .build(); mediaSession.setMetadata(metadata); mediaSession.setPlaybackState(playbackState); }
トランスポート コントロールの処理
アプリにメディア セッション トランスポート コントロール コールバックを実装する必要があります。「 次の表に、処理する必要があるトランスポート コントロールのアクションを示します。
MediaSessionCompat.Callback
操作 | 説明 |
---|---|
onPlay() | 再開 |
onPause() | 一時停止 |
onSeekTo() | 特定の位置に移動 |
onStop() | 現在のメディアを停止する |
class MyMediaSessionCallback : MediaSessionCompat.Callback() { override fun onPause() { // Pause the player and update the play state. ... } override fun onPlay() { // Resume the player and update the play state. ... } override fun onSeekTo (long pos) { // Seek and update the play state. ... } ... } mediaSession.setCallback( MyMediaSessionCallback() );
public MyMediaSessionCallback extends MediaSessionCompat.Callback { public void onPause() { // Pause the player and update the play state. ... } public void onPlay() { // Resume the player and update the play state. ... } public void onSeekTo (long pos) { // Seek and update the play state. ... } ... } mediaSession.setCallback(new MyMediaSessionCallback());
キャスト サポートの設定
送信側アプリからリリース リクエストが送信されると、インテントが作成される
関連付けられていますアプリケーションの処理で
新しい Pod を作成する
CastReceiverContext
オブジェクトを宣言します。CastReceiverContext
オブジェクトは必須です
を使用して、TV アプリの実行中に Cast を操作できます。このオブジェクトを使用すると、テレビの
アプリで、接続されているすべての送信者からのキャスト メディア メッセージを受け付けることができます。
Android TV のセットアップ
起動インテント フィルタの追加
起動を処理するアクティビティに新しいインテント フィルタを追加する インテントを受信できます。
<activity android:name="com.example.activity">
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
レシーバ オプション プロバイダを指定する
新しい P-MAX キャンペーンを
ReceiverOptionsProvider
提供する
CastReceiverOptions
:
class MyReceiverOptionsProvider : ReceiverOptionsProvider { override fun getOptions(context: Context?): CastReceiverOptions { return CastReceiverOptions.Builder(context) .setStatusText("My App") .build() } }
public class MyReceiverOptionsProvider implements ReceiverOptionsProvider { @Override public CastReceiverOptions getOptions(Context context) { return new CastReceiverOptions.Builder(context) .setStatusText("My App") .build(); } }
次に、AndroidManifest
でオプション プロバイダを指定します。
<meta-data
android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.example.mysimpleatvapplication.MyReceiverOptionsProvider" />
ReceiverOptionsProvider
は、次の場合に CastReceiverOptions
を指定するために使用されます。
CastReceiverContext
が初期化されています。
キャスト レシーバーのコンテキスト
初期化
CastReceiverContext
作成すると次のような処理が行われます。
override fun onCreate() { CastReceiverContext.initInstance(this) ... }
@Override public void onCreate() { CastReceiverContext.initInstance(this); ... }
アプリがフォアグラウンドに移行したら、CastReceiverContext
を開始します。
CastReceiverContext.getInstance().start()
CastReceiverContext.getInstance().start();
発信
stop()
日付
CastReceiverContext
動画アプリやサポート対象外のアプリでバックグラウンドに移行した後
バックグラウンド再生:
// Player has stopped. CastReceiverContext.getInstance().stop()
// Player has stopped. CastReceiverContext.getInstance().stop();
また、アプリがバックグラウンドでの再生をサポートしている場合は、stop()
を呼び出します。
CastReceiverContext
に出力されます。
次のように LifecycleObserver を
androidx.lifecycle
通話を管理するライブラリ
CastReceiverContext.start()
および
CastReceiverContext.stop()
、
特にネイティブアプリに
複数のアクティビティがある場合はなおさらですこれにより
異なるアクティビティから start()
と stop()
を呼び出す場合の条件。
// Create a LifecycleObserver class. class MyLifecycleObserver : DefaultLifecycleObserver { override fun onStart(owner: LifecycleOwner) { // App prepares to enter foreground. CastReceiverContext.getInstance().start() } override fun onStop(owner: LifecycleOwner) { // App has moved to the background or has terminated. CastReceiverContext.getInstance().stop() } } // Add the observer when your application is being created. class MyApplication : Application() { fun onCreate() { super.onCreate() // Initialize CastReceiverContext. CastReceiverContext.initInstance(this /* android.content.Context */) // Register LifecycleObserver ProcessLifecycleOwner.get().lifecycle.addObserver( MyLifecycleObserver()) } }
// Create a LifecycleObserver class. public class MyLifecycleObserver implements DefaultLifecycleObserver { @Override public void onStart(LifecycleOwner owner) { // App prepares to enter foreground. CastReceiverContext.getInstance().start(); } @Override public void onStop(LifecycleOwner owner) { // App has moved to the background or has terminated. CastReceiverContext.getInstance().stop(); } } // Add the observer when your application is being created. public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); // Initialize CastReceiverContext. CastReceiverContext.initInstance(this /* android.content.Context */); // Register LifecycleObserver ProcessLifecycleOwner.get().getLifecycle().addObserver( new MyLifecycleObserver()); } }
// In AndroidManifest.xml set MyApplication as the application class
<application
...
android:name=".MyApplication">
MediaSession を MediaManager に接続する
新しい
MediaSession
現在の MediaSession
トークンを
CastReceiverContext
これにより、コマンドの送信先とメディアの再生状態の取得先がわかります。
val mediaManager: MediaManager = receiverContext.getMediaManager() mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken())
MediaManager mediaManager = receiverContext.getMediaManager(); mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken());
非アクティブな再生が原因で MediaSession
を解放する場合は、
null トークンがオン
MediaManager
:
myPlayer.stop() mediaSession.release() mediaManager.setSessionCompatToken(null)
myPlayer.stop(); mediaSession.release(); mediaManager.setSessionCompatToken(null);
アプリがバックグラウンドで実行されているときのメディア再生をサポートしている場合は、
通話
CastReceiverContext.stop()
バックグラウンドに移動されるときは、必ず
バックグラウンドにあり、メディアを再生しなくなっています。例:
class MyLifecycleObserver : DefaultLifecycleObserver { ... // App has moved to the background. override fun onPause(owner: LifecycleOwner) { mIsBackground = true myStopCastReceiverContextIfNeeded() } } // Stop playback on the player. private fun myStopPlayback() { myPlayer.stop() myStopCastReceiverContextIfNeeded() } // Stop the CastReceiverContext when both the player has // stopped and the app has moved to the background. private fun myStopCastReceiverContextIfNeeded() { if (mIsBackground && myPlayer.isStopped()) { CastReceiverContext.getInstance().stop() } }
public class MyLifecycleObserver implements DefaultLifecycleObserver { ... // App has moved to the background. @Override public void onPause(LifecycleOwner owner) { mIsBackground = true; myStopCastReceiverContextIfNeeded(); } } // Stop playback on the player. private void myStopPlayback() { myPlayer.stop(); myStopCastReceiverContextIfNeeded(); } // Stop the CastReceiverContext when both the player has // stopped and the app has moved to the background. private void myStopCastReceiverContextIfNeeded() { if (mIsBackground && myPlayer.isStopped()) { CastReceiverContext.getInstance().stop(); } }
Cast Connect で Exoplayer を使用する
以下を使用している場合:
Exoplayer
を使用している場合は、
MediaSessionConnector
セッションと、関連するすべての情報(セッション、
再生状態を手動でトラッキングする代わりに、
MediaSessionConnector.MediaButtonEventHandler
これを使用して MediaButton イベントを処理するために、
setMediaButtonEventHandler(MediaButtonEventHandler)
それ以外の処理は
MediaSessionCompat.Callback
できます。
統合するには
MediaSessionConnector
で、プレーヤーのアクティビティ クラスまたは
メディア セッションの管理:
class PlayerActivity : Activity() { private var mMediaSession: MediaSessionCompat? = null private var mMediaSessionConnector: MediaSessionConnector? = null private var mMediaManager: MediaManager? = null override fun onCreate(savedInstanceState: Bundle?) { ... mMediaSession = MediaSessionCompat(this, LOG_TAG) mMediaSessionConnector = MediaSessionConnector(mMediaSession!!) ... } override fun onStart() { ... mMediaManager = receiverContext.getMediaManager() mMediaManager!!.setSessionCompatToken(currentMediaSession.getSessionToken()) mMediaSessionConnector!!.setPlayer(mExoPlayer) mMediaSessionConnector!!.setMediaMetadataProvider(mMediaMetadataProvider) mMediaSession!!.isActive = true ... } override fun onStop() { ... mMediaSessionConnector!!.setPlayer(null) mMediaSession!!.release() mMediaManager!!.setSessionCompatToken(null) ... } }
public class PlayerActivity extends Activity { private MediaSessionCompat mMediaSession; private MediaSessionConnector mMediaSessionConnector; private MediaManager mMediaManager; @Override protected void onCreate(Bundle savedInstanceState) { ... mMediaSession = new MediaSessionCompat(this, LOG_TAG); mMediaSessionConnector = new MediaSessionConnector(mMediaSession); ... } @Override protected void onStart() { ... mMediaManager = receiverContext.getMediaManager(); mMediaManager.setSessionCompatToken(currentMediaSession.getSessionToken()); mMediaSessionConnector.setPlayer(mExoPlayer); mMediaSessionConnector.setMediaMetadataProvider(mMediaMetadataProvider); mMediaSession.setActive(true); ... } @Override protected void onStop() { ... mMediaSessionConnector.setPlayer(null); mMediaSession.release(); mMediaManager.setSessionCompatToken(null); ... } }
送信側アプリの設定
Cast Connect のサポートを有効にする
Cast Connect のサポートを有効にして送信側アプリを更新したら、
その準備状況を示すために
androidReceiverCompatible
フラグがオン
LaunchOptions
true に設定します。
play-services-cast-framework
のバージョンが必要
19.0.0
以上。
androidReceiverCompatible
フラグが設定されていると、
LaunchOptions
(CastOptions
の一部):
class CastOptionsProvider : OptionsProvider { override fun getCastOptions(context: Context?): CastOptions { val launchOptions: LaunchOptions = Builder() .setAndroidReceiverCompatible(true) .build() return CastOptions.Builder() .setLaunchOptions(launchOptions) ... .build() } }
public class CastOptionsProvider implements OptionsProvider { @Override public CastOptions getCastOptions(Context context) { LaunchOptions launchOptions = new LaunchOptions.Builder() .setAndroidReceiverCompatible(true) .build(); return new CastOptions.Builder() .setLaunchOptions(launchOptions) ... .build(); } }
google-cast-sdk
バージョン v4.4.8
または
高くなります。
androidReceiverCompatible
フラグが設定されていると、
GCKLaunchOptions
(
GCKCastOptions
):
let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: kReceiverAppID)) ... let launchOptions = GCKLaunchOptions() launchOptions.androidReceiverCompatible = true options.launchOptions = launchOptions GCKCastContext.setSharedInstanceWith(options)
Chromium ブラウザのバージョンが必要です
M87
以降。
const context = cast.framework.CastContext.getInstance(); const castOptions = new cast.framework.CastOptions(); castOptions.receiverApplicationId = kReceiverAppID; castOptions.androidReceiverCompatible = true; context.setOptions(castOptions);
Cast Developer Console のセットアップ
Android TV アプリを設定する
Android TV アプリのパッケージ名を Cast デベロッパー コンソール キャストアプリ ID と関連付けます。
デベロッパー デバイスを登録する
使用する Android TV デバイスのシリアル番号を登録する 開発環境では、 Cast デベロッパー コンソール
登録しない場合、Cast Connect は セキュリティ上の理由により Google Play ストアにアクセスすることはできません。
Cast デバイスまたは Android TV デバイスを Cast に登録する方法の詳細 登録ページをご覧ください。
メディアの読み込み
Android TV アプリにディープリンクのサポートをすでに実装している場合は、次の手順を実施します。 Android TV マニフェストに同様の定義が設定されているはずです。
<activity android:name="com.example.activity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="https"/>
<data android:host="www.example.com"/>
<data android:pathPattern=".*"/>
</intent-filter>
</activity>
送信者のエンティティ別に読み込む
送信者では、メディアに entity
を設定することでディープリンクを渡すことができます。
次の読み込みリクエストに関する情報を提供します。
val mediaToLoad = MediaInfo.Builder("some-id") .setEntity("https://example.com/watch/some-id") ... .build() val loadRequest = MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") ... .build() remoteMediaClient.load(loadRequest)
MediaInfo mediaToLoad = new MediaInfo.Builder("some-id") .setEntity("https://example.com/watch/some-id") ... .build(); MediaLoadRequestData loadRequest = new MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") ... .build(); remoteMediaClient.load(loadRequest);
let mediaInfoBuilder = GCKMediaInformationBuilder(entity: "https://example.com/watch/some-id") ... mediaInformation = mediaInfoBuilder.build() let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder() mediaLoadRequestDataBuilder.mediaInformation = mediaInformation mediaLoadRequestDataBuilder.credentials = "user-credentials" ... let mediaLoadRequestData = mediaLoadRequestDataBuilder.build() remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
Chromium ブラウザのバージョンが必要です
M87
以降。
let mediaInfo = new chrome.cast.media.MediaInfo('some-id"', 'video/mp4'); mediaInfo.entity = 'https://example.com/watch/some-id'; ... let request = new chrome.cast.media.LoadRequest(mediaInfo); request.credentials = 'user-credentials'; ... cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request);
読み込みコマンドは、ディープリンクとパッケージ名を含むインテントを介して送信されます。 定義した値を使用します。
送信者に ATV 認証情報を設定する
Web Receiver アプリと Android TV アプリは、
ディープリンクと credentials
(認証を処理する場合など)
違います)。これに対処するために、VM の
Android TV の場合: entity
、credentials
:
val mediaToLoad = MediaInfo.Builder("some-id") .setEntity("https://example.com/watch/some-id") .setAtvEntity("myscheme://example.com/atv/some-id") ... .build() val loadRequest = MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") .setAtvCredentials("atv-user-credentials") ... .build() remoteMediaClient.load(loadRequest)
MediaInfo mediaToLoad = new MediaInfo.Builder("some-id") .setEntity("https://example.com/watch/some-id") .setAtvEntity("myscheme://example.com/atv/some-id") ... .build(); MediaLoadRequestData loadRequest = new MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") .setAtvCredentials("atv-user-credentials") ... .build(); remoteMediaClient.load(loadRequest);
let mediaInfoBuilder = GCKMediaInformationBuilder(entity: "https://example.com/watch/some-id") mediaInfoBuilder.atvEntity = "myscheme://example.com/atv/some-id" ... mediaInformation = mediaInfoBuilder.build() let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder() mediaLoadRequestDataBuilder.mediaInformation = mediaInformation mediaLoadRequestDataBuilder.credentials = "user-credentials" mediaLoadRequestDataBuilder.atvCredentials = "atv-user-credentials" ... let mediaLoadRequestData = mediaLoadRequestDataBuilder.build() remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
Chromium ブラウザのバージョンが必要です
M87
以降。
let mediaInfo = new chrome.cast.media.MediaInfo('some-id"', 'video/mp4'); mediaInfo.entity = 'https://example.com/watch/some-id'; mediaInfo.atvEntity = 'myscheme://example.com/atv/some-id'; ... let request = new chrome.cast.media.LoadRequest(mediaInfo); request.credentials = 'user-credentials'; request.atvCredentials = 'atv-user-credentials'; ... cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request);
Web Receiver アプリが起動されると、アプリは entity
と credentials
を使用します。
呼び出すことができます。ただし、Android TV アプリが起動されると、SDK は
entity
と credentials
を atvEntity
と atvCredentials
で
(指定された場合)。
Content ID または MediaQueueData による読み込み
entity
または atvEntity
を使用しておらず、Content ID または
メディア情報にコンテンツの URL を指定するか、より詳細なメディア読み込みを使用します。
[Request Data] で、次の定義済みのインテント フィルタを
Android TV アプリ:
<activity android:name="com.example.activity">
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.LOAD"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
送信者側では、エンティティごとの読み込みと同様に、次の操作を行います。
コンテンツ情報を使用して読み込みリクエストを作成し、load()
を呼び出すことができます。
val mediaToLoad = MediaInfo.Builder("some-id").build() val loadRequest = MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") ... .build() remoteMediaClient.load(loadRequest)
MediaInfo mediaToLoad = new MediaInfo.Builder("some-id").build(); MediaLoadRequestData loadRequest = new MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") ... .build(); remoteMediaClient.load(loadRequest);
let mediaInfoBuilder = GCKMediaInformationBuilder(contentId: "some-id") ... mediaInformation = mediaInfoBuilder.build() let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder() mediaLoadRequestDataBuilder.mediaInformation = mediaInformation mediaLoadRequestDataBuilder.credentials = "user-credentials" ... let mediaLoadRequestData = mediaLoadRequestDataBuilder.build() remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
Chromium ブラウザのバージョンが必要です
M87
以降。
let mediaInfo = new chrome.cast.media.MediaInfo('some-id"', 'video/mp4'); ... let request = new chrome.cast.media.LoadRequest(mediaInfo); ... cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request);
読み込みリクエストの処理
アクティビティでは、これらの読み込みリクエストを処理するために、 次のように指定します。
class MyActivity : Activity() { override fun onStart() { super.onStart() val mediaManager = CastReceiverContext.getInstance().getMediaManager() // Pass the intent to the SDK. You can also do this in onCreate(). if (mediaManager.onNewIntent(intent)) { // If the SDK recognizes the intent, you should early return. return } // If the SDK doesn't recognize the intent, you can handle the intent with // your own logic. ... } // For some cases, a new load intent triggers onNewIntent() instead of // onStart(). override fun onNewIntent(intent: Intent) { val mediaManager = CastReceiverContext.getInstance().getMediaManager() // Pass the intent to the SDK. You can also do this in onCreate(). if (mediaManager.onNewIntent(intent)) { // If the SDK recognizes the intent, you should early return. return } // If the SDK doesn't recognize the intent, you can handle the intent with // your own logic. ... } }
public class MyActivity extends Activity { @Override protected void onStart() { super.onStart(); MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); // Pass the intent to the SDK. You can also do this in onCreate(). if (mediaManager.onNewIntent(getIntent())) { // If the SDK recognizes the intent, you should early return. return; } // If the SDK doesn't recognize the intent, you can handle the intent with // your own logic. ... } // For some cases, a new load intent triggers onNewIntent() instead of // onStart(). @Override protected void onNewIntent(Intent intent) { MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); // Pass the intent to the SDK. You can also do this in onCreate(). if (mediaManager.onNewIntent(intent)) { // If the SDK recognizes the intent, you should early return. return; } // If the SDK doesn't recognize the intent, you can handle the intent with // your own logic. ... } }
MediaManager
の場合
読み込みインテントであることが検出されると、
MediaLoadRequestData
インテントからオブジェクトを取得し、
MediaLoadCommandCallback.onLoad()
。
読み込みリクエストを処理するには、このメソッドをオーバーライドする必要があります。このコールバックは
次の日付より前に登録
MediaManager.onNewIntent()
が呼び出される(Activity または App onCreate()
で実行されることが推奨されます)
メソッドをご覧ください)。
class MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val mediaManager = CastReceiverContext.getInstance().getMediaManager() mediaManager.setMediaLoadCommandCallback(MyMediaLoadCommandCallback()) } } class MyMediaLoadCommandCallback : MediaLoadCommandCallback() { override fun onLoad( senderId: String?, loadRequestData: MediaLoadRequestData ): Task{ return Tasks.call { // Resolve the entity into your data structure and load media. val mediaInfo = loadRequestData.getMediaInfo() if (!checkMediaInfoSupported(mediaInfo)) { // Throw MediaException to indicate load failure. throw MediaException( MediaError.Builder() .setDetailedErrorCode(DetailedErrorCode.LOAD_FAILED) .setReason(MediaError.ERROR_REASON_INVALID_REQUEST) .build() ) } myFillMediaInfo(MediaInfoWriter(mediaInfo)) myPlayerLoad(mediaInfo.getContentUrl()) // Update media metadata and state (this clears all previous status // overrides). castReceiverContext.getMediaManager() .setDataFromLoad(loadRequestData) ... castReceiverContext.getMediaManager().broadcastMediaStatus() // Return the resolved MediaLoadRequestData to indicate load success. return loadRequestData } } private fun myPlayerLoad(contentURL: String) { myPlayer.load(contentURL) // Update the MediaSession state. val playbackState: PlaybackStateCompat = Builder() .setState( player.getState(), player.getPosition(), System.currentTimeMillis() ) ... .build() mediaSession.setPlaybackState(playbackState) }
public class MyActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); mediaManager.setMediaLoadCommandCallback(new MyMediaLoadCommandCallback()); } } public class MyMediaLoadCommandCallback extends MediaLoadCommandCallback { @Override public TaskonLoad(String senderId, MediaLoadRequestData loadRequestData) { return Tasks.call(() -> { // Resolve the entity into your data structure and load media. MediaInfo mediaInfo = loadRequestData.getMediaInfo(); if (!checkMediaInfoSupported(mediaInfo)) { // Throw MediaException to indicate load failure. throw new MediaException( new MediaError.Builder() .setDetailedErrorCode(DetailedErrorCode.LOAD_FAILED) .setReason(MediaError.ERROR_REASON_INVALID_REQUEST) .build()); } myFillMediaInfo(new MediaInfoWriter(mediaInfo)); myPlayerLoad(mediaInfo.getContentUrl()); // Update media metadata and state (this clears all previous status // overrides). castReceiverContext.getMediaManager() .setDataFromLoad(loadRequestData); ... castReceiverContext.getMediaManager().broadcastMediaStatus(); // Return the resolved MediaLoadRequestData to indicate load success. return loadRequestData; }); } private void myPlayerLoad(String contentURL) { myPlayer.load(contentURL); // Update the MediaSession state. PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder() .setState( player.getState(), player.getPosition(), System.currentTimeMillis()) ... .build(); mediaSession.setPlaybackState(playbackState); }
読み込みインテントを処理するために、インテントを解析してデータ構造に変換します。
定義
(MediaLoadRequestData
使用されます。
メディア コマンドのサポート
基本的な再生コントロールのサポート
メディアと互換性のあるコマンドを含む基本的な統合コマンド あります。これらのコマンドは、メディア セッション コールバックを介して通知されます。必要なこと メディア セッションへのコールバックを登録してこれをサポートします( です)。
private class MyMediaSessionCallback : MediaSessionCompat.Callback() { override fun onPause() { // Pause the player and update the play state. myPlayer.pause() } override fun onPlay() { // Resume the player and update the play state. myPlayer.play() } override fun onSeekTo(pos: Long) { // Seek and update the play state. myPlayer.seekTo(pos) } ... } mediaSession.setCallback(MyMediaSessionCallback())
private class MyMediaSessionCallback extends MediaSessionCompat.Callback { @Override public void onPause() { // Pause the player and update the play state. myPlayer.pause(); } @Override public void onPlay() { // Resume the player and update the play state. myPlayer.play(); } @Override public void onSeekTo(long pos) { // Seek and update the play state. myPlayer.seekTo(pos); } ... } mediaSession.setCallback(new MyMediaSessionCallback());
キャスト コントロール コマンドのサポート
一部のキャスト コマンドは、
MediaSession
skipAd()
または
setActiveMediaTracks()
。
また、いくつかのキューコマンドをここに実装する必要があります。これは、Cast キューが
MediaSession
キューと完全な互換性がありません。
class MyMediaCommandCallback : MediaCommandCallback() { override fun onSkipAd(requestData: RequestData?): Task{ // Skip your ad ... return Tasks.forResult(null) } } val mediaManager = CastReceiverContext.getInstance().getMediaManager() mediaManager.setMediaCommandCallback(MyMediaCommandCallback())
public class MyMediaCommandCallback extends MediaCommandCallback { @Override public TaskonSkipAd(RequestData requestData) { // Skip your ad ... return Tasks.forResult(null); } } MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); mediaManager.setMediaCommandCallback(new MyMediaCommandCallback());
サポートされているメディア コマンドを指定する
キャスト レシーバーと同様に、Android TV アプリでどのコマンドを
サポートされているため、送信者は特定の UI コントロールを有効または無効にできます。対象
コマンドを
MediaSession
コマンドを
PlaybackStateCompat
。
その他のコマンドは、
MediaStatusModifier
。
// Set media session supported commands val playbackState: PlaybackStateCompat = PlaybackStateCompat.Builder() .setActions(PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PAUSE) .setState(PlaybackStateCompat.STATE_PLAYING) .build() mediaSession.setPlaybackState(playbackState) // Set additional commands in MediaStatusModifier val mediaManager = CastReceiverContext.getInstance().getMediaManager() mediaManager.getMediaStatusModifier() .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT)
// Set media session supported commands PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder() .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE) .setState(PlaybackStateCompat.STATE_PLAYING) .build(); mediaSession.setPlaybackState(playbackState); // Set additional commands in MediaStatusModifier MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); mediaManager.getMediaStatusModifier() .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT);
サポートされていないボタンを非表示にする
Android TV アプリが基本的なメディア コントロールしかサポートしていないにもかかわらず、ウェブ レシーバーが より高度な制御をサポートしているため、送信側のアプリが Android TV アプリにキャストする際に正しく機能する。たとえば、Android TV が ウェブ レシーバー アプリでは再生速度の変更がサポートされていませんが、 各プラットフォームでサポートされているアクションを正しく設定し、 UI が適切にレンダリングされます。
MediaStatus の変更
トラック、広告、ライブ、キューなどの高度な機能をサポートするために、Android
TV アプリは、以下では確認できない追加情報を提供する必要があります。
MediaSession
。
Google は、
MediaStatusModifier
クラスをご覧ください。MediaStatusModifier
は常に
設定したMediaSession
CastReceiverContext
。
作成してブロードキャストする
MediaStatus
:
val mediaManager: MediaManager = castReceiverContext.getMediaManager() val statusModifier: MediaStatusModifier = mediaManager.getMediaStatusModifier() statusModifier .setLiveSeekableRange(seekableRange) .setAdBreakStatus(adBreakStatus) .setCustomData(customData) mediaManager.broadcastMediaStatus()
MediaManager mediaManager = castReceiverContext.getMediaManager(); MediaStatusModifier statusModifier = mediaManager.getMediaStatusModifier(); statusModifier .setLiveSeekableRange(seekableRange) .setAdBreakStatus(adBreakStatus) .setCustomData(customData); mediaManager.broadcastMediaStatus();
クライアント ライブラリは MediaSession
からベース MediaStatus
を取得します。
Android TV アプリは、
MediaStatus
修飾子。
一部の状態とメタデータは、MediaSession
と
MediaStatusModifier
。Google Cloud コンソールのみを設定することを強くおすすめします。
MediaSession
。引き続き修飾子を使用して、
MediaSession
- 修飾子のステータスは常に同じであるため、この方法はおすすめしません。
MediaSession
で指定された値よりも優先度が高くなります。
送信前に MediaStatus をインターセプトする
Web Receiver SDK と同様、
送信するメッセージには、
MediaStatusInterceptor
処理し、
MediaStatus
~
あります。関数を渡します。
MediaStatusWriter
送信前に MediaStatus
を操作します。
mediaManager.setMediaStatusInterceptor(object : MediaStatusInterceptor { override fun intercept(mediaStatusWriter: MediaStatusWriter) { // Perform customization. mediaStatusWriter.setCustomData(JSONObject("{data: \"my Hello\"}")) } })
mediaManager.setMediaStatusInterceptor(new MediaStatusInterceptor() { @Override public void intercept(MediaStatusWriter mediaStatusWriter) { // Perform customization. mediaStatusWriter.setCustomData(new JSONObject("{data: \"my Hello\"}")); } });
ユーザー認証情報の処理
Android TV アプリで、特定のユーザーのみにアプリの起動や参加を許可している場合があります あります。たとえば、次の場合にのみ、送信者に開始や参加を許可します。
- 送信側アプリが ATV アプリと同じアカウントとプロファイルにログインしていること。
- 送信側アプリが、ATV アプリと同じアカウントにログインしていますが、プロファイルは異なります。
アプリで複数または匿名のユーザーが処理できる場合は、必要に応じて ATV セッションに参加するようユーザーに指示できます。ユーザーが認証情報を提供すると、ATV アプリは 進捗状況やその他のユーザーデータにアクセスできるように、 適切にトラッキングされます
送信側アプリが Android TV アプリを起動または Android TV アプリを起動すると、送信側アプリが セッションに参加するユーザーを表す認証情報を提供する必要があります。
送信者が Android TV アプリを起動して参加する前に、 チェッカーを起動して、送信者の認証情報が許可されているかどうかを確認します。そうでない場合、キャストは Connect SDK がフォールバックして Web Receiver を起動します。
送信側アプリの起動認証情報データ
送信者側では、CredentialsData
を指定して
記録されます。
credentials
は、ATV である限り、ユーザーが定義できる文字列です。
理解できます。credentialsType
は、ユーザーがアクセスするプラットフォームを
CredentialsData
はカスタム値から取得するか、カスタム値にすることができます。デフォルトでは
送信側のプラットフォームに
送信することがあります
CredentialsData
は、Android TV アプリの起動時にのみ渡されます。
記録されます。接続中に再度設定した場合、その設定は
Android TV アプリ。接続中に送信者がプロフィールを切り替えた場合、
セッションにとどまるか、
SessionManager.endCurrentCastSession(boolean stopCasting)
(新しいプロファイルがセッションに対応していないと思われる場合)。
「
CredentialsData
各送信者のメッセージは、
getSenders
日付
CastReceiverContext
SenderInfo
を取得する、
getCastLaunchRequest()
を
CastLaunchRequest
,
次に
getCredentialsData()
play-services-cast-framework
のバージョンが必要
19.0.0
以上。
CastContext.getSharedInstance().setLaunchCredentialsData( CredentialsData.Builder() .setCredentials("{\"userId\": \"abc\"}") .build() )
CastContext.getSharedInstance().setLaunchCredentialsData( new CredentialsData.Builder() .setCredentials("{\"userId\": \"abc\"}") .build());
google-cast-sdk
バージョン v4.8.3
または
高くなります。
オプションの設定後、いつでも呼び出すことができます。
GCKCastContext.setSharedInstanceWith(options)
。
GCKCastContext.sharedInstance().setLaunch( GCKCredentialsData(credentials: "{\"userId\": \"abc\"}")
Chromium ブラウザのバージョンが必要です
M87
以降。
オプションの設定後、いつでも呼び出すことができます。
cast.framework.CastContext.getInstance().setOptions(options);
。
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}"); cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
ATV リリース リクエスト チェッカーの実装
「
CredentialsData
送信側が起動または参加しようとしたときに、Android TV アプリに渡されます。Google Chat では
実装
LaunchRequestChecker
。
リクエストを許可または拒否できます
リクエストが拒否された場合、Web Receiver は起動されずに読み込まれます ATV アプリにネイティブに統合できますATV が対応できない場合、リクエストを拒否する必要があります。 開始または参加をリクエストしたユーザーを処理しますたとえば ユーザーがリクエストしたよりも ATV アプリにログインしており、アプリが 認証情報の切り替えを処理しているか、現在ログイン中のユーザーがいない ATV アプリ。
リクエストが許可されると、ATV アプリが起動します。これは
ユーザーがリクエストしたときの読み込みリクエストの送信をアプリがサポートしているかどうかに応じて、
ATV アプリにログインしていない場合や、ユーザーが一致していない場合。この動作は、
LaunchRequestChecker
で自由にカスタマイズ可能です。
実装するクラスを作成します。
CastReceiverOptions.LaunchRequestChecker
インターフェース:
class MyLaunchRequestChecker : LaunchRequestChecker { override fun checkLaunchRequestSupported(launchRequest: CastLaunchRequest): Task{ return Tasks.call { myCheckLaunchRequest( launchRequest ) } } } private fun myCheckLaunchRequest(launchRequest: CastLaunchRequest): Boolean { val credentialsData = launchRequest.getCredentialsData() ?: return false // or true if you allow anonymous users to join. // The request comes from a mobile device, e.g. checking user match. return if (credentialsData.credentialsType == CredentialsData.CREDENTIALS_TYPE_ANDROID) { myCheckMobileCredentialsAllowed(credentialsData.getCredentials()) } else false // Unrecognized credentials type. }
public class MyLaunchRequestChecker implements CastReceiverOptions.LaunchRequestChecker { @Override public TaskcheckLaunchRequestSupported(CastLaunchRequest launchRequest) { return Tasks.call(() -> myCheckLaunchRequest(launchRequest)); } } private boolean myCheckLaunchRequest(CastLaunchRequest launchRequest) { CredentialsData credentialsData = launchRequest.getCredentialsData(); if (credentialsData == null) { return false; // or true if you allow anonymous users to join. } // The request comes from a mobile device, e.g. checking user match. if (credentialsData.getCredentialsType().equals(CredentialsData.CREDENTIALS_TYPE_ANDROID)) { return myCheckMobileCredentialsAllowed(credentialsData.getCredentials()); } // Unrecognized credentials type. return false; }
class MyReceiverOptionsProvider : ReceiverOptionsProvider { override fun getOptions(context: Context?): CastReceiverOptions { return CastReceiverOptions.Builder(context) ... .setLaunchRequestChecker(MyLaunchRequestChecker()) .build() } }
public class MyReceiverOptionsProvider implements ReceiverOptionsProvider { @Override public CastReceiverOptions getOptions(Context context) { return new CastReceiverOptions.Builder(context) ... .setLaunchRequestChecker(new MyLaunchRequestChecker()) .build(); } }
true
を
LaunchRequestChecker
が ATV アプリを起動し、false
が Web Receiver アプリを起動します。
送信とカスタム メッセージの受信
キャスト プロトコルを使用すると、送信者とメッセージの間でカスタム文字列のメッセージを送信できます。
受信します。送信する名前空間(チャンネル)を登録する必要があります。
初期化する前に
CastReceiverContext
。
Android TV - カスタム名前空間を指定する
アプリケーションでサポートされている名前空間を
CastReceiverOptions
セットアップ中:
class MyReceiverOptionsProvider : ReceiverOptionsProvider { override fun getOptions(context: Context?): CastReceiverOptions { return CastReceiverOptions.Builder(context) .setCustomNamespaces( Arrays.asList("urn:x-cast:com.example.cast.mynamespace") ) .build() } }
public class MyReceiverOptionsProvider implements ReceiverOptionsProvider { @Override public CastReceiverOptions getOptions(Context context) { return new CastReceiverOptions.Builder(context) .setCustomNamespaces( Arrays.asList("urn:x-cast:com.example.cast.mynamespace")) .build(); } }
Android TV - メッセージの送信
// If senderId is null, then the message is broadcasted to all senders. CastReceiverContext.getInstance().sendMessage( "urn:x-cast:com.example.cast.mynamespace", senderId, customString)
// If senderId is null, then the message is broadcasted to all senders. CastReceiverContext.getInstance().sendMessage( "urn:x-cast:com.example.cast.mynamespace", senderId, customString);
Android TV - カスタム名前空間メッセージを受信する
class MyCustomMessageListener : MessageReceivedListener { override fun onMessageReceived( namespace: String, senderId: String?, message: String ) { ... } } CastReceiverContext.getInstance().setMessageReceivedListener( "urn:x-cast:com.example.cast.mynamespace", new MyCustomMessageListener());
class MyCustomMessageListener implements CastReceiverContext.MessageReceivedListener { @Override public void onMessageReceived( String namespace, String senderId, String message) { ... } } CastReceiverContext.getInstance().setMessageReceivedListener( "urn:x-cast:com.example.cast.mynamespace", new MyCustomMessageListener());