Cast'i Android Uygulamanıza Entegre Edin

Koleksiyonlar ile düzeninizi koruyun İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.

Bu geliştirici kılavuzunda, Android Gönderen SDK'sını kullanarak Google Cast desteğinin Android gönderen uygulamanıza nasıl ekleneceği açıklanmaktadır.

Mobil cihaz veya dizüstü bilgisayar, oynatmayı kontrol eden gönderen, Google Cast cihazı ise TV'de içeriği görüntüleyen Alıcı'dır.

Gönderici çerçevesi, yayındaki çalışma zamanında gönderen için kullanılan Cast sınıfı kitaplık ikili programını ve ilişkili kaynakları ifade eder. Gönderen uygulaması veya Yayın uygulaması, gönderende de çalışan bir uygulamayı belirtir. Web Alıcısı uygulaması, Cast uyumlu cihazda çalışan HTML uygulamasını belirtir.

Gönderen çerçevesi, gönderene etkinlikleri uygulama hakkında bilgi vermek ve Yayın uygulaması 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önderen bir Android uygulaması için tipik üst düzey yürütme akışı açıklanmaktadır:

  • Yayın çerçevesi, Activity yaşam döngüsüne göre otomatik olarak MediaRouter cihaz keşfini başlatır.
  • Kullanıcı, Yayınla düğmesini tıkladığında çerçeve, Google Cast 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 uygulamada 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ındaki medya oynatmayı yüklemek ve kontrol etmek için iletişim kanalını kullanır.
  • Bu çerçeve, medya oynatma durumunu gönderen ile Web Alıcısı arasında senkronize eder: Kullanıcı gönderen kullanıcı arayüzü işlemlerini yaptığında, çerçeve bu medya kontrol isteklerini Web Alıcısı'na iletir ve Web Alıcısı medya durumu güncellemelerini gönderdiğinde çerçeve, gönderen kullanıcı arayüzünün durumunu günceller.
  • Kullanıcı, Yayın cihazıyla bağlantısını kesmek için Yayınla 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ı bölümünde 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ırma

Uygulamanızın AndroidManifest.xml dosyası, Yayın SDK'sı için aşağıdaki öğeleri yapılandırmanız gerekir:

kullanımlar-sdk

Cast SDK'nın desteklediği minimum ve hedef Android API düzeylerini ayarlayın. Şu anda minimum hedef API düzeyi 19 ve hedef, API düzeyi 28'dir.

<uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="28" />

android:tema

Uygulamanızın temasını minimum Android SDK sürümüne göre ayarlayın. Örneğin, kendi temanızı uygulamıyorsanız Lollipop'tan önceki minimum Android SDK sürümünü hedeflerken Theme.AppCompat varyantı 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 global bir tekil nesne (CastContext) bulunur.

Uygulamanızın, CastContext tek ihtimalini başlatmak için gereken seçenekleri sağlamak üzere OptionsProvider arayüzünü uygulaması gerekir. OptionsProvider, çerçevenin davranışını etkileyen seçenekler içeren CastOptions örneği sunar. En önemli olanı, keşif sonuçlarını filtrelemek ve bir Yayın oturumu başladığında Web Alıcısı uygulamasını başlatmak için kullanılan Web Alıcı uygulama kimliğidir.

Kotlin
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
    }
}
Java
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 nitelikli 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.getSharedInstance() çağrıldığında, CastContext geç başlatılır.

Kotlin
class MyActivity : FragmentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val castContext = CastContext.getSharedInstance(this)
    }
}
Java
public class MyActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        CastContext castContext = CastContext.getSharedInstance(this);
    }
}

Cast UX Widget'ları

Cast çerçevesi, Cast Tasarım Listesi'ne uyan widget'lar sağlar:

  • Tanıtım Yer Paylaşımı: Çerçeve, bir alıcı ilk kez kullanılabilir olduğunda kullanıcıya Yayınla düğmesine dikkat etmesi gerektiğini gösteren özel bir Görünüm IntroductoryOverlay sağlar. Gönderen uygulaması, başlık metninin metnini ve konumunu özelleştirebilir.

  • Yayınla Düğmesi: Yayınla düğmesi, uygulamanızı destekleyen bir alıcı keşfedildiğinde görünür. Kullanıcı, Yayınla düğmesini ilk kez tıkladığında, keşfedilen cihazların listelendiği bir Yayın iletişim kutusu görüntülenir. Kullanıcı, cihaz bağlıyken Yayınla düğmesini tıkladığında mevcut medya meta verilerini (başlık, kayıt stüdyosu adı ve küçük resim gibi) görüntüler veya kullanıcının Yayın cihazıyla bağlantısını kesmesine izin verir.

  • Mini Denetleyici: Kullanıcı içerik yayınlarken mevcut 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 o anda oynatılan medya meta verilerini gösteren ve medya oynatmayı kontrol etmek için birkaç düğme sağlayan genişletilmiş kumanda açılır.

  • Bildirim: Yalnızca Android. Kullanıcı içerik yayınladığında ve gönderen uygulamasından ayrıldığında, o anda yayınlanan medya meta verilerini ve oynatma kontrollerini gösteren bir medya bildirimi gösterilir.

  • Kilit Ekranı: Yalnızca Android. Kullanıcı içerik yayınlamakta ve (veya cihaz zaman aşımına uğradığında) kilit ekranına gittiğinde, o anda yayınlanan medya meta verilerini ve oynatma denetimlerini gösteren bir medya kilit ekranı kontrolü görüntülenir.

