Bu geliştirici kılavuzunda, Android Gönderen SDK'sını kullanarak Android gönderen uygulamanıza Google Cast desteğinin nasıl ekleneceği açıklanmaktadır.
Mobil cihaz veya dizüstü bilgisayar, oynatmayı kontrol eden gönderen, Google Cast cihazı ise içeriği TV'de gösteren Alıcı'dır.
Gönderen çerçevesi, Cast sınıfı kitaplık ikili programını ve gönderende çalışma zamanında mevcut ilişkili kaynakları belirtir. Gönderen uygulaması veya Yayın uygulaması, gönderen üzerinde de çalışan bir uygulamayı ifade eder. Web Alıcısı uygulaması, Cast uyumlu cihazda çalışan HTML uygulamasını belirtir.
Gönderen çerçevesi, gönderenleri etkinlikler konusunda bilgilendirmek ve Cast uygulama yaşam döngüsünün çeşitli durumları arasında geçiş yapmak için eşzamansız bir geri çağırma tasarımı kullanır.
Uygulama akışı
Aşağıdaki adımlarda, gönderenin Android uygulaması için genel üst düzey yürütme akışı açıklanmaktadır:
- Yayın çerçevesi,
Activity
yaşam döngüsüne göre otomatik olarakMediaRouter
cihaz keşfini başlatır. - Kullanıcı, Yayınla düğmesini tıkladığında çerçeve, Yayınlama iletişim kutusunu keşfedilen Yayın cihazlarının listesiyle sunar.
- Kullanıcı bir Yayın cihazı seçtiğinde çerçeve, Yayın cihazında Web Alıcısı uygulamasını başlatmayı dener.
- Çerçeve, Web Alıcısı uygulamasının başlatıldığını onaylamak için gönderen uygulamasında geri çağırmaları çağırır.
- Bu çerçeve, gönderen ile Web Alıcısı uygulamaları arasında bir iletişim kanalı oluşturur.
- Çerçeve, Web Alıcısı'nda medya oynatmasını yüklemek ve kontrol etmek için iletişim kanalını kullanır.
- Çerçeve, gönderen ile Web Alıcısı'nın medya oynatma durumunu senkronize eder: Kullanıcı, gönderen kullanıcı arayüzü işlemlerini yaptığında, çerçeve bu medya kontrolü isteklerini Web Alıcı'ya iletir ve Web Alıcısı, medya durumu güncellemelerini gönderdiğinde çerçeve de gönderen kullanıcı arayüzünün durumunu günceller.
- Kullanıcı, Yayın cihazıyla olan bağlantısını kesmek için Yayın düğmesini tıkladığında çerçeve, gönderen uygulamanın Web Alıcısı ile bağlantısını keser.
Google Cast Android SDK'sındaki tüm sınıfların, yöntemlerin ve etkinliklerin kapsamlı bir listesini Android için Google Cast Gönderen API'si Referansı'nda bulabilirsiniz. Aşağıdaki bölümlerde, Google Cast'i Android uygulamanıza eklemek için uygulanması gereken adımlar açıklanmaktadır.
Android manifest'ini yapılandırın
Uygulamanızın AndroidManifest.xml dosyası, Cast SDK'sı için aşağıdaki öğeleri yapılandırmanız gerekir:
kullanımlar-sdk
Cast SDK'sının desteklediği minimum ve Android API düzeylerini hedefleyin. Şu anda minimum API düzeyi 21 ve hedef API düzeyi 28'dir.
<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="28" />
android:tema
Uygulamanızın temasını minimum Android SDK sürümüne göre belirleyin. Örneğin, kendi temanızı uygulamıyorsanız Lollipop öncesi minimum Android SDK sürümünü hedeflerken Theme.AppCompat
değişkenini kullanmanız gerekir.
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat" >
...
</application>
Yayın Bağlamını İlk Kullanıma Hazırlama
Çerçevede, çerçevenin tüm etkileşimlerini koordine eden küresel bir tekli nesne (CastContext
) bulunur.
CastContext
tek programını başlatmak için gereken seçenekleri sağlamak üzere uygulamanız OptionsProvider
arayüzünü uygulamalıdır. OptionsProvider
, çerçevenin davranışını etkileyen seçenekleri içeren bir CastOptions
örneği sağlar. Bunlar arasından en önemlisi, keşif sonuçlarını filtrelemek ve bir Yayın oturumu başlatıldığında Web Alıcısı uygulamasını başlatmak için kullanılan Web Alıcı uygulama kimliğidir.
class CastOptionsProvider : OptionsProvider { override fun getCastOptions(context: Context): CastOptions { return Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .build() } override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? { return null } }
public class CastOptionsProvider implements OptionsProvider { @Override public CastOptions getCastOptions(Context context) { CastOptions castOptions = new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .build(); return castOptions; } @Override public List<SessionProvider> getAdditionalSessionProviders(Context context) { return null; } }
Uygulanan OptionsProvider
öğesinin tam adını, gönderen uygulamanın AndroidManifest.xml dosyasında meta veri alanı olarak bildirmeniz gerekir:
<application>
...
<meta-data
android:name=
"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.foo.CastOptionsProvider" />
</application>
CastContext
, CastContext.getSharedInstance()
çağrıldığında geç başlatılır.
class MyActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { val castContext = CastContext.getSharedInstance(this) } }
public class MyActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { CastContext castContext = CastContext.getSharedInstance(this); } }
Cast Kullanıcı Deneyimi Widget'ları
Yayın çerçevesi, Yayın Tasarımı Kontrol Listesi'ne uyan widget'lar sağlar:
Tanıtım Yer Paylaşımı: Çerçeve, bir alıcı ilk kez sunulduğunda Yayınla düğmesine dikkat etmesi gereken kullanıcıya gösterilen özel bir Görünüm (
IntroductoryOverlay
) sağlar. Gönderen uygulaması başlık metninin metnini ve konumunu özelleştirebilir.Yayın Düğmesi: Bir alıcı, uygulamanızı destekleyen bir uygulama keşfedildiğinde Yayınla düğmesi görünür. Kullanıcı, Yayınla düğmesini ilk kez tıkladığında, bulunan cihazları listeleyen bir Yayın iletişim kutusu görüntülenir. Kullanıcı, cihaz bağlıyken Yayınla düğmesini tıkladığında başlık, kayıt stüdyosu adı ve küçük resim gibi geçerli medya meta verilerini gösterir veya kullanıcının Yayın cihazıyla bağlantısını kesmesine izin verir.
Mini Denetleyici: Kullanıcı içerik yayınlarken geçerli içerik sayfasından veya genişletilmiş kumandadan gönderen uygulamasında başka bir ekrana gittiğinde, kullanıcının en son yayınlanan medya meta verilerini görmesine ve oynatmayı kontrol etmesine olanak tanımak için ekranın alt kısmında mini kumanda görüntülenir.
Genişletilmiş Denetleyici: Kullanıcı içerik yayınlarken medya bildirimini veya mini kumandayı tıklarsa genişletilmiş denetleyici açılır ve şu anda oynatılan medya meta verilerini gösterir ve medya oynatmayı kontrol etmek için birkaç düğme sağlar.
Bildirim: Yalnızca Android. Kullanıcı içerik yayınladığında ve gönderen uygulamasından ayrıldığında, o anda yayınlanmakta olan medya meta verilerini ve oynatma kontrollerini gösteren bir medya bildirimi görüntülenir.
Kilit Ekranı: Yalnızca Android. Kullanıcı içerik yayınlarken ve kilit ekranına gittiğinde (veya cihaz zaman aşımına uğradığında) o anda yayın yapan medya meta verilerini ve oynatma kontrollerini gösteren bir medya kilidi ekranı kontrolü görüntülenir.
Aşağıdaki kılavuzda, bu widget'ları uygulamanıza nasıl ekleyeceğinizle ilgili açıklamalar yer almaktadır.
Yayın düğmesi ekle
Android MediaRouter
API'leri, ikincil cihazlarda medya görüntülemeyi ve oynatmayı etkinleştirmek için tasarlanmıştır.
MediaRouter
API kullanan Android uygulamaları, kullanıcıların Yayın cihazı gibi ikincil bir cihazda medya oynatmak için medya yolu seçmesine olanak tanımak amacıyla kullanıcı arayüzünün bir parçasında Yayın düğmesi içermelidir.
Çerçeve, MediaRouteButton
'i Cast button
olarak eklemeyi oldukça kolaylaştırır. İlk olarak, menünüzü tanımlayan xml dosyasına bir menü öğesi veya bir MediaRouteButton
eklemeniz ve bunu çerçeveye bağlamak için CastButtonFactory
öğesini kullanmanız gerekir.
// To add a Cast button, add the following snippet.
// menu.xml
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always" />
// Then override the onCreateOptionMenu() for each of your activities. // MyActivity.kt override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.main, menu) CastButtonFactory.setUpMediaRouteButton( applicationContext, menu, R.id.media_route_menu_item ) return true }
// Then override the onCreateOptionMenu() for each of your activities. // MyActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.main, menu); CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, R.id.media_route_menu_item); return true; }
Ardından, Activity
öğeniz FragmentActivity
mülkünden devralınıyorsa düzeninize MediaRouteButton
ekleyebilirsiniz.
// activity_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal" >
<androidx.mediarouter.app.MediaRouteButton
android:id="@+id/media_route_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:mediaRouteTypes="user"
android:visibility="gone" />
</LinearLayout>
// MyActivity.kt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_layout) mMediaRouteButton = findViewById<View>(R.id.media_route_button) as MediaRouteButton CastButtonFactory.setUpMediaRouteButton(applicationContext, mMediaRouteButton) mCastContext = CastContext.getSharedInstance(this) }
// MyActivity.java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_layout); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), mMediaRouteButton); mCastContext = CastContext.getSharedInstance(this); }
Yayınla düğmesinin görünümünü bir tema kullanarak ayarlamak için Yayın Düğmesini Özelleştir konusuna bakın.
Cihaz keşfini yapılandırma
Cihaz keşfi tamamen CastContext
tarafından yönetilir.
CastContext'i başlatırken, gönderen uygulama Web Alıcısı uygulama kimliğini belirtir ve isteğe bağlı olarak, CastOptions
'te supportedNamespaces
'yi ayarlayarak ad alanı filtrelemesi isteyebilir.
CastContext
, dahili olarak MediaRouter
referansı içerir ve gönderen uygulaması ön plana girdiğinde keşif sürecini başlatır ve gönderen uygulama arka plana geçtiğinde durur.
class CastOptionsProvider : OptionsProvider { companion object { const val CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace" } override fun getCastOptions(appContext: Context): CastOptions { val supportedNamespaces: MutableList<String> = ArrayList() supportedNamespaces.add(CUSTOM_NAMESPACE) return CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setSupportedNamespaces(supportedNamespaces) .build() } override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? { return null } }
class CastOptionsProvider implements OptionsProvider { public static final String CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace"; @Override public CastOptions getCastOptions(Context appContext) { List<String> supportedNamespaces = new ArrayList<>(); supportedNamespaces.add(CUSTOM_NAMESPACE); CastOptions castOptions = new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setSupportedNamespaces(supportedNamespaces) .build(); return castOptions; } @Override public List<SessionProvider> getAdditionalSessionProviders(Context context) { return null; } }
Oturum yönetiminin işleyiş şekli
Google Cast SDK'sı, bir Cihaza bağlanma, bir Web Alıcısı uygulaması başlatma (ya da birleştirme), bu uygulamaya bağlanma ve medya kontrol kanalı başlatma adımlarını birleştiren Yayın oturumu kavramını tanımlar. Yayınlama oturumları ve Web Alıcı yaşam döngüsü hakkında daha fazla bilgi için Web Alıcısı'na Uygulama yaşam döngüsü kılavuzuna bakın.
Oturumlar, uygulamanızın CastContext.getSessionManager()
üzerinden erişebileceği SessionManager
sınıfı tarafından yönetilir.
Her oturum, Session
sınıfının alt sınıflarıyla temsil edilir.
Örneğin, CastSession
, Yayın cihazlarıyla yapılan oturumları temsil eder. Uygulamanız şu anda etkin olan Yayın oturumuna SessionManager.getCurrentCastSession()
üzerinden erişebilir.
Uygulamanız oluşturma, askıya alma, devam ettirme ve sonlandırma gibi oturum etkinliklerini izlemek için SessionManagerListener
sınıfını kullanabilir. Çerçeve, bir oturum etkinken otomatik olarak anormal/ani sonlandırma şeklinde devam eder.
Oturumlar, MediaRouter
iletişim kutularından kullanıcı hareketlerine göre otomatik olarak oluşturulur ve silinir.
Uygulamalar, yayınlama başlatma hatalarını daha iyi anlamak için
CastContext#getCastReasonCodeForCastStatusCode(int)
kullanarak
oturum başlatma hatasını CastReasonCodes
'e dönüştürebilir.
Lütfen bazı oturum başlatma hatalarının (ör. CastReasonCodes#CAST_CANCELLED
) amaçlanan davranışlar olduğunu ve hata olarak günlüğe kaydedilmemesi gerektiğini unutmayın.
Oturumun durum değişikliklerinden haberdar olmanız gerekirse bir SessionManagerListener
uygulayabilirsiniz. Bu örnekte, bir Activity
'nin CastSession
kullanılabilirliği gösterilmektedir.
class MyActivity : Activity() { private var mCastSession: CastSession? = null private lateinit var mCastContext: CastContext private lateinit var mSessionManager: SessionManager private val mSessionManagerListener: SessionManagerListener<CastSession> = SessionManagerListenerImpl() private inner class SessionManagerListenerImpl : SessionManagerListener<CastSession?> { override fun onSessionStarting(session: CastSession?) {} override fun onSessionStarted(session: CastSession?, sessionId: String) { invalidateOptionsMenu() } override fun onSessionStartFailed(session: CastSession?, error: Int) { val castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error) // Handle error } override fun onSessionSuspended(session: CastSession?, reason Int) {} override fun onSessionResuming(session: CastSession?, sessionId: String) {} override fun onSessionResumed(session: CastSession?, wasSuspended: Boolean) { invalidateOptionsMenu() } override fun onSessionResumeFailed(session: CastSession?, error: Int) {} override fun onSessionEnding(session: CastSession?) {} override fun onSessionEnded(session: CastSession?, error: Int) { finish() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mCastContext = CastContext.getSharedInstance(this) mSessionManager = mCastContext.sessionManager } override fun onResume() { super.onResume() mCastSession = mSessionManager.currentCastSession mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java) } override fun onPause() { super.onPause() mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession::class.java) mCastSession = null } }
public class MyActivity extends Activity { private CastContext mCastContext; private CastSession mCastSession; private SessionManager mSessionManager; private SessionManagerListener<CastSession> mSessionManagerListener = new SessionManagerListenerImpl(); private class SessionManagerListenerImpl implements SessionManagerListener<CastSession> { @Override public void onSessionStarting(CastSession session) {} @Override public void onSessionStarted(CastSession session, String sessionId) { invalidateOptionsMenu(); } @Override public void onSessionStartFailed(CastSession session, int error) { int castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error); // Handle error } @Override public void onSessionSuspended(CastSession session, int reason) {} @Override public void onSessionResuming(CastSession session, String sessionId) {} @Override public void onSessionResumed(CastSession session, boolean wasSuspended) { invalidateOptionsMenu(); } @Override public void onSessionResumeFailed(CastSession session, int error) {} @Override public void onSessionEnding(CastSession session) {} @Override public void onSessionEnded(CastSession session, int error) { finish(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCastContext = CastContext.getSharedInstance(this); mSessionManager = mCastContext.getSessionManager(); } @Override protected void onResume() { super.onResume(); mCastSession = mSessionManager.getCurrentCastSession(); mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class); } @Override protected void onPause() { super.onPause(); mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class); mCastSession = null; } }
Akış aktarma
Oturum durumunu korumak, kullanıcıların ses komutlarını, Google Home uygulamasını veya akıllı ekranları kullanarak mevcut ses ve video akışlarını cihazlar arasında taşıyabileceği akış aktarımının temelini oluşturur. Medya, bir cihazda (kaynak) oynamayı durdurur ve başka bir cihazda (hedef) devam eder. En son donanım yazılımına sahip tüm Yayın cihazları, akış aktarımında kaynak veya hedef işlevi görebilir.
Akış aktarma veya genişletme işlemi sırasında yeni hedef cihazı almak için CastSession#addCastListener
kullanarak Cast.Listener
kaydedin.
Ardından, onDeviceNameChanged
geri çağırması sırasında CastSession#getCastDevice()
numaralı telefonu arayın.
Daha fazla bilgi için Web Alıcısı üzerinden akış aktarma bölümüne göz atın.
Otomatik yeniden bağlanma
Çerçeve bir ReconnectionService
sağlar. Gönderen uygulama, bağlantıyı yeniden başlatmak için bu uygulamayı etkinleştirebilir. Örneğin:
- Geçici kablosuz ağ bağlantısı kaybından kurtulma
- Cihaz uykusundan kurtar
- Uygulamayı arka planda kurtarın
- Uygulama kilitlendiyse kurtarma
Bu hizmet varsayılan olarak etkindir ve CastOptions.Builder
bölümünden devre dışı bırakılabilir.
Gradle dosyanızda otomatik birleştirme etkinleştirilmişse bu hizmet otomatik olarak uygulamanızın manifest dosyasında birleştirilebilir.
Çerçeve, bir medya oturumu olduğunda hizmeti başlatır ve medya oturumu sona erdiğinde hizmeti durdurur.
Medya Kontrolü'nün işleyiş şekli
Yayın çerçevesi, RemoteMediaPlayer
sınıfını Cast 2.x sürümünden kaldıracak şekilde, yeni bir sınıf yerine RemoteMediaClient
kullanıma sundu. Bu API, aynı işlevi daha rahat API'ler içerisinde sunan ve GoogleApiClient iletimi yapmaktan kaçınan bir sınıf.
Uygulamanız, medya ad alanını destekleyen bir Web Alıcısı uygulaması ile CastSession
kurduğunda çerçeve tarafından otomatik olarak bir RemoteMediaClient
örneği oluşturulur. Uygulamanız, CastSession
örneğinde getRemoteMediaClient()
yöntemini çağırarak buna erişebilir.
Web Alıcısına istek gönderen tüm RemoteMediaClient
yöntemleri, bu isteği izlemek için kullanılabilecek bir pendingResult nesnesi döndürür.
RemoteMediaClient
örneğinin, uygulamanızın birden fazla parçası ve hatta kalıcı mini kumandalar ve bildirim hizmeti gibi çerçevenin bazı dahili bileşenleri tarafından paylaşılması beklenir.
Bu amaçla, bu örnek birden fazla RemoteMediaClient.Listener
kaydının kaydedilmesini destekler.
Medya meta verilerini ayarlama
MediaMetadata
sınıfı, yayınlamak istediğiniz medya öğesi hakkındaki bilgileri temsil eder. Aşağıdaki örnek, bir filmin yeni MediaMetale örneğini oluşturur ve başlığı, alt başlığı ve iki görüntüyü ayarlar.
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE) movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle()) movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio()) movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(0)))) movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(1))))
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE); movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle()); movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio()); movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(0)))); movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(1))));
Medya meta verileriyle resim kullanımı hakkında Resim Seçimi bölümüne göz atın.
Medya yükle
Uygulamanız, aşağıdaki kodda gösterildiği gibi bir medya öğesi yükleyebilir. İlk olarak, MediaInfo
örneğini oluşturmak için medyanın meta verileriyle MediaInfo.Builder
kullanın. Mevcut CastSession
öğesinden RemoteMediaClient
öğesini alın, ardından MediaInfo
öğesini bu RemoteMediaClient
öğesine yükleyin. Medya Alıcısı'nda çalışan bir medya oynatıcı uygulamasını oynatmak, duraklatmak ve
başka şekilde kontrol etmek için RemoteMediaClient
kullanın.
val mediaInfo = MediaInfo.Builder(mSelectedMedia.getUrl()) .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setContentType("videos/mp4") .setMetadata(movieMetadata) .setStreamDuration(mSelectedMedia.getDuration() * 1000) .build() val remoteMediaClient = mCastSession.getRemoteMediaClient() remoteMediaClient.load(MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build())
MediaInfo mediaInfo = new MediaInfo.Builder(mSelectedMedia.getUrl()) .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setContentType("videos/mp4") .setMetadata(movieMetadata) .setStreamDuration(mSelectedMedia.getDuration() * 1000) .build(); RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); remoteMediaClient.load(new MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build());
Ayrıca, medya parçalarını kullanma ile ilgili bölüme bakın.
4K video biçimi
Medyanızın hangi video biçimini kontrol ettiğini öğrenmek için MediaStatus'da getVideoInfo()
kullanarak mevcut VideoInfo
örneğini alın.
Bu örnekte HDR TV biçiminin türü ile ekran yüksekliği ve genişliğinin piksel cinsinden ifadesi bulunmaktadır. 4K biçimindeki varyantlar sabit sayılarla HDR_TYPE_*
gösterilir.
Birden fazla cihaza uzaktan kumanda bildirimleri
Bir kullanıcı içerik yayınlarken aynı ağdaki diğer Android cihazlar da oynatmayı kontrol etmeleri için bildirim alır. Cihazı bu tür bildirimleri alan herkes, Google'da Ayarlar uygulaması > Google Cast > Uzaktan kumanda bildirimlerini göster bölümünden bu cihaz için bildirimleri kapatabilir. (Bildirimlerde, Ayarlar uygulamasının bir kısayolu bulunur.) Daha ayrıntılı bilgi için Uzaktan kumandayı yayınlama bildirimleri bölümüne bakın.
Mini kumanda ekle
Yayın Tasarımı Kontrol Listesi'ne göre, bir gönderen uygulaması, kullanıcı mevcut içerik sayfasından ayrıldığında, gönderenin uygulamasının başka bir bölümüne gittiğinde mini denetleyici olarak bilinen kalıcı bir kontrol sağlamalıdır. Mini kumanda, geçerli yayın oturumunun kullanıcısına görünür bir hatırlatıcı sağlar. Kullanıcı, mini kumandaya dokunarak Yayın tam ekran genişletilmiş kumanda görünümüne geri dönebilir.
Çerçeve, özel bir Görünüm, MiniControllerFragment sunar. Bu denetleyiciyi, mini denetleyiciyi göstermek istediğiniz her etkinliğin düzen dosyasının en altına ekleyebilirsiniz.
<fragment
android:id="@+id/castMiniController"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:visibility="gone"
class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment" />
Gönderen uygulamanız bir video veya ses canlı yayını oynatırken SDK, mini kumandadaki oynat/duraklat düğmesinin yerine otomatik olarak bir oynat/dur düğmesi gösterir.
Bu özel görünümün başlığının ve alt metninin metin görünümünü ayarlamak ve düğmeleri seçmek için Mini Denetleyiciyi Özelleştir'e bakın.
Genişletilmiş kumanda ekle
Google Cast Tasarım Kontrol Listesi için bir gönderen uygulamasının, yayınlanacak medya için genişletilmiş kumanda sağlaması gerekir. Genişletilmiş kumanda, mini kumandanın tam ekran sürümüdür.
Cast SDK'sı, ExpandedControllerActivity
adlı genişletilmiş kumanda için bir widget sağlar.
Bu, bir Yayınla düğmesi eklemek için alt sınıfa geçmeniz gereken soyut bir sınıftır.
İlk olarak, genişletilmiş kumanda için Yayınla düğmesini sağlamak üzere yeni bir menü kaynağı dosyası oluşturun:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
</menu>
ExpandedControllerActivity
'ı kapsayan yeni bir sınıf oluşturun.
class ExpandedControlsActivity : ExpandedControllerActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.expanded_controller, menu) CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item) return true } }
public class ExpandedControlsActivity extends ExpandedControllerActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.expanded_controller, menu); CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item); return true; } }
Şimdi application
etiketi içindeki uygulama manifest dosyasında yeni etkinliğinizi tanımlayın:
<application>
...
<activity
android:name=".expandedcontrols.ExpandedControlsActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.CastVideosDark"
android:screenOrientation="portrait"
android:parentActivityName="com.google.sample.cast.refplayer.VideoBrowserActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
...
</application>
Hedef etkinliği yeni etkinliğinize ayarlamak için CastOptionsProvider
öğesini düzenleyin ve NotificationOptions
ve CastMediaOptions
ayarlarını değiştirin:
override fun getCastOptions(context: Context): CastOptions? { val notificationOptions = NotificationOptions.Builder() .setTargetActivityClassName(ExpandedControlsActivity::class.java.name) .build() val mediaOptions = CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name) .build() return CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build() }
public CastOptions getCastOptions(Context context) { NotificationOptions notificationOptions = new NotificationOptions.Builder() .setTargetActivityClassName(ExpandedControlsActivity.class.getName()) .build(); CastMediaOptions mediaOptions = new CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .setExpandedControllerActivityClassName(ExpandedControlsActivity.class.getName()) .build(); return new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build(); }
Uzak medya yüklendiğinde yeni etkinliğinizi görüntülemek için LocalPlayerActivity
loadRemoteMedia
yöntemini güncelleyin:
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) { val remoteMediaClient = mCastSession?.remoteMediaClient ?: return remoteMediaClient.registerCallback(object : RemoteMediaClient.Callback() { override fun onStatusUpdated() { val intent = Intent(this@LocalPlayerActivity, ExpandedControlsActivity::class.java) startActivity(intent) remoteMediaClient.unregisterCallback(this) } }) remoteMediaClient.load( MediaLoadRequestData.Builder() .setMediaInfo(mSelectedMedia) .setAutoplay(autoPlay) .setCurrentTime(position.toLong()).build() ) }
private void loadRemoteMedia(int position, boolean autoPlay) { if (mCastSession == null) { return; } final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); if (remoteMediaClient == null) { return; } remoteMediaClient.registerCallback(new RemoteMediaClient.Callback() { @Override public void onStatusUpdated() { Intent intent = new Intent(LocalPlayerActivity.this, ExpandedControlsActivity.class); startActivity(intent); remoteMediaClient.unregisterCallback(this); } }); remoteMediaClient.load(new MediaLoadRequestData.Builder() .setMediaInfo(mSelectedMedia) .setAutoplay(autoPlay) .setCurrentTime(position).build()); }
Gönderen uygulamanız bir video veya ses canlı yayını oynatırken SDK, genişletilmiş kumandadaki oynatma/duraklatma düğmesinin yerine otomatik olarak bir oynat/dur düğmesi gösterir.
Temaları kullanarak görünümü ayarlamak, hangi düğmelerin gösterileceğini seçmek ve özel düğmeler eklemek için Genişletilmiş Denetleyiciyi Özelleştirme konusuna bakın.
Ses düzeyi kontrolü
Çerçeve, gönderen uygulamanın ses düzeyini otomatik olarak yönetir. Çerçeve, gönderen ve Web Alıcısı uygulamalarını otomatik olarak senkronize eder. Böylece gönderen kullanıcı her zaman Web Alıcısı tarafından belirtilen hacmi bildirir.
Fiziksel düğme ses denetimi
Android'de, Jelly Bean veya daha yeni bir sürümün yüklü olduğu tüm cihazlarda, web alıcısındaki Yayın oturumunun ses düzeyini varsayılan olarak değiştirmek için, gönderen cihazındaki fiziksel düğmeler kullanılabilir.
Jelly Bean'den önceki fiziksel düğme ses seviyesi kontrolü
Jelly Bean'den daha eski Android cihazlarda Web Alıcısı cihaz hacmini kontrol etmek amacıyla fiziksel ses seviyesi tuşlarını kullanmak için, gönderen uygulamanın Etkinliklerindeki dispatchKeyEvent
ayarını geçersiz kılması ve CastContext.onDispatchVolumeKeyEventBeforeJellyBean()
yöntemini çağırması gerekir:
class MyActivity : FragmentActivity() { override fun dispatchKeyEvent(event: KeyEvent): Boolean { return (CastContext.getSharedInstance(this) .onDispatchVolumeKeyEventBeforeJellyBean(event) || super.dispatchKeyEvent(event)) } }
class MyActivity extends FragmentActivity { @Override public boolean dispatchKeyEvent(KeyEvent event) { return CastContext.getSharedInstance(this) .onDispatchVolumeKeyEventBeforeJellyBean(event) || super.dispatchKeyEvent(event); } }
Bildirim ve kilit ekranına medya denetimleri ekleme
Google Cast Tasarım Listesi yalnızca Android'de, gönderen uygulamanın bildirimde ve kilit ekranında gönderenin denetimlerini yayınladığı, ancak gönderenin uygulamasının odaklanmadığı bir uygulama gerektirir. Çerçeve, gönderen uygulamasının bir bildirimde ve kilit ekranında medya denetimleri oluşturmasına yardımcı olmak için MediaNotificationService
ve MediaIntentReceiver
özelliklerini sağlar.
MediaNotificationService
, gönderen içeriği yayınlarken çalışır ve mevcut küçük resimle ilgili bilgilerin yanı sıra oynatma/duraklatma düğmesi ve durdur düğmesi ile ilgili bilgilerin yer aldığı bir bildirim gösterir.
MediaIntentReceiver
, kullanıcı bildirimlerini bildirimden işleyen BroadcastReceiver
öğesidir.
Uygulamanız, kilit ekranından NotificationOptions
tarihine kadar bildirim ve medya kontrolü yapılandırabilir.
Uygulamanız, bildirimde hangi kontrol düğmelerinin gösterileceğini ve bildirime kullanıcı dokunduğunda hangi Activity
düğmelerinin açılacağını yapılandırabilir. İşlemler açık bir şekilde sağlanmazsa varsayılan değerler olan MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK
ve MediaIntentReceiver.ACTION_STOP_CASTING
kullanılır.
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting". val buttonActions: MutableList<String> = ArrayList() buttonActions.add(MediaIntentReceiver.ACTION_REWIND) buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK) buttonActions.add(MediaIntentReceiver.ACTION_FORWARD) buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING) // Showing "play/pause" and "stop casting" in the compat view of the notification. val compatButtonActionsIndices = intArrayOf(1, 3) // Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds. // Tapping on the notification opens an Activity with class VideoBrowserActivity. val notificationOptions = NotificationOptions.Builder() .setActions(buttonActions, compatButtonActionsIndices) .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS) .setTargetActivityClassName(VideoBrowserActivity::class.java.name) .build()
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting". List<String> buttonActions = new ArrayList<>(); buttonActions.add(MediaIntentReceiver.ACTION_REWIND); buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK); buttonActions.add(MediaIntentReceiver.ACTION_FORWARD); buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING); // Showing "play/pause" and "stop casting" in the compat view of the notification. int[] compatButtonActionsIndices = new int[]{1, 3}; // Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds. // Tapping on the notification opens an Activity with class VideoBrowserActivity. NotificationOptions notificationOptions = new NotificationOptions.Builder() .setActions(buttonActions, compatButtonActionsIndices) .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS) .setTargetActivityClassName(VideoBrowserActivity.class.getName()) .build();
Bildirim ve kilit ekranından medya denetimleri gösterme, varsayılan olarak etkindir ve CastMediaOptions.Builder
içinde boş setNotificationOptions
çağrısı yaparak devre dışı bırakılabilir.
Şu anda bildirim etkin olduğu sürece kilit ekranı özelliği etkin durumdadır.
// ... continue with the NotificationOptions built above val mediaOptions = CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .build() val castOptions: CastOptions = Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build()
// ... continue with the NotificationOptions built above CastMediaOptions mediaOptions = new CastMediaOptions.Builder() .setNotificationOptions(notificationOptions) .build(); CastOptions castOptions = new CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setCastMediaOptions(mediaOptions) .build();
Gönderen uygulamanız bir video veya ses canlı yayını oynatırken SDK, bildirim kontrolünde oynatma/duraklatma düğmesinin yerine otomatik olarak bir oynat/dur düğmesi gösterir, ancak kilit ekranı kontrolünde göstermez.
Not: Kilit ekranı kontrollerini Lollipop öncesi cihazlarda görüntülemek için
RemoteMediaClient
sizin adınıza otomatik olarak ses odaklama isteğinde bulunur.
Hataları işleme
Gönderen uygulamaların tüm hata geri çağırmalarını ele alması ve yayınlama yaşam döngüsünün her aşaması için en iyi yanıtı seçmesi çok önemlidir. Uygulama, kullanıcıya hata iletişim kutuları gösterebilir veya Web Alıcısı ile olan bağlantıyı yıkmaya karar verebilir.