Bu sayfada, Android TV Alıcı uygulamasını özelleştirmek için kullanılabilecek özelliklerin kod snippet'leri ve açıklamaları yer alır.
Kitaplıklar yapılandırılıyor
Cast Connect API'lerini Android TV uygulamanızda kullanılabilir hale getirmek için:
-
Uygulama modülü dizininizdeki
build.gradledosyasını açın. -
google()öğesinin, listelenenrepositoriesiçinde yer aldığını doğrulayın.repositories { google() } -
Uygulamanızın hedef cihaz türüne bağlı olarak kitaplıkların en yeni sürümlerini bağımlılıklarınıza ekleyin:
-
Android Alıcı uygulaması için:
dependencies { implementation 'com.google.android.gms:play-services-cast-tv:21.1.1' implementation 'com.google.android.gms:play-services-cast:23.0.0' }
-
Android gönderen uygulaması için:
dependencies { implementation 'com.google.android.gms:play-services-cast:21.1.1' implementation 'com.google.android.gms:play-services-cast-framework:23.0.0' }
-
Android Alıcı uygulaması için:
-
Değişiklikleri kaydedin ve araç çubuğunda
Sync Project with Gradle Filessimgesini tıklayın.
-
Podfileuygulamanızıngoogle-cast-sdk4.8.6 veya sonraki bir sürümü hedeflediğinden emin olun. -
iOS 16 veya sonraki sürümleri hedeflemelidir. Daha fazla bilgi için Sürüm Notları'na bakın.
platform: ios, '16' def target_pods pod 'google-cast-sdk', '~>4.8.6' end
- Chromium tarayıcı M87 veya sonraki bir sürümü gerektirir.
-
Web Sender API kitaplığını projenize ekleme
<script src="//www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
AndroidX şartı
Google Play Hizmetleri'nin yeni sürümleri, androidx ad alanını kullanmak için uygulamanın güncellenmesini gerektirir. AndroidX'e geçiş ile ilgili talimatları uygulayın.
Android TV uygulaması: Ön koşullar
Android TV uygulamanızda Cast Connect'i desteklemek için bir medya oturumundan etkinlikler oluşturmanız ve desteklemeniz gerekir. Medya oturumunuz tarafından sağlanan veriler, medya durumunuzla ilgili temel bilgileri (ör. konum, oynatma durumu vb.) sağlar. Medya oturumunuz, gönderenden belirli mesajlar (ör. duraklatma) aldığında sinyal göndermek için Cast Connect kitaplığı tarafından da kullanılır.
Medya oturumu ve medya oturumunun nasıl ilk kullanıma hazırlanacağı hakkında daha fazla bilgi için medya oturumuyla çalışma kılavuzuna bakın.
Medya oturumu yaşam döngüsü
Uygulamanız, oynatma başladığında bir medya oturumu oluşturmalı ve artık kontrol edilemediğinde bu oturumu serbest bırakmalıdır. Örneğin, uygulamanız bir video uygulamasıysa kullanıcı oynatma etkinliğinden çıktığında (diğer içeriklere göz atmak için "geri"yi seçerek veya uygulamayı arka plana alarak) oturumu sonlandırmanız gerekir. Uygulamanız bir müzik uygulamasıysa artık herhangi bir medya oynatmadığında oturumu sonlandırmanız gerekir.
Oturum durumu güncelleniyor
Medya oturumunuzdaki veriler, oynatıcınızın durumuyla güncel tutulmalıdır. Örneğin, oynatma duraklatıldığında oynatma durumunu ve desteklenen işlemleri güncellemeniz gerekir. Aşağıdaki tablolarda, güncel tutmaktan sorumlu olduğunuz eyaletler listelenmiştir.
MediaMetadataCompat
| Meta Veri Alanı | Açıklama |
|---|---|
| METADATA_KEY_TITLE (zorunlu) | Medya başlığı. |
| METADATA_KEY_DISPLAY_SUBTITLE | Alt başlık. |
| METADATA_KEY_DISPLAY_ICON_URI | Simge URL'si. |
| METADATA_KEY_DURATION (zorunlu) | Medya süresi. |
| METADATA_KEY_MEDIA_URI | Content ID. |
| METADATA_KEY_ARTIST | Sanatçı. |
| METADATA_KEY_ALBUM | Albüm. |
PlaybackStateCompat
| Gerekli Yöntem | Açıklama |
|---|---|
| setActions() | Desteklenen medya komutlarını ayarlar. |
| setState() | Oynatma durumunu ve mevcut konumu ayarlayın. |
MediaSessionCompat
| Gerekli Yöntem | Açıklama |
|---|---|
| setRepeatMode() | Tekrar modunu ayarlar. |
| setShuffleMode() | Karışık modunu ayarlar. |
| setMetadata() | Medya meta verilerini ayarlar. |
| setPlaybackState() | Oynatma durumunu ayarlar. |
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);
}Taşıma kontrolünü yönetme
Uygulamanız, medya oturumu aktarım kontrolü geri çağırma işlevini uygulamalıdır. Aşağıdaki tabloda, işlemeleri gereken taşıma kontrolü işlemleri gösterilmektedir:
MediaSessionCompat.Callback
| İşlemler | Açıklama |
|---|---|
| onPlay() | Devam ettir |
| onPause() | Duraklat |
| onSeekTo() | Bir konuma gitme |
| onStop() | Mevcut medyayı durdurma |
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());
Cast desteğini yapılandırma
Gönderen uygulama tarafından bir başlatma isteği gönderildiğinde uygulama ad alanıyla bir intent oluşturulur. Uygulamanız, TV uygulaması başlatıldığında bu intent'i işlemekten ve CastReceiverContext nesnesinin bir örneğini oluşturmaktan sorumludur. TV uygulaması çalışırken Cast ile etkileşim kurmak için CastReceiverContext nesnesi gerekir. Bu nesne, TV uygulamanızın bağlı tüm gönderenlerden gelen Cast medya mesajlarını kabul etmesini sağlar.
Android TV kurulumu
Başlatma intent filtresi ekleme
Gönderen uygulamanızdan başlatma intent'ini işlemesini istediğiniz etkinliğe yeni bir intent filtresi ekleyin:
<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>
Alıcı seçenekleri sağlayıcısını belirtme
CastReceiverOptions sağlamak için
ReceiverOptionsProvider
uygulamanız gerekir:
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(); } }
Ardından, AndroidManifest dosyanızda seçenek sağlayıcıyı belirtin:
<meta-data
android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.example.mysimpleatvapplication.MyReceiverOptionsProvider" />
ReceiverOptionsProvider, CastReceiverContext başlatıldığında CastReceiverOptions sağlamak için kullanılır.
Yayın alıcısı bağlamı
Uygulamanız oluşturulduğunda CastReceiverContext nesnesini başlatın:
override fun onCreate() { CastReceiverContext.initInstance(this) ... }
@Override public void onCreate() { CastReceiverContext.initInstance(this); ... }
Uygulamanız ön plana geçtiğinde CastReceiverContext başlatın:
CastReceiverContext.getInstance().start()
CastReceiverContext.getInstance().start();
Video uygulamaları veya arka planda oynatmayı desteklemeyen uygulamalar arka plana geçtikten sonra
CastReceiverContext
üzerinde
stop()
öğesini çağırın:
// Player has stopped. CastReceiverContext.getInstance().stop()
// Player has stopped. CastReceiverContext.getInstance().stop();
Ayrıca, uygulamanız arka planda oynatmayı destekliyorsa arka planda oynatma durduğunda CastReceiverContext üzerinde stop() yöntemini çağırın.
Özellikle yerel uygulamanızda birden fazla etkinlik varsa CastReceiverContext.start() ve CastReceiverContext.stop() çağrılarını yönetmek için androidx.lifecycle kitaplığındaki LifecycleObserver'ı kullanmanızı önemle tavsiye ederiz. Bu sayede, farklı etkinliklerden start() ve stop() yöntemlerini çağırdığınızda yarışma durumları önlenir.
// 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'a bağlama
MediaSession oluşturduğunuzda, komutların nereye gönderileceğini ve medya oynatma durumunun nereden alınacağını bilmesi için CastReceiverContext'a mevcut MediaSession jetonunu da sağlamanız gerekir:
val mediaManager: MediaManager = receiverContext.getMediaManager() mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken())
MediaManager mediaManager = receiverContext.getMediaManager(); mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken());
Etkin olmayan oynatma nedeniyle MediaSession öğenizi serbest bıraktığınızda MediaManager üzerinde boş bir jeton ayarlamanız gerekir:
myPlayer.stop() mediaSession.release() mediaManager.setSessionCompatToken(null)
myPlayer.stop(); mediaSession.release(); mediaManager.setSessionCompatToken(null);
Uygulamanız arka plandayken medya oynatmayı destekliyorsa uygulamanız arka plana gönderildiğinde CastReceiverContext.stop() yöntemini çağırmak yerine, yalnızca uygulamanız arka plandayken ve artık medya oynatmadığında bu yöntemi çağırmanız gerekir. Örneğin:
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(); } }
Exoplayer'ı Cast Connect ile kullanma
Exoplayer kullanıyorsanız değişiklikleri manuel olarak takip etmek yerine oturumu ve oynatma durumu da dahil olmak üzere ilgili tüm bilgileri otomatik olarak korumak için MediaSessionConnector kullanabilirsiniz.
MediaSessionConnector.MediaButtonEventHandler,
setMediaButtonEventHandler(MediaButtonEventHandler)
öğesini çağırarak MediaButton etkinliklerini işlemek için kullanılabilir. Bu etkinlikler normalde varsayılan olarak
MediaSessionCompat.Callback
tarafından işlenir.
MediaSessionConnector
öğesini uygulamanıza entegre etmek için oynatıcı etkinliği sınıfınıza veya medya oturumunuzu yönettiğiniz yere aşağıdakileri ekleyin:
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); ... } }
Gönderen uygulama kurulumu
Cast Connect desteğini etkinleştirme
Gönderen uygulamanızı Cast Connect desteğiyle güncelledikten sonra LaunchOptions üzerinde androidReceiverCompatible işaretini "true" olarak ayarlayarak hazır olduğunu bildirebilirsiniz.
play-services-cast-framework sürüm 19.0.0 veya daha yeni bir sürüm gerekir.
androidReceiverCompatible işareti, LaunchOptions (CastOptions kapsamında) içinde ayarlanır:
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 veya daha yeni bir sürüm gerekir.
androidReceiverCompatible işareti, GCKLaunchOptions (GCKCastOptions'nin bir parçasıdır) içinde ayarlanır:
let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: kReceiverAppID)) ... let launchOptions = GCKLaunchOptions() launchOptions.androidReceiverCompatible = true options.launchOptions = launchOptions GCKCastContext.setSharedInstanceWith(options)
Chromium tarayıcı sürüm M87 veya daha yeni bir sürüm gerekir.
const context = cast.framework.CastContext.getInstance(); const castOptions = new cast.framework.CastOptions(); castOptions.receiverApplicationId = kReceiverAppID; castOptions.androidReceiverCompatible = true; context.setOptions(castOptions);
Cast Geliştirici Konsolu kurulumu
Android TV uygulamasını yapılandırma
Android TV uygulamanızın paket adını Cast Developer Console'a ekleyerek Cast uygulama kimliğinizle ilişkilendirin.