Aşağıdaki kılavuzda, bu widget'ları uygulamanıza nasıl ekleyeceğinizle ilgili açıklamalar bulunmaktadı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'sini kullanan Android uygulamaları, kullanıcıların Yayın cihazı gibi ikincil bir cihazda medya oynatacak medya rotası seçebilmeleri için kullanıcı arayüzlerinin bir parçası olarak Yayınla düğmesi içermelidir.

Çerçeve, MediaRouteButton'i Cast button olarak eklemeyi oldukça kolaylaştırır. Önce xml dosyanıza menünüzü tanımlayan bir menü öğesi veya MediaRouteButton eklemeniz, ardından 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" />
Kotlin
// 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
}
Java
// 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 bir 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>
Kotlin
// 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)
}
Java
// 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);
}

Tema kullanarak yayınla düğmesinin görünümünü ayarlamak için Yayın Düğmesini Özelleştirme konusuna bakın.

Cihaz keşfini yapılandırın

Cihaz keşfi tamamen CastContext tarafından yönetilir. CastContext başlatılırken, gönderen uygulama Web Alıcısı uygulama kimliğini belirtir ve isteğe bağlı olarak CastOptions içinde supportedNamespaces ayarını yaparak ad alanı filtrelemesi isteyebilir. CastContext, dahili olarak MediaRouter için referans içerir ve gönderen uygulaması ön plana girdiğinde keşif işlemini başlatır ve gönderen uygulaması arka plana girdiğinde durur.

Kotlin
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
    }
}
Java
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

Cast SDK'sı, bir cihaza bağlanma, bir Web Alıcısı uygulamasını başlatma (veya uygulamaya katılma), bu uygulamaya bağlanma ve bir medya kontrol kanalı başlatma adımlarını birleştiren Yayın oturumu kavramını ortaya koydu. Yayınlama oturumları ve Web Alıcısı 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ınlama 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 anormal veya ani bir sonlandırmadan otomatik olarak devam etmeye çalışır.

Oturumlar, MediaRouter iletişim kutularından kullanıcı hareketlerine yanıt olarak otomatik olarak oluşturulur ve kaldırılır.

Oturumla ilgili durum değişiklikleri hakkında bilgi sahibi olmanız gerekirse SessionManagerListener uygulayabilirsiniz. Bu örnekte, bir Activity içindeki CastSession öğesinin kullanılabilirliği gösterilmektedir.

Kotlin
class MyActivity : Activity() {
    private var mCastSession: CastSession? = null
    private lateinit var mSessionManager: SessionManager
    private val mSessionManagerListener: SessionManagerListener<CastSession> =
        SessionManagerListenerImpl()

    private inner class SessionManagerListenerImpl : SessionManagerListener<CastSession?> {
        override fun onSessionStarted(session: CastSession?, sessionId: String) {
            invalidateOptionsMenu()
        }

        override fun onSessionResumed(session: CastSession?, wasSuspended: Boolean) {
            invalidateOptionsMenu()
        }

        override fun onSessionEnded(session: CastSession?, error: Int) {
            finish()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mSessionManager = CastContext.getSharedInstance(this).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
    }
}
Java
public class MyActivity extends Activity {
    private CastSession mCastSession;
    private SessionManager mSessionManager;
    private SessionManagerListener<CastSession> mSessionManagerListener =
            new SessionManagerListenerImpl();

