1. Genel bakış
Bu codelab'de, Google Cast uyumlu bir cihazda içerik yayınlamak için mevcut bir Android video uygulamasını nasıl değiştireceğinizi öğreneceksiniz.
Google Cast nedir?
Google Cast, kullanıcıların bir mobil cihazdan TV'ye içerik yayınlamasına olanak tanır. Kullanıcılar daha sonra mobil cihazlarını TV'de medya oynatmak için uzaktan kumanda olarak kullanabilir.
Google Cast SDK'sı, uygulamanızı bir TV veya ses sistemini kontrol edecek şekilde genişletmenize olanak tanır. Cast SDK'sı, Google Cast Tasarım Kontrol Listesi'ne göre gerekli kullanıcı arayüzü bileşenlerini eklemenize olanak tanır.
Google Cast Tasarım Kontrol Listesi, desteklenen tüm platformlarda Cast kullanıcı deneyimini basit ve tahmin edilebilir hale getirmek için sağlanmıştır.
Neyi inşa edeceğiz?
Bu codelab'i tamamladığınızda videoları Google Cast uyumlu bir cihazda yayınlayabilecek bir Android video uygulamanız olacaktır.
Neler öğreneceksiniz?
- Örnek bir video uygulamasına Google Cast SDK'sı nasıl eklenir?
- Google Cast cihazı seçmek için Yayın düğmesi nasıl eklenir?
- Yayın cihazına bağlanıp medya alıcısı nasıl başlatılır?
- Video nasıl yayınlanır?
- Uygulamanıza Cast mini kumanda ekleme.
- Medya bildirimleri ve kilit ekranı kontrolleri nasıl desteklenir?
- Genişletilmiş kumanda nasıl eklenir?
- Tanıtım amaçlı yer paylaşımı nasıl sağlanır?
- Yayın widget'ları nasıl özelleştirilir?
- Cast Connect ile entegrasyon
Gerekenler
- En son Android SDK.
- Android Studio 3.2 ve sonraki sürümleri
- Android 4.1+ Jelly Bean (API düzeyi 16) yüklü bir mobil cihaz.
- Mobil cihazınızı geliştirme bilgisayarınıza bağlamak için bir USB veri kablosu.
- İnternet erişimi olan, Chromecast veya Android TV gibi bir Google Cast cihazı.
- HDMI girişi olan bir TV veya monitör.
- Cast Connect entegrasyonunu test etmek için Google TV Yüklü Chromecast gereklidir, ancak Codelab'in geri kalanı için isteğe bağlıdır. Destek kaydınız yoksa bu eğiticinin sonuna doğru olan Cast Connect Desteği Ekleme adımını atlayabilirsiniz.
Deneyim
- Kotlin ve Android geliştirme konusunda önceden bilgi sahibi olmanız gerekir.
- Ayrıca TV izleme konusunda da önceden bilgi sahibi olmanız gerekir :)
Bu eğiticiyi nasıl kullanacaksınız?
Android uygulamaları oluşturma deneyiminizi nasıl değerlendirirsiniz?
TV izleme deneyiminizi nasıl değerlendirirsiniz?
2. Örnek kodu alın
Örnek kodun tamamını bilgisayarınıza indirebilirsiniz...
indirilen zip dosyasını açın.
3. Örnek uygulamayı çalıştırma
Önce tamamlanmış örnek uygulamanın nasıl göründüğüne bakalım. Uygulama, temel bir video oynatıcıdır. Kullanıcı, listeden bir video seçebilir ve videoyu cihazda yerel olarak oynatabilir veya bir Google Cast cihazına yayınlayabilir.
Kod indirildikten sonra aşağıdaki talimatlarda, tamamlanmış örnek uygulamayı Android Studio'da nasıl açacağınız ve çalıştıracağınız açıklanmaktadır:
Karşılama ekranında Projeyi İçe Aktar'ı veya Dosya > Yeni > Projeyi İçe Aktar... menü seçeneklerini belirleyin.
Örnek kod klasöründen app-done
dizinini seçin ve Tamam'ı tıklayın.
Dosya > Projeyi Gradle Dosyalarıyla Senkronize Et'i tıklayın.
Android cihazınızda USB üzerinden hata ayıklamayı etkinleştirin. Android 4.2 ve sonraki sürümlerde Geliştirici seçenekleri ekranı varsayılan olarak gizlidir. Telefonu görünür hale getirmek için Ayarlar > Telefon hakkında'ya gidip Derleme numarası'na yedi kez dokunun. Önceki ekrana dönün, Sistem > Gelişmiş'e gidin ve alt taraftaki Geliştirici seçenekleri'ne dokunun, ardından USB hata ayıklaması'na dokunarak özelliği etkinleştirin.
Android cihazınızı fişe takın ve Android Studio'daki Çalıştır düğmesini tıklayın. Birkaç saniye sonra Video Yayınla adlı video uygulamasını görürsünüz.
Video uygulamasındaki Yayınla düğmesini tıklayın ve Google Cast cihazınızı seçin.
Bir video seçin ve oynat düğmesini tıklayın.
Video, Google Cast cihazınızda oynatılmaya başlar.
Genişletilmiş kumanda gösterilir. Oynatmayı kontrol etmek için oynat/duraklat düğmesini kullanabilirsiniz.
Video listesine geri dönün.
Ekranın alt kısmında artık bir mini kumanda görünüyor.
Videoyu alıcıda duraklatmak için mini kumandadaki duraklat düğmesini tıklayın. Videoyu tekrar oynatmaya devam etmek için mini kumandadaki oynat düğmesini tıklayın.
Mobil cihazın ana sayfa düğmesini tıklayın. Bildirimleri aşağı çektiğinizde Yayın oturumuyla ilgili bir bildirim görürsünüz.
Telefonunuzu kilitlediğinizde, kilidini açtığınızda medya oynatmayı kontrol etmek veya yayınlamayı durdurmak için kilit ekranında bir bildirim görürsünüz.
Video uygulamasına dönün ve Google Cast cihazında yayını durdurmak için Yayınla düğmesini tıklayın.
Sık sorulan sorular
4. Başlangıç projesini hazırlama
İndirdiğiniz başlangıç uygulamasına Google Cast desteği eklememiz gerekiyor. Bu codelab'de kullanacağımız bazı Google Cast terminolojisini aşağıda bulabilirsiniz:
- Mobil cihazda veya dizüstü bilgisayarda çalışan bir gönderen uygulaması ise
- Google Cast cihazında bir alıcı uygulaması çalışır.
Artık Android Studio'yu kullanarak başlangıç projesinin temelini oluşturmaya hazırsınız:
- Örnek kod indirmenizden
app-start
dizinini seçin (hoş geldiniz ekranında Projeyi İçe Aktar'ı veya Dosya > Yeni > Projeyi İçe Aktar... menü seçeneğini seçin). - Sync Project with Gradle Files (Projeyi Gradle Dosyalarıyla Senkronize Et) düğmesini tıklayın.
- Uygulamayı çalıştırmak ve kullanıcı arayüzünü keşfetmek için Çalıştır düğmesini tıklayın.
Uygulama tasarımı
Uygulama, uzak bir web sunucusundan video listesi getirir ve kullanıcının göz atabileceği bir liste sağlar. Kullanıcılar bir video seçerek ayrıntılarını görebilir veya videoyu mobil cihazlarında yerel olarak oynatabilir.
Uygulama iki ana etkinlikten oluşuyor: VideoBrowserActivity
ve LocalPlayerActivity
. Google Cast işlevselliğinin entegre edilmesi için Etkinlikler, AppCompatActivity
veya üst öğesinden FragmentActivity
öğesini devralmalıdır. Bu sınırlama, MediaRouteButton
öğesini (MediaRouter destek kitaplığında sağlanır) MediaRouteActionProvider
olarak eklememiz gerekeceğinden ve bu işlem yalnızca etkinliğin yukarıda belirtilen sınıflardan devraldığı durumlarda işe yarayacaktır. MediaRouter destek kitaplığı, gerekli sınıfları sağlayan AppCompat destek kitaplığına bağlıdır.
VideoBrowserActivity
Bu etkinlik bir Fragment
(VideoBrowserFragment
) içeriyor. Bu liste ArrayAdapter
(VideoListAdapter
) ile desteklenmektedir. Videoların listesi ve ilişkili meta verileri, JSON dosyası olarak uzak bir sunucuda barındırılır. AsyncTaskLoader
(VideoItemLoader
) bu JSON'u getirir ve MediaItem
nesnelerinin listesini oluşturmak için işler.
MediaItem
nesnesi, bir videoyu ve onunla ilişkili meta verileri (ör. başlığı, açıklaması, akışın URL'si, destekleyici resimlerin URL'si ve varsa ilişkili Metin Parçaları) modeller. MediaItem
nesnesi etkinlikler arasında aktarılır. Bu nedenle MediaItem
, nesneyi Bundle
(veya tersi) için yardımcı program yöntemlerine sahiptir.
Yükleyici MediaItems
listesini oluşturduğunda, bu listeyi VideoListAdapter
'a iletir. Daha sonra, bu liste VideoBrowserFragment
içinde MediaItems
listesini sunar. Kullanıcıya, her videonun kısa bir açıklamasını içeren video küçük resimlerinden oluşan bir liste sunulur. Bir öğe seçildiğinde, karşılık gelen MediaItem
bir Bundle
öğesine dönüştürülür ve LocalPlayerActivity
öğesine iletilir.
LocalPlayerActivity
Bu etkinlik, belirli bir video hakkındaki meta verileri görüntüler ve kullanıcının mobil cihazda videoyu yerel olarak oynatmasına olanak tanır.
Etkinlikte bir VideoView
, bazı medya denetimleri ve seçilen videonun açıklamasının gösterildiği bir metin alanı bulunur. Oynatıcı ekranın üst kısmını kaplar ve videonun ayrıntılı açıklaması için yer bırakır. Kullanıcı videoları oynatabilir/duraklatabilir veya yerel olarak oynatılmasını arayabilir.
Bağımlılıklar
AppCompatActivity
kullandığımız için AppCompat destek kitaplığına ihtiyacımız var. Video listesini yönetmek ve listedeki görselleri eşzamansız olarak almak için Volley kitaplığını kullanıyoruz.
Sık sorulan sorular
5. Yayınla düğmesi ekleniyor
Cast uyumlu bir uygulamanın, etkinliklerinin her birinde Yayın düğmesi görüntülenir. Yayınla düğmesi tıklandığında, kullanıcının seçebileceği Yayın cihazlarının listesi görüntülenir. Kullanıcı, içeriği gönderen cihazda yerel olarak oynatıyorsa, bir yayın cihazı seçildiğinde ilgili yayın cihazında oynatma başlatılır veya devam ettirilir. Yayınlama oturumu sırasında istediği zaman kullanıcı Yayınla düğmesini tıklayabilir ve uygulamanızın Yayın cihazına yayınlanmasını durdurabilir. Kullanıcı, uygulamanızdaki herhangi bir etkinlik sırasında Google Cast Tasarım Kontrol Listesi'nde açıklandığı gibi yayın cihazına bağlanabilmeli veya yayın cihazın bağlantısını kesebilmelidir.
Bağımlılıklar
Uygulama build.gradle dosyasını gerekli kitaplık bağımlılıklarını içerecek şekilde güncelleyin:
dependencies {
implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'androidx.mediarouter:mediarouter:1.3.1'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.google.android.gms:play-services-cast-framework:21.1.0'
implementation 'com.android.volley:volley:1.2.1'
implementation "androidx.core:core-ktx:1.8.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
Proje derlemelerinin hatasız olduğunu onaylamak için projeyi senkronize edin.
Başlatma
Cast çerçevesi, tüm Cast etkileşimlerini koordine eden genel bir tekil nesneye (CastContext
) sahiptir.
CastContext
teklisini başlatmak için gereken CastOptions
kaynağını sağlamak amacıyla OptionsProvider
arayüzünü uygulamanız gerekir. En önemli seçenek, yayın cihazının keşif sonuçlarını filtrelemek ve bir yayın oturumu başlatıldığında alıcı uygulamayı başlatmak için kullanılan alıcı uygulama kimliğidir.
Cast uyumlu kendi uygulamanızı geliştirdiğinizde, Cast geliştiricisi olarak kaydolmanız ve ardından uygulamanız için bir uygulama kimliği almanız gerekir. Bu codelab için örnek bir uygulama kimliği kullanacağız.
Aşağıdaki yeni CastOptionsProvider.kt
dosyasını projenin com.google.sample.cast.refplayer
paketine ekleyin:
package com.google.sample.cast.refplayer
import android.content.Context
import com.google.android.gms.cast.framework.OptionsProvider
import com.google.android.gms.cast.framework.CastOptions
import com.google.android.gms.cast.framework.SessionProvider
class CastOptionsProvider : OptionsProvider {
override fun getCastOptions(context: Context): CastOptions {
return CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.build()
}
override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
return null
}
}
Şimdi uygulama AndroidManifest.xml
dosyasının "application
" etiketi içinde OptionsProvider
öğesini tanımlayın:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />
VideoBrowserActivity
onCreate yönteminde CastContext
öğesini geç bir şekilde başlatın:
import com.google.android.gms.cast.framework.CastContext
private var mCastContext: CastContext? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.video_browser)
setupActionBar()
mCastContext = CastContext.getSharedInstance(this)
}
Aynı başlatma mantığını LocalPlayerActivity
öğesine ekleyin.
Yayınla düğmesi
CastContext
başlatıldığına göre kullanıcının yayın cihazı seçebilmesi için Yayınla düğmesini eklememiz gerekir. Yayınla düğmesi, MediaRouter destek kitaplığındaki MediaRouteButton
tarafından uygulanır. Etkinliğinize ekleyebileceğiniz herhangi bir işlem simgesi gibi (ActionBar
veya Toolbar
kullanarak) önce ilgili menü öğesini menünüze eklemeniz gerekir.
res/menu/browse.xml
dosyasını düzenleyin ve menüde ayarlar öğesinin önüne MediaRouteActionProvider
öğesini ekleyin:
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
MediaRouteButton
öğesini Cast çerçevesine bağlamak için CastButtonFactory
kullanarak VideoBrowserActivity
onCreateOptionsMenu()
yöntemini geçersiz kılın:
import com.google.android.gms.cast.framework.CastButtonFactory
private var mediaRouteMenuItem: MenuItem? = null
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.browse, menu)
mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu,
R.id.media_route_menu_item)
return true
}
LocalPlayerActivity
öğesinde onCreateOptionsMenu
öğesini benzer bir şekilde geçersiz kılın.
Uygulamayı mobil cihazınızda çalıştırmak için Çalıştır düğmesini tıklayın. Uygulamanın işlem çubuğunda bir Yayınla düğmesi görürsünüz. Bu düğmeyi tıkladığınızda yerel ağınızdaki yayın cihazları listelenir. Cihaz keşfi CastContext
tarafından otomatik olarak yönetilir. Yayın cihazınızı seçin. Yayın cihazına örnek alıcı uygulaması yüklenir. Göz atma etkinliği ile yerel oynatıcı etkinliği arasında gezinebilirsiniz. Yayın düğmesinin durumu senkronize edilir.
Medya oynatma desteği almadığımızdan henüz yayın cihazında video oynatamıyorsunuz. Bağlantıyı kesmek için Yayınla düğmesini tıklayın.
6. Video içeriği yayınlanıyor
Örnek uygulamanın kapsamını, videoları bir Cast cihazında uzaktan oynatacak şekilde genişleteceğiz. Bunun için Cast çerçevesi tarafından oluşturulan çeşitli etkinlikleri dinlememiz gerekir.
Medya yayınlanıyor
Genel olarak, bir yayın cihazında medya oynatmak isterseniz aşağıdakileri yapmanız gerekir:
- Medya öğesini modelleyen bir
MediaInfo
nesnesi oluşturun. - Yayın cihazına bağlanıp alıcı uygulamanızı başlatın.
MediaInfo
nesnesini alıcınıza yükleyin ve içeriği oynatın.- Medya durumunu izleyin.
- Kullanıcı etkileşimlerine bağlı olarak alıcıya oynatma komutları gönderin.
Önceki bölümde yer alan 2. Adım'ı zaten yapmıştık. 3. adımı Cast çerçevesiyle yapmak kolaydır. 1. adım bir nesnenin başka bir nesneyle eşlenmesi anlamına gelir; MediaInfo
, Cast çerçevesinin anladığı bir şey, MediaItem
ise uygulamamızın bir medya öğesine yönelik kapsülüdür. Bir MediaItem
öğesini kolayca bir MediaInfo
ile eşleyebiliriz.
Örnek uygulama LocalPlayerActivity
, şu enum'u kullanarak yerel ve uzaktan oynatma arasında zaten ayrım yapmaktadır:
private var mLocation: PlaybackLocation? = null
enum class PlaybackLocation {
LOCAL, REMOTE
}
enum class PlaybackState {
PLAYING, PAUSED, BUFFERING, IDLE
}
Bu codelab'de tüm örnek oynatıcı mantığının tam olarak nasıl çalıştığını anlamanız önemli değildir. Uygulamanızın medya oynatıcısının, iki oynatma konumunu benzer bir şekilde fark etmesi için değiştirilmesi gerektiğini anlamak önemlidir.
Şu anda yerel oynatıcı, Yayınlama durumları hakkında henüz hiçbir şey bilmediğinden her zaman yerel oynatma durumundadır. Kullanıcı arayüzünü, Cast çerçevesinde gerçekleşen durum geçişlerine göre güncellememiz gerekir. Örneğin, yayınlamaya başlarsak yerel oynatmayı durdurmamız ve bazı kontrolleri devre dışı bırakmamız gerekir. Benzer şekilde, bu işlem devam ederken yayını durdurursak yerel oynatmaya geçiş yapmamız gerekir. Bunu halletmek için Cast çerçevesi tarafından oluşturulan çeşitli etkinlikleri dinlememiz gerekir.
Yayın oturumu yönetimi
Yayın çerçevesi için Cast oturumu; cihaza bağlanma, başlatma (veya katılma), alıcı uygulamaya bağlanma ve uygunsa bir medya kontrol kanalını başlatma adımlarını birleştirir. Medya kontrol kanalı, Yayın çerçevesinin alıcı medya oynatıcıdan mesaj gönderip alma yöntemidir.
Yayın oturumu, kullanıcı Yayınla düğmesinden bir cihaz seçtiğinde otomatik olarak başlatılır ve kullanıcı bağlantısı kesildiğinde otomatik olarak durdurulur. Ağ sorunları nedeniyle alıcı oturumuna yeniden bağlanma da otomatik olarak Cast SDK'sı tarafından gerçekleştirilir.
LocalPlayerActivity
içine SessionManagerListener
ekleyelim:
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
...
private var mSessionManagerListener: SessionManagerListener<CastSession>? = null
private var mCastSession: CastSession? = null
...
private fun setupCastListener() {
mSessionManagerListener = object : SessionManagerListener<CastSession> {
override fun onSessionEnded(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionResumed(session: CastSession, wasSuspended: Boolean) {
onApplicationConnected(session)
}
override fun onSessionResumeFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionStarted(session: CastSession, sessionId: String) {
onApplicationConnected(session)
}
override fun onSessionStartFailed(session: CastSession, error: Int) {
onApplicationDisconnected()
}
override fun onSessionStarting(session: CastSession) {}
override fun onSessionEnding(session: CastSession) {}
override fun onSessionResuming(session: CastSession, sessionId: String) {}
override fun onSessionSuspended(session: CastSession, reason: Int) {}
private fun onApplicationConnected(castSession: CastSession) {
mCastSession = castSession
if (null != mSelectedMedia) {
if (mPlaybackState == PlaybackState.PLAYING) {
mVideoView!!.pause()
loadRemoteMedia(mSeekbar!!.progress, true)
return
} else {
mPlaybackState = PlaybackState.IDLE
updatePlaybackLocation(PlaybackLocation.REMOTE)
}
}
updatePlayButton(mPlaybackState)
invalidateOptionsMenu()
}
private fun onApplicationDisconnected() {
updatePlaybackLocation(PlaybackLocation.LOCAL)
mPlaybackState = PlaybackState.IDLE
mLocation = PlaybackLocation.LOCAL
updatePlayButton(mPlaybackState)
invalidateOptionsMenu()
}
}
}
LocalPlayerActivity
etkinliğinde, Cast cihazına bağlandığımızda veya cihaz bağlantısı kesildiğinde bilgi almak isteriz. Böylece yerel oynatıcıya veya yerel oynatıcıdan geçiş yapabiliriz. Bağlantının yalnızca uygulamanızın mobil cihazınızda çalışan örneği nedeniyle kesintiye uğrayabileceğini değil, aynı zamanda uygulamanızın farklı bir mobil cihazda çalışan (ya da başka bir) uygulamanızın başka bir örneği nedeniyle de kesintiye uğrayabileceğini unutmayın.
Şu anda etkin olan oturuma SessionManager.getCurrentSession()
adresinden erişilebilir. Oturumlar, kullanıcıların Yayınlama iletişim kutularıyla olan etkileşimlerine yanıt olarak otomatik olarak oluşturulur ve azaltılır.
Oturum işleyicimizi kaydetmemiz ve etkinlikte kullanacağımız bazı değişkenleri başlatmamız gerekiyor. LocalPlayerActivity
onCreate
yöntemini şu şekilde değiştirin:
import com.google.android.gms.cast.framework.CastContext
...
private var mCastContext: CastContext? = null
...
override fun onCreate(savedInstanceState: Bundle?) {
...
mCastContext = CastContext.getSharedInstance(this)
mCastSession = mCastContext!!.sessionManager.currentCastSession
setupCastListener()
...
loadViews()
...
val bundle = intent.extras
if (bundle != null) {
....
if (shouldStartPlayback) {
....
} else {
if (mCastSession != null && mCastSession!!.isConnected()) {
updatePlaybackLocation(PlaybackLocation.REMOTE)
} else {
updatePlaybackLocation(PlaybackLocation.LOCAL)
}
mPlaybackState = PlaybackState.IDLE
updatePlayButton(mPlaybackState)
}
}
...
}
Medya yükleniyor
Cast SDK'sında RemoteMediaClient
, alıcıdaki uzaktan medya oynatmayı yönetmek için kullanabileceğiniz bir dizi kullanışlı API sağlar. Medya oynatmayı destekleyen bir CastSession
için SDK tarafından otomatik olarak RemoteMediaClient
örneği oluşturulur. CastSession
örneğinde getRemoteMediaClient()
yöntemi çağırılarak erişilebilir. Şu anda seçili olan videoyu alıcıya yüklemek için aşağıdaki yöntemleri LocalPlayerActivity
öğesine ekleyin:
import com.google.android.gms.cast.framework.media.RemoteMediaClient
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaLoadOptions
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.common.images.WebImage
import com.google.android.gms.cast.MediaLoadRequestData
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
if (mCastSession == null) {
return
}
val remoteMediaClient = mCastSession!!.remoteMediaClient ?: return
remoteMediaClient.load( MediaLoadRequestData.Builder()
.setMediaInfo(buildMediaInfo())
.setAutoplay(autoPlay)
.setCurrentTime(position.toLong()).build())
}
private fun buildMediaInfo(): MediaInfo? {
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
mSelectedMedia?.studio?.let { movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, it) }
mSelectedMedia?.title?.let { movieMetadata.putString(MediaMetadata.KEY_TITLE, it) }
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(0))))
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(1))))
return mSelectedMedia!!.url?.let {
MediaInfo.Builder(it)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType("videos/mp4")
.setMetadata(movieMetadata)
.setStreamDuration((mSelectedMedia!!.duration * 1000).toLong())
.build()
}
}
Şimdi de uzaktan oynatmayı desteklemek üzere Yayın oturumu mantığını kullanmak için mevcut çeşitli yöntemleri güncelleyin:
private fun play(position: Int) {
startControllersTimer()
when (mLocation) {
PlaybackLocation.LOCAL -> {
mVideoView!!.seekTo(position)
mVideoView!!.start()
}
PlaybackLocation.REMOTE -> {
mPlaybackState = PlaybackState.BUFFERING
updatePlayButton(mPlaybackState)
//seek to a new position within the current media item's new position
//which is in milliseconds from the beginning of the stream
mCastSession!!.remoteMediaClient?.seek(position.toLong())
}
else -> {}
}
restartTrickplayTimer()
}
private fun togglePlayback() {
...
PlaybackState.IDLE -> when (mLocation) {
...
PlaybackLocation.REMOTE -> {
if (mCastSession != null && mCastSession!!.isConnected) {
loadRemoteMedia(mSeekbar!!.progress, true)
}
}
else -> {}
}
...
}
override fun onPause() {
...
mCastContext!!.sessionManager.removeSessionManagerListener(
mSessionManagerListener!!, CastSession::class.java)
}
override fun onResume() {
Log.d(TAG, "onResume() was called")
mCastContext!!.sessionManager.addSessionManagerListener(
mSessionManagerListener!!, CastSession::class.java)
if (mCastSession != null && mCastSession!!.isConnected) {
updatePlaybackLocation(PlaybackLocation.REMOTE)
} else {
updatePlaybackLocation(PlaybackLocation.LOCAL)
}
super.onResume()
}
updatePlayButton
yöntemi için isConnected
değişkeninin değerini değiştirin:
private fun updatePlayButton(state: PlaybackState?) {
...
val isConnected = (mCastSession != null
&& (mCastSession!!.isConnected || mCastSession!!.isConnecting))
...
}
Şimdi, uygulamayı mobil cihazınızda çalıştırmak için Çalıştır düğmesini tıklayın. Yayın cihazınıza bağlanın ve bir videoyu oynatmaya başlayın. Videonun alıcıda oynatıldığını görüyor olmanız gerekir.
7. Mini kumanda
Yayın Tasarımı Kontrol Listesi, tüm Cast uygulamalarında kullanıcı geçerli içerik sayfasından ayrıldığında görünen bir mini denetleyici olmasını gerektirir. Mini kumanda, geçerli Yayın oturumu için anında erişim ve görünür bir hatırlatıcı sağlar.
Cast SDK'sı, mini kumandayı göstermek istediğiniz etkinliklerin uygulama düzen dosyasına eklenebilecek özel bir görünüm (MiniControllerFragment
) sağlar.
res/layout/player_activity.xml
ve res/layout/video_browser.xml
kodunun altına aşağıdaki parça tanımını ekleyin:
<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"/>
Uygulamayı çalıştırmak ve video yayınlamak için Çalıştır düğmesini tıklayın. Alıcıda oynatma başladığında, her etkinliğin alt kısmında mini kumandanın belirdiğini görürsünüz. Mini kumandayı kullanarak uzaktan oynatmayı kontrol edebilirsiniz. Göz atma etkinliği ile yerel oynatıcı etkinliği arasında gezinirseniz mini kumandanın durumu, alıcının medya oynatma durumuyla senkronize olmalıdır.
8. Bildirim ve kilit ekranı
Google Cast tasarımıyla ilgili yapılacaklar listesi, gönderen uygulamanın bir bildirim ve kilit ekranındaki medya denetimlerini uygulamasını gerektirir.
Cast SDK'sı, gönderen uygulamanın bildirim ve kilit ekranı için medya kontrolleri oluşturmasına yardımcı olmak üzere bir MediaNotificationService
sağlar. Hizmet, gradle tarafından otomatik olarak uygulamanızın manifest dosyasıyla birleştirilir.
MediaNotificationService
, gönderen yayın sırasında arka planda çalışır ve geçerli yayın öğesine ilişkin küçük resim ve meta veriler, bir oynat/duraklat düğmesi ve bir durdurma düğmesi içeren bir bildirim gösterir.
CastContext
başlatılırken CastOptions
ile bildirim ve kilit ekranı kontrolleri etkinleştirilebilir. Bildirim ve kilit ekranı için medya kontrolleri varsayılan olarak açıktır. Bildirim etkin olduğu sürece kilit ekranı özelliği de etkin halde kalır.
CastOptionsProvider
öğesini düzenleyin ve getCastOptions
uygulamasını bu kodla eşleşecek şekilde değiştirin:
import com.google.android.gms.cast.framework.media.CastMediaOptions
import com.google.android.gms.cast.framework.media.NotificationOptions
override fun getCastOptions(context: Context): CastOptions {
val notificationOptions = NotificationOptions.Builder()
.setTargetActivityClassName(VideoBrowserActivity::class.java.name)
.build()
val mediaOptions = CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.build()
return CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.app_id))
.setCastMediaOptions(mediaOptions)
.build()
}
Uygulamayı mobil cihazınızda çalıştırmak için Çalıştır düğmesini tıklayın. Video yayınlayın ve örnek uygulamadan ayrılın. Alıcıda gösterilmekte olan video için bildirim gösterilir. Mobil cihazınızı kilitlediğinizde, kilit ekranında Yayın cihazında medya oynatmaya ilişkin kontroller gösterilecektir.
9. Tanıtım yer paylaşımı
Google Cast tasarımıyla ilgili yapılacaklar listesi, bir gönderen uygulamanın, gönderen uygulamasının artık yayınlamayı desteklediğini ve Google Cast'i kullanmaya yeni başlayan kullanıcılara da yardımcı olduğunu bildirmek için mevcut kullanıcılara Yayın düğmesini tanıtmasını gerektirir.
Cast SDK'sı, kullanıcılara ilk gösterildiğinde Yayın düğmesini vurgulamak için kullanılabilen özel bir görünüm (IntroductoryOverlay
) sağlar. VideoBrowserActivity
için şu kodu ekleyin:
import com.google.android.gms.cast.framework.IntroductoryOverlay
import android.os.Looper
private var mIntroductoryOverlay: IntroductoryOverlay? = null
private fun showIntroductoryOverlay() {
mIntroductoryOverlay?.remove()
if (mediaRouteMenuItem?.isVisible == true) {
Looper.myLooper().run {
mIntroductoryOverlay = com.google.android.gms.cast.framework.IntroductoryOverlay.Builder(
this@VideoBrowserActivity, mediaRouteMenuItem!!)
.setTitleText("Introducing Cast")
.setSingleTime()
.setOnOverlayDismissedListener(
object : IntroductoryOverlay.OnOverlayDismissedListener {
override fun onOverlayDismissed() {
mIntroductoryOverlay = null
}
})
.build()
mIntroductoryOverlay!!.show()
}
}
}
Şimdi CastStateListener
ekleyip onCreate
yöntemini değiştirerek bir yayın cihazı kullanılabilir olduğunda showIntroductoryOverlay
yöntemini çağırın ve onResume
ile onPause
yöntemlerini aşağıdakilerle eşleşecek şekilde geçersiz kılın:
import com.google.android.gms.cast.framework.CastState
import com.google.android.gms.cast.framework.CastStateListener
private var mCastStateListener: CastStateListener? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.video_browser)
setupActionBar()
mCastStateListener = object : CastStateListener {
override fun onCastStateChanged(newState: Int) {
if (newState != CastState.NO_DEVICES_AVAILABLE) {
showIntroductoryOverlay()
}
}
}
mCastContext = CastContext.getSharedInstance(this)
}
override fun onResume() {
super.onResume()
mCastContext?.addCastStateListener(mCastStateListener!!)
}
override fun onPause() {
super.onPause()
mCastContext?.removeCastStateListener(mCastStateListener!!)
}
Uygulama verilerini temizleyin veya uygulamayı cihazınızdan kaldırın. Ardından, uygulamayı mobil cihazınızda çalıştırmak için Çalıştır düğmesini tıklayın. Tanıtım amaçlı yer paylaşımını görürsünüz (yer paylaşımı görünmüyorsa uygulama verilerini temizleyin).
10. Genişletilmiş kumanda
Google Cast tasarım listesi, gönderen uygulamanın, yayınlanmakta olan medya için genişletilmiş denetleyici sağlamasını gerektirir. Genişletilmiş kumanda, mini kumandanın tam ekran sürümüdür.
Cast SDK'sı, genişletilmiş kumanda için ExpandedControllerActivity
adlı bir widget sağlar. Bu, Yayınla düğmesi eklemek için alt sınıfa getirmeniz gereken soyut bir sınıftır.
Öncelikle, genişletilmiş denetleyicinin Yayın düğmesini sağlaması için expanded_controller.xml
adlı yeni bir menü kaynak dosyası oluşturun:
<?xml version="1.0" encoding="utf-8"?>
<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>
com.google.sample.cast.refplayer
paketinde yeni bir expandedcontrols
paketi oluşturun. Ardından com.google.sample.cast.refplayer.expandedcontrols
paketinde ExpandedControlsActivity.kt
adlı yeni bir dosya oluşturun.
package com.google.sample.cast.refplayer.expandedcontrols
import android.view.Menu
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
import com.google.sample.cast.refplayer.R
import com.google.android.gms.cast.framework.CastButtonFactory
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
}
}
Şimdi AndroidManifest.xml
öğesinin içinde, OPTIONS_PROVIDER_CLASS_NAME
öğesinin üzerindeki application
etiketinin içinde ExpandedControlsActivity
öğesini tanımlayın:
<application>
...
<activity
android:name="com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/Theme.CastVideosDark"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.google.sample.cast.refplayer.VideoBrowserActivity"/>
</activity>
...
</application>
CastOptionsProvider
öğesini düzenleyin ve hedef etkinliği ExpandedControlsActivity
değerine ayarlamak için NotificationOptions
ve CastMediaOptions
değerlerini değiştirin:
import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity
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()
}
Uzak medya yüklendiğinde ExpandedControlsActivity
öğesini görüntülemek için LocalPlayerActivity
loadRemoteMedia
yöntemini güncelleyin:
import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
if (mCastSession == null) {
return
}
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(buildMediaInfo())
.setAutoplay(autoPlay)
.setCurrentTime(position.toLong()).build())
}
Uygulamayı mobil cihazınızda çalıştırmak ve video yayınlamak için Çalıştır düğmesini tıklayın. Genişletilmiş denetleyici gösterilir. Video listesine geri dönün. Mini kumandayı tıkladığınızda genişletilmiş kumanda tekrar yüklenir. Bildirimi görmek için uygulamanın dışına gidin. Genişletilmiş kumandayı yüklemek için bildirim resmini tıklayın.
11. Cast Connect desteği ekleyin
Cast Connect kitaplığı, mevcut gönderen uygulamalarının Cast protokolü aracılığıyla Android TV uygulamalarıyla iletişim kurmasına olanak tanır. Cast Connect, Android TV uygulamanızın alıcı görevi gördüğü Cast altyapısını temel alır.
Bağımlılıklar
Not: Cast Connect'i uygulamak için play-services-cast-framework
, 19.0.0
veya daha yüksek olmalıdır.
LaunchOptions
Android Alıcı olarak da bilinen Android TV uygulamasını başlatmak için LaunchOptions
nesnesinde setAndroidReceiverCompatible
işaretini true olarak ayarlamamız gerekir. Bu LaunchOptions
nesnesi, alıcının nasıl başlatılacağını belirler ve CastOptionsProvider
sınıfı tarafından döndürülen CastOptions
öğesine iletilir. Yukarıda bahsedilen işaretin false
değerine ayarlanması, Cast Developer Console'da tanımlanan Uygulama Kimliği için web alıcısı başlatır.
CastOptionsProvider.kt
dosyasında getCastOptions
yöntemine aşağıdaki kodu ekleyin:
import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
.setAndroidReceiverCompatible(true)
.build()
return new CastOptions.Builder()
.setLaunchOptions(launchOptions)
...
.build()
Başlatma Kimlik Bilgilerini Ayarla
Gönderen tarafında, oturuma kimlerin katıldığını temsil etmesi için CredentialsData
değerini belirtebilirsiniz. credentials
, ATV uygulamanız tarafından anlaşılabildiği sürece kullanıcı tanımlı bir dizedir. CredentialsData
, Android TV uygulamanıza yalnızca başlatma veya katılma sırasında aktarılır. Bağlıyken tekrar ayarlarsanız Android TV uygulamanıza aktarılmaz.
Başlatma Kimlik Bilgilerinin ayarlanması için CredentialsData
ürününün tanımlanması ve LaunchOptions
nesnesine geçirilmesi gerekir. Aşağıdaki kodu CastOptionsProvider.kt
dosyanızdaki getCastOptions
yöntemine ekleyin:
import com.google.android.gms.cast.CredentialsData
...
val credentialsData = CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build()
val launchOptions = LaunchOptions.Builder()
...
.setCredentialsData(credentialsData)
.build()
LoadRequest'te Kimlik Bilgilerini Belirleme
Web Alıcısı ve Android TV uygulamanız credentials
ürününü farklı şekilde ele alıyorsa her biri için ayrı bir credentials
tanımlamanız gerekebilir. Bu işlemi yapmak için LocalPlayerActivity.kt
dosyanıza loadRemoteMedia
işlevinin altına aşağıdaki kodu ekleyin:
remoteMediaClient.load(MediaLoadRequestData.Builder()
...
.setCredentials("user-credentials")
.setAtvCredentials("atv-user-credentials")
.build())
Göndereninizin yayın yaptığı alıcı uygulamaya bağlı olarak, SDK artık geçerli oturum için hangi kimlik bilgilerinin kullanılacağını otomatik olarak işliyor.
Cast Connect'i test etme
Android TV APK'sını Google TV Yüklü Chromecast'e yükleme adımları
- Android TV cihazınızın IP adresini bulun. Bu özellik genellikle Ayarlar > Ağ ve İnternet > (Cihazınızın bağlı olduğu ağ adı) altından bulunur. Sağ tarafta, ayrıntıları ve cihazınızın ağdaki IP'sini gösterir.
- Cihazınıza terminali kullanarak ADB aracılığıyla bağlanmak için IP adresini kullanın:
$ adb connect <device_ip_address>:5555
- Terminal pencerenizden, bu codelab'in başında indirdiğiniz codelab örneklerinin üst düzey klasörüne gidin. Örneğin:
$ cd Desktop/android_codelab_src
- Aşağıdaki komutu çalıştırarak bu klasördeki .apk dosyasını Android TV'nize yükleyin:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Artık Android TV cihazınızdaki Uygulamalarınız menüsünde Video Yayınla adıyla bir uygulamayı görebilmeniz gerekir.
- Android Studio projenize dönün ve gönderen uygulamasını fiziksel mobil cihazınıza yükleyip çalıştırmak için Çalıştır düğmesini tıklayın. Sağ üst köşedeki yayınlama simgesini tıklayın ve mevcut seçenekler arasından Android TV cihazınızı seçin. Artık Android TV cihazınızda Android TV uygulamasını görüyor olmanız gerekir. Video oynattığınızda video oynatmayı Android TV uzaktan kumandanızı kullanarak kontrol edebilirsiniz.
12. Yayın widget'larını özelleştirme
Renkleri ayarlayarak, düğmelerin stilini, metni ve küçük resim görünümünü ayarlayarak ve görüntülenecek düğme türlerini seçerek Yayın widget'larını özelleştirebilirsiniz.
res/values/styles_castvideo.xml
öğelerini güncelle
<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
...
<item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
<item name="castIntroOverlayStyle">@style/CustomCastIntroOverlay</item>
<item name="castMiniControllerStyle">@style/CustomCastMiniController</item>
<item name="castExpandedControllerStyle">@style/CustomCastExpandedController</item>
<item name="castExpandedControllerToolbarStyle">
@style/ThemeOverlay.AppCompat.ActionBar
</item>
...
</style>
Aşağıdaki özel temaları beyan edin:
<!-- Customize Cast Button -->
<style name="CustomMediaRouterTheme" parent="Theme.MediaRouter">
<item name="mediaRouteButtonStyle">@style/CustomMediaRouteButtonStyle</item>
</style>
<style name="CustomMediaRouteButtonStyle" parent="Widget.MediaRouter.Light.MediaRouteButton">
<item name="mediaRouteButtonTint">#EEFF41</item>
</style>
<!-- Customize Introductory Overlay -->
<style name="CustomCastIntroOverlay" parent="CastIntroOverlay">
<item name="castButtonTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Button</item>
<item name="castTitleTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Title</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Button" parent="android:style/TextAppearance">
<item name="android:textColor">#FFFFFF</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Title" parent="android:style/TextAppearance.Large">
<item name="android:textColor">#FFFFFF</item>
</style>
<!-- Customize Mini Controller -->
<style name="CustomCastMiniController" parent="CastMiniController">
<item name="castShowImageThumbnail">true</item>
<item name="castTitleTextAppearance">@style/TextAppearance.AppCompat.Subhead</item>
<item name="castSubtitleTextAppearance">@style/TextAppearance.AppCompat.Caption</item>
<item name="castBackground">@color/accent</item>
<item name="castProgressBarColor">@color/orange</item>
</style>
<!-- Customize Expanded Controller -->
<style name="CustomCastExpandedController" parent="CastExpandedController">
<item name="castButtonColor">#FFFFFF</item>
<item name="castPlayButtonDrawable">@drawable/cast_ic_expanded_controller_play</item>
<item name="castPauseButtonDrawable">@drawable/cast_ic_expanded_controller_pause</item>
<item name="castStopButtonDrawable">@drawable/cast_ic_expanded_controller_stop</item>
</style>
13. Tebrikler
Artık Android'de Cast SDK'sı widget'larını kullanarak bir video uygulamasını Cast için nasıl etkinleştireceğinizi biliyorsunuz.
Daha ayrıntılı bilgi için Android Gönderen geliştirici kılavuzuna bakın.