Geliştirici cihazlarını kaydetme
Geliştirme için kullanacağınız Android TV cihazının seri numarasını Cast Developer Console'a kaydedin.

Kayıt olmadan Cast Connect, güvenlik nedeniyle yalnızca Google Play Store'dan yüklenen uygulamalarda çalışır.
Cast geliştirme için Cast veya Android TV cihazı kaydetme hakkında daha fazla bilgi edinmek istiyorsanız kayıt sayfasını ziyaret edin.
Medya yükleniyor
Android TV uygulamanızda derin bağlantı desteğini zaten uyguladıysanız Android TV manifest dosyanızda yapılandırılmış benzer bir tanımınız olmalıdır:
<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>
Gönderendeki varlığa göre yük
Gönderenlerde, yükleme isteği için medya bilgilerinde entity değerini ayarlayarak derin bağlantıyı iletebilirsiniz:
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 tarayıcı sürüm M87 veya daha yeni bir sürüm gerekir.
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);
Yükleme komutu, derin bağlantınızı ve geliştirici konsolunda tanımladığınız paket adını içeren bir intent aracılığıyla gönderilir.
Gönderende ATV kimlik bilgileri ayarlanıyor
Web Alıcısı uygulamanız ve Android TV uygulamanız farklı derin bağlantıları ve credentials destekleyebilir (örneğin, iki platformda kimlik doğrulamayı farklı şekilde işliyorsanız). Bu sorunu çözmek için Android TV için alternatif entity ve credentials sağlayabilirsiniz:
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 tarayıcı sürüm M87 veya daha yeni bir sürüm gerekir.
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 Alıcısı uygulaması başlatılırsa yükleme isteğindeki entity ve credentials değerlerini kullanır. Ancak Android TV uygulamanız başlatılırsa SDK, entity ve credentials değerlerini atvEntity ve atvCredentials değerlerinizle (belirtilmişse) geçersiz kılar.
Content ID veya MediaQueueData ile yükleme
entity veya atvEntity kullanmıyorsanız ve medya bilgilerinizde Content ID veya içerik URL'si kullanıyorsanız ya da daha ayrıntılı medya yükleme isteği verilerini kullanıyorsanız Android TV uygulamanıza aşağıdaki önceden tanımlanmış intent filtresini eklemeniz gerekir:
<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>
Gönderen tarafında, öğeye göre yükleme işlemine benzer şekilde, içerik bilgilerinizle bir yükleme isteği oluşturabilir ve load() yöntemini çağırabilirsiniz.
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 tarayıcı sürüm M87 veya daha yeni bir sürüm gerekir.
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);
Yükleme isteklerini işleme
Etkinliğinizde bu yükleme isteklerini işlemek için etkinlik yaşam döngüsü geri çağırma yöntemlerinizdeki intent'leri işlemeniz gerekir:
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, intent'in bir yükleme intent'i olduğunu algılarsa intent'ten bir MediaLoadRequestData nesnesi çıkarır ve MediaLoadCommandCallback.onLoad() yöntemini çağırır.
Yükleme isteğini işlemek için bu yöntemi geçersiz kılmanız gerekir. Geri çağırma, MediaManager.onNewIntent() çağrılmadan önce kaydedilmelidir (bir Etkinlik veya Uygulama onCreate() yönteminde olması önerilir).
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); }
Yükleme amacını işlemek için amacı, tanımladığımız veri yapılarına ayrıştırabilirsiniz (yükleme istekleri için MediaLoadRequestData).
Medya komutlarını destekleme
Temel oynatma kontrolü desteği
Temel entegrasyon komutları, medya oturumuyla uyumlu komutları içerir. Bu komutlar, medya oturumu geri çağırmaları aracılığıyla bildirilir. Bunu desteklemek için medya oturumuna bir geri çağırma kaydetmeniz gerekir (bunu zaten yapıyor olabilirsiniz).
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());
Cast kontrol komutlarını destekleme
MediaSession uygulamasında kullanılamayan bazı yayınlama komutları vardır. Örneğin, skipAd() veya setActiveMediaTracks().
Ayrıca, Cast sırası MediaSession sırasıyla tam olarak uyumlu olmadığından bazı sıra komutlarının burada uygulanması gerekir.
class MyMediaCommandCallback : MediaCommandCallback() { override fun onSkipAd(requestData: RequestData?): Task<Void?> { // 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());
Desteklenen medya komutlarını belirtme
Yayın alıcınızda olduğu gibi, Android TV uygulamanız da hangi komutların desteklendiğini belirtmelidir. Böylece gönderenler belirli kullanıcı arayüzü kontrollerini etkinleştirebilir veya devre dışı bırakabilir. MediaSession'nin parçası olan komutlar için komutları PlaybackStateCompat içinde belirtin.
Ek komutlar MediaStatusModifier içinde belirtilmelidir.
// 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);
Desteklenmeyen düğmeleri gizle
Android TV uygulamanız yalnızca temel medya kontrolünü destekliyor ancak Web Alıcı uygulamanız daha gelişmiş kontrolü destekliyorsa gönderen uygulamanızın Android TV uygulamasına yayın yaparken doğru şekilde davrandığından emin olmanız gerekir. Örneğin, Android TV uygulamanız oynatma hızını değiştirmeyi desteklemiyor ancak Web Alıcı uygulamanız destekliyorsa desteklenen işlemleri her platformda doğru şekilde ayarlamanız ve gönderen uygulamanızın kullanıcı arayüzünü düzgün şekilde oluşturduğundan emin olmanız gerekir.
MediaStatus değiştiriliyor
Android TV uygulamanızın; parçalar, reklamlar, canlı yayın ve sıraya alma gibi ileri seviye özellikleri desteklemesi için MediaSession aracılığıyla tespit edilemeyen ek bilgiler sağlaması gerekir.
Bunu yapabilmeniz için MediaStatusModifier sınıfını sunuyoruz. MediaStatusModifier, her zaman CastReceiverContext bölümünde ayarladığınız MediaSession ile çalışır.
MediaStatus oluşturmak ve yayınlamak için:
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();İstemci kitaplığımız, temel MediaStatus değerini MediaSession uygulamasından alır. Android TV uygulamanız, ek durum belirtebilir ve MediaStatus değiştirici aracılığıyla durumu geçersiz kılabilir.
Bazı durumlar ve meta veriler hem MediaSession hem de MediaStatusModifier içinde ayarlanabilir. Bunları yalnızca MediaSession içinde ayarlamanızı kesinlikle öneririz. Değiştiriciyi kullanarak MediaSession içindeki durumları geçersiz kılabilirsiniz. Ancak değiştiricideki durum her zaman MediaSession tarafından sağlanan değerlerden daha yüksek önceliğe sahip olduğundan bu yöntem önerilmez.
Göndermeden önce MediaStatus'u yakalama
Web Alıcı SDK'sında olduğu gibi, göndermeden önce son dokunuşları yapmak istiyorsanız gönderilecek MediaStatus öğesini işlemek için bir MediaStatusInterceptor belirtebilirsiniz. MediaStatus gönderilmeden önce üzerinde değişiklik yapmak için bir MediaStatusWriter iletiriz.
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\"}")); } });
Kullanıcı kimlik bilgilerini işleme
Android TV uygulamanız yalnızca belirli kullanıcıların uygulama oturumunu başlatmasına veya oturuma katılmasına izin veriyor olabilir. Örneğin, bir gönderenin yalnızca aşağıdaki durumlarda oturum başlatmasına veya oturuma katılmasına izin verin:
- Gönderen uygulama, ATV uygulamasıyla aynı hesap ve profilde oturum açmış.
- Gönderen uygulama, ATV uygulamasıyla aynı hesapta ancak farklı bir profilde oturum açmış.
Uygulamanız birden fazla veya anonim kullanıcıyı destekliyorsa başka kullanıcıların da ATV oturumuna katılmasına izin verebilirsiniz. Kullanıcı kimlik bilgilerini sağlarsa ATV uygulamanızın, kullanıcının ilerleme durumunun ve diğer kullanıcı verilerinin düzgün bir şekilde takip edilebilmesi için kimlik bilgilerini işlemesi gerekir.
Gönderen uygulamanız Android TV uygulamanızı başlattığında veya uygulamanıza katıldığında, oturuma kimin katıldığını gösteren kimlik bilgilerini sağlamalıdır.
Gönderen, Android TV uygulamanızı başlatıp uygulamaya katılmadan önce, gönderen kimlik bilgilerine izin verilip verilmediğini görmek için bir başlatma denetleyicisi belirtebilirsiniz. Aksi takdirde Cast Connect SDK'sı, Web Alıcınızı başlatır.
Gönderen uygulama başlatma kimlik bilgileri verileri
Gönderen tarafında, oturuma kimin katıldığını belirtmek için CredentialsData değerini belirtebilirsiniz.
credentials, ATV uygulamanız tarafından anlaşılabildiği sürece kullanıcı tarafından tanımlanabilen bir dizedir. credentialsType, CredentialsData değerinin hangi platformdan geldiğini tanımlar veya özel bir değer olabilir. Varsayılan olarak, gönderildiği platforma ayarlanır.
CredentialsData, Android TV uygulamanıza yalnızca başlatma veya katılma sırasında iletilir. Bağlıyken tekrar ayarlarsanız Android TV uygulamanıza aktarılmaz. Göndereniniz bağlıyken profili değiştirirse oturumda kalabilir veya yeni profilin oturumla uyumlu olmadığını düşünüyorsanız SessionManager.endCurrentCastSession(boolean stopCasting) yöntemini çağırabilirsiniz.
Her gönderenin CredentialsData bilgisi, CastReceiverContext üzerinde getSenders kullanılarak SenderInfo bilgisini almak için getCastLaunchRequest(), CastLaunchRequest bilgisini almak için getCredentialsData() kullanılarak alınabilir.
play-services-cast-framework sürüm 19.0.0 veya daha yeni bir sürüm gerekir.
CastContext.getSharedInstance().setLaunchCredentialsData( CredentialsData.Builder() .setCredentials("{\"userId\": \"abc\"}") .build() )
CastContext.getSharedInstance().setLaunchCredentialsData(
new CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build());google-cast-sdk v4.8.6 veya daha yeni bir sürüm gerekir.
Seçenekler ayarlandıktan sonra herhangi bir zamanda çağrılabilir:
GCKCastContext.setSharedInstanceWith(options).
GCKCastContext.sharedInstance().setLaunch( GCKCredentialsData(credentials: "{\"userId\": \"abc\"}")
Chromium tarayıcı sürüm M87 veya daha yeni bir sürüm gerekir.
Seçenekler ayarlandıktan sonra herhangi bir zamanda çağrılabilir:
cast.framework.CastContext.getInstance().setOptions(options);.
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}"); cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
ATV başlatma isteği denetleyicisini uygulama
Gönderen, başlatmaya veya katılmaya çalıştığında CredentialsData, Android TV uygulamanıza iletilir. LaunchRequestChecker
uygulayabilirsiniz.
Bu isteğe izin vermek veya isteği reddetmek için
İstek reddedilirse ATV uygulamasında yerel olarak başlatılmak yerine Web Alıcısı yüklenir. ATV'niz, kullanıcının başlatma veya katılma isteğini işleyemiyorsa isteği reddetmeniz gerekir. Örneğin, ATV uygulamasında istekte bulunan kullanıcıdan farklı bir kullanıcı oturum açmış olabilir ve uygulamanız kimlik bilgilerini değiştiremiyor olabilir ya da ATV uygulamasında oturum açmış bir kullanıcı olmayabilir.
İsteğe izin verilirse ATV uygulaması başlatılır. Kullanıcı ATV uygulamasında oturum açmadığında veya kullanıcı uyuşmazlığı olduğunda uygulamanızın yükleme istekleri göndermeyi destekleyip desteklemediğine bağlı olarak bu davranışı özelleştirebilirsiniz. Bu davranış, LaunchRequestChecker üzerinden tamamen özelleştirilebilir.
CastReceiverOptions.LaunchRequestChecker arayüzünü uygulayan bir sınıf oluşturun:
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; }
Ardından ReceiverOptionsProvider uygulamanızda ayarlayın:
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(); } }
LaunchRequestChecker içinde true çözümlendiğinde ATV uygulaması, false çözümlendiğinde ise Web Alıcısı uygulamanız başlatılır.
Özel Mesaj Gönderme ve Alma
Cast protokolü, gönderenler ile alıcı uygulamanız arasında özel dize mesajları göndermenize olanak tanır. CastReceiverContext'nızı başlatmadan önce mesaj göndermek için bir ad alanı (kanal) kaydetmeniz gerekir.
Android TV: Özel Ad Alanı Belirtme
Kurulum sırasında desteklenen ad alanlarınızı CastReceiverOptions dosyanızda belirtmeniz gerekir:
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: Mesaj gönderme
// 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: Özel Ad Alanı Mesajları Alma
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());