    private class SessionManagerListenerImpl implements SessionManagerListener<CastSession> {
        @Override
        public void onSessionStarted(CastSession session, String sessionId) {
            invalidateOptionsMenu();
        }
        @Override
        public void onSessionResumed(CastSession session, boolean wasSuspended) {
            invalidateOptionsMenu();
        }
        @Override
        public void onSessionEnded(CastSession session, int error) {
            finish();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSessionManager = CastContext.getSharedInstance(this).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 sesli komutlar, Google Home uygulaması 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) oynamaya devam eder ve başka bir cihazda (hedef) devam eder. En son donanım yazılımına sahip tüm Cast cihazları, akış aktarımında kaynak veya hedef işlevi görebilir.

Akış aktarma veya genişletme sırasında yeni hedef cihazı almak için CastSession#addCastListener öğesini kullanarak bir 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ında akış aktarımı bölümüne bakın.

Otomatik yeniden bağlantı

Çerçeve, birçok basit durumda yeniden bağlantı oluşturmak için gönderen uygulamanın etkinleştirebileceği bir ReconnectionService sağlar. Örneğin:

  • Kablosuz ağ geçici olarak kaybedildiğinden kurtulma
  • Cihaz uykusundan kurtar
  • Uygulamanın arka planını kurtarma
  • 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, uygulama manifestinizle otomatik olarak birleştirilebilir.

Çerçeve, hizmeti bir medya oturumu olduğunda başlatır ve medya oturumu sona erdiğinde durdurur.

Medya Kontrolü'nün işleyiş şekli

Cast çerçevesi, RemoteMediaPlayer sınıfını Cast 2.x sürümünden itibaren kullanımdan kaldırarak yeni bir sınıfı kullanıma sundu. RemoteMediaClient, aynı işlevleri daha kullanışlı API'ler kümesinde sunan ve bir GoogleApiClient'inden geçmekten kaçınan bir sınıftır.

Uygulamanız, medya ad alanını destekleyen bir Web Alıcısı uygulaması ile CastSession oluşturduğunda çerçeve tarafından otomatik olarak 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 WaitResult nesnesi döndürür.

RemoteMediaClient örneğinin, uygulamanızın birden fazla parçası ve hatta çerçevenin kalıcı mini kumandaları ve bildirim hizmeti gibi bazı dahili bileşenleriyle paylaşılması beklenir. Bu örnekte, birden fazla RemoteMediaClient.Listener kaydının kaydedilmesi bu örnekte amaçlanmaktadır.

Medya meta verilerini ayarlama

MediaMetadata sınıfı, yayınlamak istediğiniz medya öğesiyle ilgili bilgileri temsil eder. Aşağıdaki örnekte bir filmin yeni MediaMetale örneği oluşturulur ve başlık, alt başlık ve iki resim ayarlanır.

Kotlin
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))))
Java
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 verili resimlerin kullanımı hakkında bilgi için Resim Seçimi konusuna bakı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 değerini alın, ardından MediaInfo içini mevcut 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 uygulamasını kullanın.

Kotlin
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())
Java
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());

Medya kanallarını kullanma ile ilgili bölüme de bakın.

4K video biçimi

Medyanızın ne tür bir video biçimine sahip olduğunu kontrol etmek için Medya Durumu'nda getVideoInfo() öğesini kullanarak VideoInfo örneğini alın. Bu örnekte HDR TV biçiminin türü, ekran yüksekliği ve piksel cinsinden genişlik bulunmaktadır. 4K biçimindeki varyantlar sabit değerler HDR_TYPE_* ile gösterilir.

Birden çok cihaza uzaktan kumanda bildirimleri

Bir kullanıcı yayın yaparken aynı ağdaki diğer Android cihazlar da oynatmayı kontrol etmeleri için bildirim alır. Cihazı bu tür bildirimleri alan herkes bu bildirimleri, Google'ın Ayarlar uygulaması > Google Cast > Uzaktan kumanda bildirimlerini göster bölümünden kapatabilir. (Bildirimlerde Ayarlar uygulamasının kısayolu yer alır.) Daha ayrıntılı bilgi için Uzaktan kumanda bildirimlerini yayınlama bölümüne bakın.

Mini kumanda ekleyin

Yayın Tasarımı Kontrol Listesi'ne göre, bir gönderen uygulamasının, kullanıcı mevcut içerik sayfasından ayrılıp gönderen uygulamanın başka bir bölümüne gittiğinde görünmesi gereken mini kumanda olarak bilinen kalıcı kontrolü sağlaması gerekir. 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 Tam ekran genişletilmiş kumanda kumandasına dönebilir.

Çerçevede, mini kumandayı göstermek istediğiniz her etkinliğin düzen dosyasının en altına ekleyebileceğiniz özel bir Görünüm, MiniControllerFragment özelliği bulunur.

<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 video veya ses canlı yayını oynatırken SDK, mini kumandadaki oynat/duraklat düğmesi yerine otomatik olarak bir oynat/durdur 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ştirme konusuna bakın.

