Bu sayfada, Android TV alıcı uygulamasını özelleştirmek için kullanılabilen özelliklerin kod snippet'leri ve açıklamaları bulunmaktadır.
Kitaplıkları yapılandırma
Cast Connect API'lerini Android TV uygulamanızda kullanılabilir hale getirmek için:
-
Uygulama modülü dizininizdeki
build.gradle
dosyasını açın. -
google()
değerinin listelenenrepositories
değerine dahil edildiğini doğrulayın.repositories { google() }
-
Uygulamanız için hedeflediğiniz cihaz türüne bağlı olarak, kitaplıkların en son sürümlerini bağımlılıklarınıza ekleyin:
-
Android Receiver uygulaması için:
dependencies { implementation 'com.google.android.gms:play-services-cast-tv:21.1.1' implementation 'com.google.android.gms:play-services-cast:22.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:22.0.0' }
-
Android Receiver uygulaması için:
-
Değişiklikleri kaydedin ve araç çubuğunda
Sync Project with Gradle Files
simgesini tıklayın.
-
Podfile
'üngoogle-cast-sdk
4.8.3 veya sonraki bir sürümü hedeflediğinden emin olun -
iOS 14 veya sonraki bir sürümü hedefleyin. Daha fazla bilgi için Sürüm Notları'na bakın.
platform: ios, '14' def target_pods pod 'google-cast-sdk', '~>4.8.3' end
- Chromium tarayıcı M87 veya sonraki bir sürüm gereklidir.
-
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, uygulamaların androidx
ad alanını kullanacak şekilde güncellenmesini gerektirir. AndroidX'e geçiş ile ilgili talimatları uygulayın.
Android TV uygulamasıyla ilgili ön koşullar
Android TV uygulamanızda Cast Connect'i desteklemek için bir medya oturumundan etkinlik oluşturmanız ve desteklemeniz gerekir. Medya oturumunuz tarafından sağlanan veriler, medya durumunuz için temel bilgileri (ör. konum, oynatma durumu vb.) sağlar. Medya oturumunuz, Cast Connect kitaplığı tarafından bir gönderenden belirli mesajlar (ör. duraklatma) aldığında sinyal vermek için de kullanılır.
Medya oturumu ve medya oturumunun nasıl başlatılacağı 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 oturumu serbest bırakmanız gerekir. Kullanıcı, diğer içeriklere göz atmak için "geri"yi seçerek veya uygulamayı arka plana alarak oturumu serbest bırakabilir. Uygulamanız bir müzik uygulamasıysa artık medya oynatılmadığında oturumu serbest bırakmanız gerekir.
Oturum durumunu güncelleme
Medya oturumunuzda bulunan veriler, oynatıcınızın durumuyla güncel tutulmalıdır. Örneğin, oynatma duraklatıldığında oynatma durumunun yanı sıra desteklenen işlemleri de güncellemeniz gerekir. Aşağıdaki tablolarda, güncel tutmakla 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() | Tekrarlama modunu ayarlar. |
setShuffleMode() | Karıştırma 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); }
Aktarım denetimini işleme
Uygulamanız, medya oturumu aktarım denetimi geri çağırma işlevini uygulamalıdır. Aşağıdaki tabloda, bu düğümlerin hangi aktarım denetimi işlemlerini gerçekleştirmesi gerektiği gösterilmektedir:
MediaSessionCompat.Callback
İşlemler | Açıklama |
---|---|
onPlay() | Devam ettir |
onPause() | Duraklat |
onSeekTo() | Bir konuma atlama |
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());
Yayın desteğini yapılandırma
Gönderen uygulama tarafından bir başlatma isteği gönderildiğinde, uygulama ad alanı içeren bir intent oluşturulur. Bu işlemi gerçekleştirme ve TV uygulaması açıldığında CastReceiverContext
nesnesinin bir örneğini oluşturma işlemlerinden uygulamanız 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
Lansman amacı filtresi ekleme
Gönderen uygulamanızdan başlatma intent'ini işlemek 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ı belirtin
CastReceiverOptions
sağlamak için bir 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" />
CastReceiverContext
başlatılırken ReceiverOptionsProvider
, CastReceiverOptions
sağlamak için kullanılır.
Yayın alıcısı bağlamı
Uygulamanız oluşturulduğunda CastReceiverContext
değişkenini başlatın:
override fun onCreate() { CastReceiverContext.initInstance(this) ... }
@Override public void onCreate() { CastReceiverContext.initInstance(this); ... }
Uygulamanız ön plana geçtiğinde CastReceiverContext
'yi başlatın:
CastReceiverContext.getInstance().start()
CastReceiverContext.getInstance().start();
Video uygulamaları veya arka planda oynatmayı desteklemeyen uygulamalar için uygulama arka plana geçtikten sonra CastReceiverContext
üzerinde stop()
çağrısı yapın:
// Player has stopped. CastReceiverContext.getInstance().stop()
// Player has stopped. CastReceiverContext.getInstance().stop();
Ayrıca, uygulamanız arka planda oynatmayı destekliyorsa arka planda oynatma durdurulduğunda CastReceiverContext
üzerinde stop()
simgesini tıklayı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, start()
ve stop()
'u farklı etkinliklerden çağırdığınızda yarış koşullarının oluşmasını önler.
// 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'u MediaManager'a bağlama
Bir MediaSession
oluşturduğunuzda, CastReceiverContext
'e komutları nereye göndereceğini ve medya oynatma durumunu nereden alacağını bildirmek için 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
'ünüzü yayınladığınızda MediaManager
üzerinde null jetonu 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()
işlevini çağırmanız yerine, yalnızca uygulamanız arka plandayken ve artık medya oynatmıyorken ç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
'i kullanabilirsiniz.
MediaSessionConnector.MediaButtonEventHandler
, varsayılan olarak MediaSessionCompat.Callback
tarafından ele alınan setMediaButtonEventHandler(MediaButtonEventHandler)
işlevini çağırarak MediaButton etkinliklerini işlemek için kullanılabilir.
MediaSessionConnector
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 uygulaması kurulumu
Cast Connect desteğini etkinleştirme
Gönderen uygulamanızı Cast Connect desteğiyle güncelledikten sonra, androidReceiverCompatible
işaretini LaunchOptions
doğru olarak ayarlayarak uygulamanızın hazır olduğunu belirtebilirsiniz.
play-services-cast-framework
19.0.0
veya daha yeni bir sürüm gerekir.
androidReceiverCompatible
işareti, CastOptions
'nin bir parçası olan
LaunchOptions
'te 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, GCKCastOptions
'nin bir parçası olan GCKLaunchOptions
'te ayarlanır:
let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: kReceiverAppID)) ... let launchOptions = GCKLaunchOptions() launchOptions.androidReceiverCompatible = true options.launchOptions = launchOptions GCKCastContext.setSharedInstanceWith(options)
Chromium Tarayıcı 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 Developer Console kurulumu
Android TV uygulamasını yapılandırma
Android TV uygulamanızın paket adını Cast Developer Console'a ekleyip 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 isterseniz kayıt sayfasına bakın.
Medya yükleme
Android TV uygulamanızda derin bağlantı desteğini zaten uyguladıysanız Android TV manifestinizde benzer bir tanım yapılandırılmış 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 öğeye göre yükleme
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ı 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ıyla bir intent aracılığıyla gönderilir.
Gönderenin ATV kimlik bilgilerini ayarlama
Web alıcı uygulamanız ve Android TV uygulamanız farklı derin bağlantıları ve credentials
'yi destekliyor olabilir (örneğin, kimlik doğrulamayı iki platformda farklı şekilde yönetiyorsanız). Bu sorunu gidermek 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ı 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ğinde entity
ve credentials
kullanılır. Ancak Android TV uygulamanız başlatılırsa SDK, entity
ve credentials
değerlerini atvEntity
ve atvCredentials
(belirtildiyse) değerlerinizle geçersiz kılar.
Content ID veya MediaQueueData ile yükleme
entity
veya atvEntity
kullanmıyorsanız ve Medya Bilgilerinizde Content ID ya da Content URL'yi kullanıyorsanız veya daha ayrıntılı Medya Yükleme İsteği Verileri'ni 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'ye benzer şekilde, içerik bilgilerinizle bir yükleme isteği oluşturabilir ve load()
'yi ç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ı 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önteminizde 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
, amacın bir yükleme amacı olduğunu algılarsa amaçtan bir MediaLoadRequestData
nesnesi çıkarır ve MediaLoadCommandCallback.onLoad()
'ı çağırır.
Yükleme isteğini işlemek için bu yöntemi geçersiz kılmanız gerekir. Geri çağırma işlevi, 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 niyetini işlemek için niyeti tanımladığımız veri yapılarına (yükleme istekleri için MediaLoadRequestData
) ayrıştırabilirsiniz.
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 geri çağırma işlevi kaydetmeniz gerekir (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());
Chromecast kontrol komutlarını destekleme
skipAd()
veya setActiveMediaTracks()
gibi bazı yayınlama komutları MediaSession
'te kullanılamaz.
Ayrıca, Cast sırası MediaSession
sırasıyla tam uyumlu olmadığından burada bazı sıra komutlarının 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
Gönderenlerin belirli kullanıcı arayüzü kontrollerini etkinleştirebilmesi veya devre dışı bırakabilmesi için Android TV uygulamanızda, Cast alıcınızda olduğu gibi hangi komutların desteklendiğini belirtmeniz gerekir. MediaSession
kapsamındaki komutlar için PlaybackStateCompat
komutlarını 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 gizleme
Android TV uygulamanız yalnızca temel medya kontrolünü destekliyorsa ancak Web Alıcısı uygulamanız daha gelişmiş kontrolleri destekliyorsa gönderen uygulamanızın Android TV uygulamasına yayınlarken doğru şekilde davrandığından emin olmanız gerekir. Örneğin, Android TV uygulamanız oynatma hızını değiştirmeyi desteklemezken Web Alıcısı uygulamanız bunu 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'u değiştirme
Parça, reklam, canlı yayın ve sıraya ekleme gibi gelişmiş özellikleri desteklemek için Android TV uygulamanızın MediaSession
üzerinden belirlenemeyen ek bilgiler sağlaması gerekir.
Bunu başarmanız için MediaStatusModifier
sınıfını sunuyoruz. MediaStatusModifier
, her zaman CastReceiverContext
içinde belirlediğiniz MediaSession
üzerinde ç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();
Müşteri kitaplığımız MediaSession
'dan temel MediaStatus
'yi alır. Android TV uygulamanız, MediaStatus
değiştirici aracılığıyla ek durum belirtebilir ve durumu geçersiz kılabilir.
Bazı durumlar ve meta veriler hem MediaSession
hem de MediaStatusModifier
'te ayarlanabilir. Bu ayarları yalnızca MediaSession
'de yapmanızı kesinlikle öneririz. MediaSession
'teki durumları geçersiz kılmak için değiştiriciyi kullanmaya devam edebilirsiniz. Değiştiricideki durum her zaman MediaSession
tarafından sağlanan değerlerden daha yüksek önceliğe sahip olduğundan bu işlem önerilmez.
Göndermeden önce MediaStatus'u durdurma
Web Alıcı SDK'sı ile aynı şekilde, göndermeden önce bazı son rötuşlar yapmak istiyorsanız gönderilecek MediaStatus
öğesini işlemek için bir MediaStatusInterceptor
belirtebilirsiniz. Gönderilmeden önce MediaStatus
üzerinde işlem yapmak için bir MediaStatusWriter
iletiyoruz.
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 verebilir. Örneğin, bir gönderenin yalnızca aşağıdaki durumlarda başlatmasına veya katılmasına izin verin:
- Gönderen uygulama, ATV uygulamasıyla aynı hesapta ve profilde oturum açmalıdır.
- Gönderen uygulaması aynı hesaba, ancak ATV uygulamasıyla farklı bir profile giriş yapmıştır.
Uygulamanız birden fazla veya anonim kullanıcıyı işleyebiliyorsa ATV oturumuna başka kullanıcıların da katılmasına izin verebilirsiniz. Kullanıcı kimlik bilgileri sağlarsa ilerleme durumunun ve diğer kullanıcı verilerinin düzgün bir şekilde izlenmesi için ATV uygulamanızın kimlik bilgilerini işlemesi gerekir.
Gönderen uygulamanız Android TV uygulamanızı başlattığında veya uygulamanıza katıldığında, oturuma katılan kişiyi temsil eden kimlik bilgilerini sağlamalıdır.
Bir gönderen Android TV uygulamanızı başlatıp katılmadan önce, gönderen kimlik bilgilerine izin verilip verilmediğini görmek için bir başlatma kontrol cihazı belirtebilirsiniz. Aksi takdirde Cast Connect SDK'sı, web alıcınızı başlatmaya geri döner.
Gönderen uygulama başlatma kimlik bilgileri verileri
Gönderen tarafında, oturuma kimin katıldığını belirtmek için CredentialsData
değerini kullanabilirsiniz.
credentials
, ATV uygulamanız anlayabildiğ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
yalnızca başlatma veya katılma sırasında Android TV uygulamanıza iletilir. Bağlantıdayken 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)
düğmesine basabilirsiniz.
Her gönderenin CredentialsData
değeri, SenderInfo
değerini almak için CastReceiverContext
üzerinde getSenders
, CastLaunchRequest
değerini almak için getCastLaunchRequest()
ve ardından getCredentialsData()
kullanılarak alınabilir.
play-services-cast-framework
19.0.0
veya sonraki bir sürümü gerektirir.
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
veya daha yeni bir sürüm gerekir.
Seçenekler belirlendikten sonra dilediğiniz zaman çağrılabilir:
GCKCastContext.setSharedInstanceWith(options)
.
GCKCastContext.sharedInstance().setLaunch( GCKCredentialsData(credentials: "{\"userId\": \"abc\"}")
Chromium Tarayıcı M87
veya daha yeni bir sürüm gerekir.
Seçenekler belirlendikten sonra dilediğiniz zaman ç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 kontrol cihazını uygulama
Bir gönderen başlatmaya veya katılmaya çalıştığında CredentialsData
, Android TV uygulamanıza iletilir. LaunchRequestChecker
uygulayabilirsiniz.
tıklayarak bu isteğe izin verebilir veya isteği reddedebilirsiniz.
Bir istek reddedilirse ATV uygulamasında yerel olarak başlatılmak yerine Web Alıcısı yüklenir. ATV'niz, başlatma veya katılma isteğinde bulunan kullanıcıyı işleyemiyorsa isteği reddetmeniz gerekir. Örneğin, ATV uygulamasında istekte bulunan kullanıcıdan farklı bir kullanıcının oturum açmış olması ve uygulamanızın kimlik bilgisi geçişini idare edememesi veya ATV uygulamasında şu anda oturum açmış bir kullanıcı olmaması bu duruma neden olabilir.
İsteğe izin verilirse ATV uygulaması açılır. Bu davranışı, uygulamanızın bir kullanıcı ATV uygulamasına giriş yapmadığında veya kullanıcı uyuşmazlığı olduğunda yükleme isteği gönderip göndermediğine bağlı olarak özelleştirebilirsiniz. Bu davranış, LaunchRequestChecker
'te 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
'te 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üldüğünde ATV uygulaması, false
çözüldüğünde ise Web Alıcısı uygulamanız başlatılır.
Özel Mesaj Gönderme ve Alma
Yayın protokolü, gönderenler ile alıcı uygulamanız arasında özel dize mesajları göndermenize olanak tanır. CastReceiverContext
öğenizi başlatmadan önce mesaj göndermek için bir ad alanı (kanal) kaydettirmeniz gerekir.
Android TV: Özel Ad Alanı Belirtme
Kurulum sırasında desteklenen ad alanlarınızı CastReceiverOptions
içinde 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'de 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 Alan Adı 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());