Bu sayfada kod snippet'leri ve Android TV Alıcısı uygulamasını özelleştirmek için kullanılabilen özelliklerin açıklamaları yer almaktadı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()
öğesinin listelenenrepositories
içinde yer aldığını doğrulayın.repositories { google() }
-
Uygulamanız için hedef cihaz türünüze bağlı olarak, bağımlılarınıza kitaplıkların en son sürümlerini ekleyin:
-
Android Alıcı uygulaması için:
dependencies { implementation 'com.google.android.gms:play-services-cast-tv:20.0.0' implementation 'com.google.android.gms:play-services-cast:21.2.0' }
-
Android Gönderen uygulaması için:
dependencies { implementation 'com.google.android.gms:play-services-cast:20.0.0' implementation 'com.google.android.gms:play-services-cast-framework:21.2.0' }
-
Android Alıcı uygulaması için:
-
Değişiklikleri kaydedin ve araç çubuğundaki
Sync Project with Gradle Files
simgesini tıklayın.
-
Podfile
uygulamanızıngoogle-cast-sdk
4.7.0 veya sonraki bir sürümü hedeflediğinden emin olun -
iOS 12 veya sonraki sürümleri hedefleyin. Daha fazla bilgi için Sürüm Notları'na bakın.
platform: ios, '12' def target_pods pod 'google-cast-sdk', '~>4.7.0' end
- Chromium tarayıcı M87 veya sonraki bir sürüm gerektirir.
-
Web Gönderen API'si kitaplığını
<script src="//www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
projesine ekleyin
AndroidX gereksinimi
Google Play Hizmetleri'nin yeni sürümleri, androidx
ad alanını kullanmak için bir uygulamanın güncellenmesini gerektiriyor. AndroidX'e geçiş talimatlarını 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, bir yayın gönderenden belirli mesajları (ör. duraklatma) aldığını belirtmek için Cast Connect kitaplığı tarafından da kullanılır.
Medya oturumu ve medya oturumunu başlatma 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 medya medyası oluşturmalı ve artık kontrol edilememesi durumunda iptal etmelidir. Örneğin, uygulamanız bir video uygulamasıysa, kullanıcı oynatma etkinliğinden çıktığında başka içeriğe göz atmak için "geri" seçeneğini belirleyerek veya uygulamanın arka planını seçerek oturumu yayınlamanız gerekir. Uygulamanız bir müzik uygulamasıysa, uygulamanız artık medya oynatmadığında yayınlamanız gerekir.
Oturum durumu güncelleniyor
Medya oturumunuzdaki veriler oynatıcınızın durumuyla ilgili güncel olmalıdır. Örneğin, oynatma duraklatıldığında oynatma durumunu ve desteklenen işlemleri güncellemeniz gerekir. Aşağıdaki tablolarda, bilgi edinmekten sorumlu olduğunuz durumlar listelenmiştir.
MediaMeta Veri Uyumluluğu
Meta Veri Alanı | Açıklama |
---|---|
METADATA_KEY_TITLE (zorunlu) | Medya başlığı. |
METADATA_KEY_DISPLAY_SUBTITLE | Altyazı. |
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. |
OynatmaStateCompat
Gerekli Yöntem | Açıklama |
---|---|
setActions() | Desteklenen medya komutlarını ayarlar. |
setState() | Oynatma durumunu ve mevcut konumu ayarlayın. |
MedyaOturumu
Gerekli Yöntem | Açıklama |
---|---|
setTekrarMode() | Tekrarlamayı ayarlar. |
setMixedMode() | Karıştırma modunu ayarlar. |
setMeta() | Medya meta verilerini ayarlar. |
setplayState() | 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 denetimini kullanma
Uygulamanız medya oturumu aktarım kontrolü geri çağırmasını uygulamalıdır. Aşağıdaki tabloda, işlenmesi gereken taşıma kontrolü işlemleri gösterilmektedir:
MediaSessionCompat.Callback
İşlemler | Açıklama |
---|---|
onPlay() | Devam ettir |
onPause() | Duraklat |
onSeekTo() | Belirli bir konuma git |
onStop() | Mevcut medyayı durdur |
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ı ile bir niyet oluşturulur. Uygulamanız bunu işlemekten ve TV uygulaması başlatıldığında CastReceiverContext
nesnesinin bir örneğini oluşturmaktan sorumludur. CastReceiverContext
nesnesi, TV uygulaması çalışırken Yayın'la etkileşimde bulunmak için gereklidir. Bu nesne, TV uygulamanızın bağlı gönderenlerden gelen Cast medya mesajlarını kabul etmesini sağlar.
Android TV kurulumu
Başlatma amacı filtresi ekleme
Gönderen uygulamanızdan başlatma amacını 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
seçeneğinizdeki 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
öğesini sağlamak için kullanılır.
Yayın alıcısı bağlamı
Uygulamanız oluşturulduğunda CastReceiverContext
öğesini başlatın:
override fun onCreate() { CastReceiverContext.initInstance(this) ... }
@Override public void onCreate() { CastReceiverContext.initInstance(this); ... }
Uygulamanız ön plana geçtiğinde CastReceiverContext
öğesini başlatın:
CastReceiverContext.getInstance().start()
CastReceiverContext.getInstance().start();
Uygulama, video uygulamaları veya arka planda oynatmayı desteklemeyen uygulamalar için arka plana geçtikten sonra CastReceiverContext
adresinden stop()
numaralı telefonu arayın:
// Player has stopped. CastReceiverContext.getInstance().stop()
// Player has stopped. CastReceiverContext.getInstance().stop();
Ek olarak, uygulamanız arka planda oynatmayı destekliyorsa arka planda
oynatmayı durdurduğunda CastReceiverContext
üzerinden stop()
işlevini çağırın.
Özellikle yerel uygulamanızın birden fazla etkinliği varsa CastReceiverContext.start()
ve CastReceiverContext.stop()
aramalarını yönetmek için androidx.lifecycle
kitaplığındaki LifecycleObserver aracını kullanmanızı kesinlikle öneririz. Bu durum, farklı aktivitelerden start()
ve stop()
çağırdığınızda yarış koşulları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'ı MediaManager'a bağlama
Bir MediaSession
oluşturduğunuzda, komutların nereye gönderileceğini ve medya oynatma durumunu nereden alacağını bilmesi için mevcut MediaSession
jetonunu CastReceiverContext
alanına 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
videonuzu yayınladığı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ı desteklerse
uygulama arka plana gönderilirken CastReceiverContext.stop()
araması yapmak yerine yalnızca uygulamanız arka plandayken ve artık medya oynatmıyorken çağırmalısınız. Ö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'yı Cast Connect ile kullanma
Exoplayer
kullanıyorsanız değişiklikleri manuel olarak izlemek yerine oturumu ve oynatma durumu dahil tüm alakalı bilgileri otomatik olarak korumak için MediaSessionConnector
kullanabilirsiniz.
MediaSessionConnector.MediaButtonEventHandler
varsayılan olarak MediaSessionCompat.Callback
tarafından işlenen setMediaButtonEventHandler(MediaButtonEventHandler)
çağrısıyla MediaButton etkinliklerini işlemek için kullanılabilir.
MediaSessionConnector
uygulamasını uygulamanıza entegre etmek için oynatıcı etkinliği sınıfınıza veya medya oturumunuzu yönettiğiniz herhangi bir yere şunları 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ştir
Gönderen uygulamanızı Cast Connect desteğiyle güncelledikten sonra, LaunchOptions
üzerindeki androidReceiverCompatible
işaretini doğru değerine ayarlayarak uygulamanın hazır olduğunu beyan edebilirsiniz.
play-services-cast-framework
veya 19.0.0
ya da üzeri bir sürüm gerektirir.
androidReceiverCompatible
işareti LaunchOptions
bölgesinde ayarlanır (CastOptions
öğesinin bir parçasıdı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
veya üzeri v4.4.8
sürümü gerekir.
androidReceiverCompatible
işareti GCKLaunchOptions
bölgesinde ayarlandı (GCKCastOptions
öğesinin bir parçası):
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 gerektirir.
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ı Yayın Geliştirici Konsolu'na ekleyerek yayın uygulaması kimliğinizle ilişkilendirin.
Geliştirici cihazlarını kaydet
Geliştirme için kullanacağınız Android TV cihazının seri numarasını Cast Console'a kaydedin.
Cast Connect, güvenlik nedenleriyle yalnızca Google Play Store'dan yüklenen uygulamalarda çalışır.
Yayın veya Android TV cihazını yayınlama geliştirme amacıyla kaydettirme hakkında daha fazla bilgi için kayıt sayfasını inceleyin.
Medya yükleniyor
Android TV uygulamanızda derin bağlantı desteğini zaten uyguladıysanız Android TV Manifest'inizde yapılandırılmış benzer bir tanım olacaktı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önderende varlığa göre yükle
Gönderenlerde, yükleme isteğinin medya bilgilerindeki entity
öğesini 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 gerektirir.
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ı ile bir intent aracılığıyla gönderilir.
Gönderende ATV kimlik bilgileri ayarlanıyor
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ürütüyorsanız). Bu sorunu çözmek için Android TV'ye 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 gerektirir.
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ır. Ancak Android TV uygulamanız kullanıma sunulduğunda SDK, (belirtilmişse) entity
ve credentials
özelliklerini atvEntity
ve atvCredentials
parametrelerinizle 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 kullanıyorsanız veya daha ayrıntılı Medya Yükleme İsteği Verileri kullanıyorsanız Android TV uygulamanıza aşağıdaki önceden tanımlanmış amaç 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ükle özelliğine benzer şekilde içerik bilgilerinizle bir yükleme isteği oluşturabilir ve load()
öğesini arayabilirsiniz.
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 gerektirir.
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ğırmalarınızdaki amaçları ele almanız 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()
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 niyeti 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 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());
Yayınlama kontrol komutlarını destekleme
MediaSession
'te bulunmayan bazı skipAd()
komutlarını (ör. skipAd()
veya setActiveMediaTracks()
) kullanabilirsiniz.
Ayrıca, Yayınla sırası MediaSession
sırası ile tam olarak uyumlu olmadığından bazı sıra komutlarının uygulanması gerekir.
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());
Desteklenen medya komutlarını belirtin
Yayın alıcınızda olduğu gibi, Android TV uygulamanız hangi komutların desteklendiğini belirtmelidir. Böylece gönderenler belirli kullanıcı arayüzü kontrollerini etkinleştirebilir veya devre dışı bırakabilir. MediaSession
kapsamındaki komutlar için PlaybackStateCompat
içerisindeki komutları 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ü destekliyorsa 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 davrandığından emin olmanız gerekir. Örneğin, Android TV uygulamanız, Web Alıcı uygulamanızı desteklerken oynatma hızını değiştirmeyi desteklemiyorsa desteklenen işlemleri her platformda doğru şekilde yapmanız ve gönderen uygulamanızın kullanıcı arayüzünü doğru şekilde oluşturduğundan emin olmanız gerekir.
MedyaDurumunu Değiştirme
Parçalar, reklamlar, canlı ve sıraya alma gibi gelişmiş özellikleri desteklemek için Android TV uygulamanızın MediaSession
aracılığıyla belirlanamayan ek bilgiler sağlaması gerekir.
Bunun için MediaStatusModifier
sınıfını size sunuyoruz. MediaStatusModifier
her zaman CastReceiverContext
hizmetinde ayarladığınız MediaSession
ile çalışır.
Oluşturmak ve yayınlamak için
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();
İstemci kitaplığımız MediaSession
üzerinden temel MediaStatus
bilgisini alacak. Android TV uygulamanız ek bir durum belirtebilir ve durumu MediaStatus
değiştiricisiyle geçersiz kılabilir.
Bazı eyaletler ve meta veriler hem MediaSession
hem de MediaStatusModifier
içinde ayarlanabilir. Bunları yalnızca MediaSession
içinde ayarlamanızı kesinlikle öneririz. Yine de değiştiricide MediaSession
durumunu kullanmak için bu seçeneği kullanabilirsiniz. Bu durum, değiştiricideki durumun her zaman MediaSession
tarafından sağlanan değerlerden daha yüksek önceliğe sahip olması nedeniyle önerilmez.
Göndermeden önce MediaStatus'a müdahale etme
Web Alıcı SDK'sı ile aynı şekilde, göndermeden önce son rötuşları yapmak isterseniz gönderilecek bir MediaStatusInterceptor
belirterek MediaStatus
gönderilmesini sağlayabilirsiniz. MediaStatusWriter
Göndermeden önce MediaStatus
için değişiklik yaparız.
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 kullanma
Android TV uygulamanız yalnızca belirli kullanıcıların uygulama oturumu başlatmasına veya oturuma katılmasına izin verebilir. Örneğin, bir gönderenin yalnızca şu durumlarda başlatılmasına veya katılmasına izin verin:
- Gönderen uygulama, ATV uygulamasıyla aynı hesaba ve profile giriş yaptı.
- Gönderen uygulama aynı hesaba giriş yapmış ancak ATV uygulamasıyla farklı profil kullanıyor.
Uygulamanız birden fazla veya anonim kullanıcıyı işleyebiliyorsa ek kullanıcıların ATV oturumuna katılmasına izin verebilirsiniz. Kullanıcı kimlik bilgisi sağlarsa ilerleme durumunun ve diğer kullanıcı verilerinin doğru şekilde izlenebilmesi için ATV uygulamanızın kimlik bilgilerini işlemesi gerekir.
Gönderen uygulamanız Android TV uygulamanızı başlattığında veya bu uygulamaya katıldığında, gönderen uygulamanız oturuma kimlerin katıldığını gösteren kimlik bilgilerini sağlamalıdır.
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 denetleyicisi belirtebilirsiniz. Yayınlanmıyorsa Cast Connect SDK'sı Web Alıcınızı kullanmaya başlar.
Gönderen uygulama başlatma kimlik bilgisi verileri
Gönderen tarafında, oturuma kimlerin katılacağını temsil etmek için CredentialsData
öğesini belirtebilirsiniz.
credentials
, ATV uygulamanız anlayabildiği sürece kullanıcı tarafından tanımlanabilecek bir dizedir. credentialsType
, CredentialsData
platformunun hangi platformdan geldiğini belirtir veya özel bir değer olabilir. Varsayılan olarak, gönderen gönderen platforma ayarlanır.
CredentialsData
, Android TV uygulamanıza yalnızca başlatma veya katılma sırasında iletilir. Bağlıyken bu ayarı Android TV uygulamanıza iletme
yamazsınız. Gönderen kullanıcı bağlıyken profili değiştirirse oturumda kalabilir veya
yeni profilin oturumla uyumlu olmadığını düşünüyorsanız SessionManager.endCurrentCastSession(boolean stopCasting)
adlı kullanıcıyı arayabilirsiniz.
Her
gönderen için CredentialsData
CastReceiverContext
kullanılarak SenderInfo
almak için,
getCastLaunchRequest()
almak için
CastLaunchRequest
ve ardından
getCredentialsData()
alabilirsiniz.
play-services-cast-framework
veya 19.0.0
ya da üzeri 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
veya üzeri v4.7.0
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ı M87
veya daha yeni bir sürüm gerektirir.
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
Bir gönderen başlatmaya veya katılmaya çalıştığında CredentialsData
Android TV uygulamanıza iletilir. LaunchRequestChecker
uygulayabilirsiniz.
seçeneğini belirleyin.
İstek reddedilirse web TV'yi yerel olarak ATV uygulamasında başlatmak yerine yüklenir. ATV'niz başlatma veya katılım isteğinde bulunan kullanıcıyı yönetemiyorsa isteği reddetmeniz gerekir. ATV uygulamasına istekte bulunandan farklı bir kullanıcının giriş yapması ve uygulamanızın kimlik bilgilerini değiştirme işlemini gerçekleştirememesi veya şu anda ATV uygulamasına giriş yapmış bir kullanıcı olmaması olabilir.
Bir isteğe izin verilirse ATV uygulaması başlatılır. Bu davranışı, kullanıcı ATV uygulamasına giriş yapmamışsa veya bir kullanıcı uyumsuzluğu varsa uygulamanızın yükleme isteği göndermeyi destekleyip desteklemediğine bağlı olarak özelleştirebilirsiniz. Bu davranış, LaunchRequestChecker
içinde tamamen yapılandırılabilir.
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
bölümünde 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
aracındaki true
sonlandığında ATV uygulaması başlatılır ve false
Web Alıcı uygulamanızı başlatır.
Özel Mesaj Gönderme ve Alma
Yayın protokolü, gönderenler ve 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) kaydetmeniz gerekir.
Android TV - Özel Ad Alanı Belirtin
Desteklenen ad alanlarınızı kurulum sırasında CastReceiverOptions
bölümünde 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());