Genişletilmiş kumanda ekle

Google Cast Tasarım Kontrol Listesi için bir gönderen uygulaması, yayınlanmakta olan medya için genişletilmiş kumanda sağlamalıdır. 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, Yayın düğmesi eklemek için alt sınıf kullanmanız gereken soyut bir sınıftır.

İlk olarak, genişletilmiş kumanda için Yayınla düğmesini sağlaması amacıyla 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 tarihini kapsayan yeni bir sınıf oluşturun.

Kotlin
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
    }
}
Java
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 etiketindeki uygulama manifestinde 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ğiniz olarak ayarlamak için CastOptionsProvider öğesini düzenleyin ve NotificationOptions ile CastMediaOptions ayarlarını değiştirin:

Kotlin
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()
}
Java
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:

Kotlin
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()
    )
}
Java
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 video veya ses canlı yayını oynatırken SDK, genişletilmiş kumandadaki oynat/duraklat düğmesi yerine otomatik olarak oynat/durdur düğmesi gösterir.

Temaları kullanarak görünümü ayarlamak, görüntülenecek düğmeleri 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 uygulamasının ses düzeyini otomatik olarak yönetir. Çerçeve, gönderen kullanıcı ile 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 ses düzeyini bildirir.

Fiziksel düğme ses denetimi

Android'de, Jelly Bean veya daha yeni sürümleri kullanan herhangi bir cihaz için gönderen cihazın fiziksel düğmeleri, Web Alıcısı'ndaki yayın oturumunun ses düzeyini değiştirmek için kullanılabilir.

Jelly Bean'den önce fiziksel düğme ses seviyesi kontrolü

Jelly Bean'den daha eski Android cihazlarda Web Alıcısı cihaz ses seviyesini kontrol etmek üzere fiziksel ses seviyesi tuşlarını kullanmak için, gönderen uygulamanın Etkinliklerinde dispatchKeyEvent politikasını geçersiz kılması ve CastContext.onDispatchVolumeKeyEventBeforeJellyBean() numarasını araması gerekir:

Kotlin
class MyActivity : FragmentActivity() {
    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        return (CastContext.getSharedInstance(this)
            .onDispatchVolumeKeyEventBeforeJellyBean(event)
                || super.dispatchKeyEvent(event))
    }
}
Java
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

Yalnızca Android'de, Google Cast Tasarım Kontrol Listesi için bir gönderen uygulamasının bildirimde ve kilit ekranında, gönderenin yayınladığı ama gönderen uygulamasının odaklanmadığı medya kontrolleri uygulaması gerekir. Bu çerçeve, gönderen uygulamanın bir bildirimle kilit ekranında medya denetimleri oluşturmasına yardımcı olmak için MediaNotificationService ve MediaIntentReceiver özelliklerini sağlar.

MediaNotificationService, gönderen yayın yaparken çalışır ve hem küçük resmin hem de o anda yayınlanan öğeyle ilgili bilgilerin, bir oynat/duraklat düğmesinin ve bir durdurma düğmesinin yer aldığı bir bildirim gösterir.

MediaIntentReceiver, bildirimden gelen kullanıcı işlemlerini işleyen BroadcastReceiver'dir.

Uygulamanız, kilit ekranından NotificationOptions aracılığıyla bildirim ve medya kontrolü yapılandırabilir. Uygulamanız, bildirimde hangi kontrol düğmelerinin gösterileceğini ve bildirime dokunulduğunda hangi Activity öğesinin açılacağını yapılandırabilir. İşlemler açık bir şekilde sağlanmazsa MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK ve MediaIntentReceiver.ACTION_STOP_CASTING varsayılan değerleri kullanılır.

Kotlin
// 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()
Java
// 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ındaki medya denetimlerinin gösterilmesi, varsayılan olarak etkindir ve CastMediaOptions.Builder içinde boş değerli setNotificationOptions çağırılarak devre dışı bırakılabilir. Şu anda bildirim etkin olduğu sürece kilit ekranı özelliği etkin durumdadır.

Kotlin
// ... 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()
Java
// ... 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 video veya ses canlı yayını oynatırken SDK, bildirim kontrolündeki oynat/duraklat düğmesi yerine otomatik olarak bir oynat/dur düğmesi gösterir ancak kilit ekranı kontrolünü göstermez.

Not: Kilit ekranı denetimlerini Lollipop öncesi cihazlarda görüntülemek için RemoteMediaClient otomatik olarak sizin adınıza ses odağı ister.

Hataları ele alma

Gönderen uygulamaların tüm hata geri çağırmalarını ele alması ve Yayın 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ı bağlantısının bağlantısını kesmeye karar verebilir.