Bu sayfada, Android TV Alıcısı uygulamasını özelleştirmek için kullanabileceğiniz ö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ü dizininizin içindeki
build.gradle
dosyasını açın. -
google()
politikasının, listelenenrepositories
kapsamına girdiğini doğrulayın.repositories { google() }
-
Uygulamanız için hedef cihaz türünüze bağlı olarak kitaplıkların en son 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.0.1' implementation 'com.google.android.gms:play-services-cast:21.4.0' }
-
Android Sender uygulaması için:
dependencies { implementation 'com.google.android.gms:play-services-cast:21.0.1' implementation 'com.google.android.gms:play-services-cast-framework:21.4.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
ayarınızıngoogle-cast-sdk
4.8.0 veya sonraki bir sürümü hedeflediğinden emin olun -
iOS 13 veya sonraki sürümleri hedefleyin. Diğer ayrıntılar için Sürüm Notları'na göz atın.
platform: ios, '13' def target_pods pod 'google-cast-sdk', '~>4.8.0' end
- Chromium tarayıcı M87 veya sonraki bir sürümünü gerektirir.
-
Web Sender API kitaplığını
<script src="//www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
projenize ekleyin
AndroidX gereksinimi
Google Play Hizmetleri'nin yeni sürümleri, androidx
ad alanını kullanmak için bir uygulamanın güncellenmesini gerektirir. AndroidX'e taşıma talimatlarını uygulayın.
Android TV uygulaması - ön koşullar
Android TV uygulamanızda Cast Connect'i desteklemek için 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 ayrıca Cast Connect kitaplığı tarafından bir gönderenden duraklatma gibi belirli mesajlar aldığında sinyal vermek için 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 bir medya oturumu oluşturmalı ve artık kontrol edilemediğinde yayınlamalıdır. Örneğin, uygulamanız bir video uygulamasıysa, kullanıcı oynatma etkinliğinden çıktığında oturumu serbest bırakmanız gerekir. Bunun için diğer içeriğe göz atmak için "geri"yi seçmeniz veya uygulamayı arka plana almanız gerekir. Uygulamanız bir müzik uygulamasıysa uygulamanız hiçbir medyayı oynatmadığında bu uygulamayı yayınlamanı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, hangi durumları güncel tutmaktan sorumlu olduğunuz listelenmiştir.
MediaMetadataCompat
Meta Veri Alanı | Açıklama |
---|---|
METADATA_KEY_TITLE (gerekli) | Medya başlığı. |
METADATA_KEY_DISPLAY_SUBTITLE | Altyazı. |
METADATA_KEY_DISPLAY_ICON_URI | Simge URL'si. |
METADATA_KEY_DURATION (gerekli) | Medya süresi. |
METADATA_KEY_MEDIA_URI | İçerik Kimliği. |
METADATA_KEY_ARTIST | Sanatçı. |
METADATA_KEY_ALBUM | Albüm. |
PlaybackStateCompat
Gerekli Yöntem | Açıklama |
---|---|
setActions() | Desteklenen medya komutlarını ayarlar. |
setState() | Çalma durumunu ve mevcut konumu ayarlayın. |
MediaSessionCompat
Gerekli Yöntem | Açıklama |
---|---|
setRepeatMode() | Tekrar 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 hangi aktarım denetimi işlemlerini gerçekleştirmeleri gerektiği gösterilmiştir:
MediaSessionCompat.Callback
İşlemler | Açıklama |
---|---|
onPlay() | Devam ettir |
onPause() | Duraklat |
onSeekTo() | Belirli bir konuma sar |
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
Bir gönderen uygulama tarafından başlatma isteği gönderildiğinde, uygulama ad alanına sahip bir amaç oluşturulur. Uygulamanız, TV uygulaması başlatıldığında bunu ele almaktan ve CastReceiverContext
nesnesinin bir örneğini oluşturmaktan sorumludur. TV uygulaması çalışırken Yayınla etkileşimde bulunmak için CastReceiverContext
nesnesi gerekir. Bu nesne, TV uygulamanızın bağlı gönderenlerden gelen yayın medya mesajlarını kabul etmesini sağlar.
Android TV kurulumu
Başlatma amacı filtresi ekleme
Gönderen uygulamanızdan başlatma amacını 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ı belirtin
CastReceiverOptions
aşağıdakileri 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
içinde seçenek sağlayıcısını 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ıldığında CastReceiverOptions
sağlamak için ReceiverOptionsProvider
kullanılır.
Yayın alıcı bağlamı
Uygulamanız oluşturulduğunda CastReceiverContext
'i 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();
Arka planda oynatmayı desteklemeyen video uygulamaları veya uygulamalar için uygulama arka plana geçtikten sonra CastReceiverContext
numaralı telefondan stop()
numaralı telefonu arayı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
'den stop()
çağrısı yapı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, farklı etkinliklerden start()
ve stop()
çağrılarını yaptığınızda yarış koşullarının önüne geçer.
// 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 durumunu alacağını bilmesi için CastReceiverContext
adlı iş ortağına geçerli 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()
çağrısını yapmak yerine yalnızca uygulamanız arka plandayken
medya çalmı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'ı Cast Connect ile birlikte kullanma
Exoplayer
kullanıyorsanız değişiklikleri manuel olarak izlemek yerine oturumu ve oynatma durumu dahil tüm ilgili bilgileri otomatik olarak yönetmek için MediaSessionConnector
özelliğini kullanabilirsiniz.
MediaSessionConnector.MediaButtonEventHandler
, varsayılan olarak MediaSessionCompat.Callback
tarafından işlenen setMediaButtonEventHandler(MediaButtonEventHandler)
yöntemini çağırarak MediaButton etkinliklerini işlemek için kullanılabilir.
MediaSessionConnector
uygulamasını uygulamanıza entegre etmek için aşağıdakileri oynatıcı etkinlik sınıfınıza veya medya oturumunuzu yönettiğiniz yere
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 true olarak ayarlayarak uygulamanın kullanıma hazır olduğunu beyan edebilirsiniz.
play-services-cast-framework
19.0.0
veya sonraki bir sürümü gerektirir.
androidReceiverCompatible
işareti, CastOptions
öğesinin parçası olan LaunchOptions
bölgesinde 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 sonraki bir sürümü gerektirir.
androidReceiverCompatible
işareti, GCKCastOptions
öğesinin parçası olan GCKLaunchOptions
bölgesinde 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 sonraki 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ı Cast Uygulaması Kimliğinizle ilişkilendirmek için Cast Developer Console'da paket adını ekleyin.
Geliştirici cihazlarını kaydetme
Geliştirme için kullanacağınız Android TV cihazının seri numarasını Cast Developer Console'da kaydedin.
Kayıt olmadan, Cast Connect güvenlik nedeniyle yalnızca Google Play Store'dan yüklenen uygulamalarda çalışır.
Cast veya Android TV cihazını Cast geliştirmesi için kaydettirme hakkında daha fazla bilgi edinmek istiyorsanız kayıt sayfasına bakın.
Medya yükleniyor
Android TV uygulamanızda derin bağlantı desteğini daha önce uyguladıysanız Android TV Manifest'inizde de 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 varlığa göre yükle
Gönderenlerde, yükleme isteği için medya bilgilerinde entity
özelliğini ayarlayarak derin bağlantıyı aktarabilirsiniz:
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 sonraki 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ını içeren bir niyet aracılığıyla gönderilir.
Gönderende ATV kimlik bilgilerini ayarlama
Web Alıcısı uygulamanız ve Android TV uygulamanızın farklı derin bağlantıları ve credentials
'yi desteklemesi mümkündür (örneğin, kimlik doğrulamasını iki platformda farklı bir şekilde yürütüyorsanız). Bu sorunu gidermek üzere 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 sonraki 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ılır. Ancak Android TV uygulamanız başlatılırsa SDK, entity
ve credentials
değerlerini atvEntity
ve atvCredentials
(belirtilmişse) ile geçersiz kılar.
Content ID veya MediaQueueData ile yükleniyor
entity
veya atvEntity
kullanmıyorsanız ve Medya Bilgilerinizde Content ID ya da İçerik URL'si 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, varlığa göre yükleme işlemine benzer şekilde, içerik bilgilerinizle bir yükleme isteği oluşturabilir ve load()
işlevini ç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 sonraki 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ük 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ı 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()
yöntemini çağırır.
Yükleme isteğini işlemek için bu yöntemi geçersiz kılmanız gerekir. MediaManager.onNewIntent()
çağrılmadan önce geri çağırmanın kaydedilmesi gerekir (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 (yükleme istekleri için MediaLoadRequestData
) ayrıştırabilirsiniz.
Medya komutlarını destekleme
Temel oynatma kontrolü desteği
Temel entegrasyon komutları, medya oturumuyla uyumlu olan komutları içerir. Bu komutlar, medya oturumu geri çağırmalarıyla bildirilir. Bunu desteklemek için bir 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ın kontrol komutlarını destekleme
MediaSession
ürününde kullanılamayan skipAd()
veya setActiveMediaTracks()
gibi bazı Cast komutları mevcuttur.
Ayrıca, Yayınlama sırası MediaSession
sırası ile tam olarak uyumlu olmadığından bazı sıra komutlarının burada 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ı belirtme
Yayın alıcınızda olduğu gibi, gönderenlerin belirli kullanıcı arayüzü kontrollerini etkinleştirebilmesi veya devre dışı bırakabilmesi için Android TV uygulamanız hangi komutların desteklendiğini belirtmelidir. MediaSession
parçası olan komutlar için PlaybackStateCompat
içinde 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ü, Web Alıcı uygulamanız ise 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ısı uygulamanız oynatırken oynatma hızını değiştirmeyi desteklemiyorsa, her platformda desteklenen işlemleri doğru şekilde ayarlamanız ve gönderen uygulamanızın, kullanıcı arayüzünü doğru oluşturduğundan emin olmanız gerekir.
MediaStatus değiştiriliyor
Android TV uygulamanızın; parçalar, reklamlar, canlı yayınlar ve sıraya ekleme gibi gelişmiş özellikleri desteklemesi için MediaSession
ile tespit edilemeyen ek bilgiler sağlaması gerekir.
Bunu başarmanız için MediaStatusModifier
sınıfını sağlıyoruz. MediaStatusModifier
her zaman CastReceiverContext
içinde ayarladığınız MediaSession
üzerinde çalışır.
MediaStatus
oluşturup 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, MediaSession
kaynağından temel MediaStatus
değerini alır. Android TV uygulamanız ise bir MediaStatus
değiştiricisi aracılığıyla ek durum belirtebilir ve 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, MediaSession
içindeki durumları geçersiz kılmak için kullanmaya devam edebilirsiniz. Değiştiricideki durum, MediaSession
tarafından sağlanan değerlerden her zaman daha yüksek önceliğe sahip olduğu için bu önerilmez.
Göndermeden önce MediaStatus'a müdahale etme
Web Recipientr SDK'sında olduğu gibi, projeyi göndermeden önce son rötuşları yapmak isterseniz gönderilecek MediaStatus
öğesini işlemek için bir MediaStatusInterceptor
belirtebilirsiniz. MediaStatus
öğeyi gönderilmeden önce değiştirmek için 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 uygulamaya katılmasına izin veriyor olabilir. Örneğin, yalnızca aşağıdaki durumlarda gönderenin başlatmasına veya katılmasına izin verin:
- Gönderen uygulama, ATV uygulamasıyla aynı hesaba ve profile giriş yapmış olmalıdır.
- Gönderen uygulama, ATV uygulamasıyla aynı hesaba ancak farklı bir profile giriş yapmış.
Uygulamanız birden fazla veya anonim kullanıcıyı işleyebiliyorsa başka herhangi bir kullanıcının ATV oturumuna katılmasına izin verebilirsiniz. Kullanıcı kimlik bilgisi sağlarsa ATV uygulamanızın, ilerleme durumunun ve diğer kullanıcı verilerinin doğru şekilde izlenebilmesi için bu kullanıcının kimlik bilgilerini işlemesi gerekir.
Gönderen uygulamanız, Android TV uygulamanızı başlattığında veya uygulamaya katıldığında, gönderen uygulamanız oturuma kimlerin katıldığını temsil eden 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. Aksi takdirde, Cast Connect SDK'sı Web Alıcınızı başlatmaya geri döner.
Gönderenin uygulama başlatma kimlik bilgileri verileri
Gönderen tarafında, oturuma kimlerin katıldığını temsil etmek 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
öğesinin hangi platformdan geldiğini tanımlar veya özel bir değer olabilir. Varsayılan olarak, verinin gönderildiği platforma ayarlanır.
CredentialsData
, Android TV uygulamanıza yalnızca başlatma veya katılma zamanı sırasında aktarılır. Bağlı durumdayken tekrar ayarlarsanız bu kimlik, Android TV uygulamanıza iletilmez. 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önderen için CredentialsData
,
CastReceiverContext
üzerinden
getSenders
kullanarak alınabilir. SenderInfo
,
getCastLaunchRequest()
ve ardından
CastLaunchRequest
,
ardından getCredentialsData()
.
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.0
veya sonraki bir sürümü gerektirir.
Seçenekler belirlendikten 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 sonraki bir sürümü gerektirir.
Seçenekler belirlendikten 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 denetleyiciyi uygulama
Bir gönderen uygulamayı başlatmaya veya uygulamaya katılmaya çalıştığında CredentialsData
Android TV uygulamanıza aktarılır. LaunchRequestChecker
uygulayabilirsiniz.
bu isteği kabul edebilir veya reddedebilirsiniz.
Bir istek reddedilirse ATV uygulamasına yerel olarak başlatmak yerine Web Alıcısı yüklenir. ATV'niz, başlatma veya katılma isteğinde bulunan kullanıcıyı işleyemiyorsa isteği reddetmelisiniz. İstekte bulunandan farklı bir kullanıcının ATV uygulamasına giriş yapmış olması ve uygulamanızın geçiş kimlik bilgilerini işleyememesi veya ATV uygulamasına giriş yapmış bir kullanıcının olmaması buna örnek olarak gösterilebilir.
Bir isteğe izin veriliyorsa ATV uygulaması başlatılır. Uygulamanızın, ATV uygulamasına giriş yapmamışken yükleme istekleri göndermeyi destekleyip desteklemediğine veya kullanıcı uyuşmazlığına bağlı olarak bu davranışı özelleştirebilirsiniz. Bu davranış, LaunchRequestChecker
içinde 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
hesabını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ı başlatılır ve false
Web Alıcı uygulamanız başlatılır.
Özel Mesaj Gönderme ve Alma
Cast protokolü, gönderenlerle alıcı uygulamanız arasında özel dize mesajları göndermenizi sağlar. CastReceiverContext
cihazınızı 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
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());