1. Ringkasan
Codelab ini akan mengajarkan cara memodifikasi aplikasi video Android yang ada untuk mentransmisikan konten di perangkat yang kompatibel dengan Google Cast.
Apa itu Google Cast?
Google Cast memungkinkan pengguna mentransmisikan konten dari perangkat seluler ke TV. Pengguna kemudian dapat menggunakan perangkat seluler sebagai remote control untuk pemutaran media di TV.
Google Cast SDK memungkinkan Anda memperluas aplikasi untuk mengontrol TV atau sistem suara. Cast SDK memungkinkan Anda menambahkan komponen UI yang diperlukan berdasarkan Checklist Desain Google Cast.
Checklist Desain Google Cast disediakan untuk menyederhanakan pengalaman pengguna Cast dan membuatnya dapat diprediksi di semua platform yang didukung.
Apa yang akan kita buat?
Setelah menyelesaikan codelab ini, Anda akan memiliki aplikasi video Android yang dapat mentransmisikan video ke perangkat yang kompatibel untuk Google Cast.
Yang akan Anda pelajari
- Cara menambahkan Google Cast SDK ke aplikasi video sampel.
- Cara menambahkan tombol Cast untuk memilih perangkat Google Cast.
- Cara menghubungkan ke perangkat Cast dan meluncurkan penerima media.
- Cara mentransmisikan video.
- Cara menambahkan pengontrol mini Cast ke aplikasi Anda.
- Cara mendukung notifikasi media dan kontrol layar kunci.
- Cara menambahkan pengontrol yang diperluas.
- Cara menyediakan overlay perkenalan.
- Cara menyesuaikan widget Cast.
- Cara berintegrasi dengan Cast Connect
Yang Anda butuhkan
- Android SDK terbaru.
- Android Studio versi 3.2+
- Satu perangkat seluler dengan Android 4.1+ Jelly Bean (API level 16).
- Kabel data USB untuk menyambungkan perangkat seluler ke komputer pengembangan.
- Perangkat Google Cast seperti Chromecast atau Android TV yang dikonfigurasi dengan akses internet.
- TV atau monitor dengan input HDMI.
- Chromecast dengan Google TV diperlukan untuk menguji integrasi Cast Connect, tetapi bersifat opsional untuk bagian Codelab lainnya. Jika Anda tidak memilikinya, jangan ragu untuk melewati langkah Tambahkan Dukungan Cast Connect, di akhir tutorial ini.
Pengalaman
- Sebelumnya, Anda harus memiliki pengetahuan pengembangan Kotlin dan Android.
- Anda juga perlu memiliki pengetahuan tentang menonton TV :)
Bagaimana Anda akan menggunakan tutorial ini?
Bagaimana Anda menilai pengalaman membuat aplikasi Android Anda?
Bagaimana Anda menilai pengalaman menonton TV Anda?
2. Mendapatkan kode contoh
Anda dapat mendownload semua kode contoh ke komputer Anda...
dan mengekstrak file zip yang didownload.
3. Menjalankan aplikasi contoh
Pertama, mari kita lihat bagaimana tampilan contoh aplikasi yang sudah selesai. Aplikasi ini adalah pemutar video dasar. Pengguna dapat memilih video dari daftar dan kemudian dapat memutar video secara lokal di perangkat atau mentransmisikannya ke perangkat Google Cast.
Setelah mendownload kode, petunjuk berikut menjelaskan cara membuka dan menjalankan contoh aplikasi yang telah selesai di Android Studio:
Pilih Import Project di layar sambutan atau opsi menu File > New > Import Project....
Pilih direktori app-done
dari folder kode contoh dan klik OK.
Klik File > Sync Project with Gradle Files.
Aktifkan proses debug USB di perangkat Android Anda – di Android 4.2 dan versi yang lebih baru, layar Opsi developer disembunyikan secara default. Agar terlihat, buka Setelan > Tentang ponsel lalu ketuk Nomor versi tujuh kali. Kembali ke layar sebelumnya, buka Sistem > Lanjutan dan ketuk Opsi developer di dekat bagian bawah, lalu ketuk Proses debug USB untuk mengaktifkannya.
Colokkan perangkat Android Anda dan klik tombol Run di Android Studio. Anda akan melihat aplikasi video bernama Cast Videos muncul setelah beberapa detik.
Klik tombol Cast di aplikasi video dan pilih perangkat Google Cast.
Pilih video dan klik tombol putar.
Video akan mulai diputar di perangkat Google Cast.
Pengontrol yang diperluas akan ditampilkan. Anda dapat menggunakan tombol putar/jeda untuk mengontrol pemutaran.
Kembali ke daftar video.
Pengontrol mini kini terlihat di bagian bawah layar.
Klik tombol jeda di pengontrol mini untuk menjeda video pada penerima. Klik tombol putar di pengontrol mini untuk melanjutkan pemutaran video lagi.
Klik tombol layar utama perangkat seluler. Tarik turun notifikasi dan Anda akan melihat notifikasi untuk sesi Cast.
Kunci ponsel dan saat membuka kunci, Anda akan melihat notifikasi di layar kunci untuk mengontrol pemutaran media atau menghentikan transmisi.
Kembali ke aplikasi video dan klik tombol Cast untuk menghentikan transmisi di perangkat Google Cast.
Pertanyaan umum (FAQ)
4. Menyiapkan project awal
Kita perlu menambahkan dukungan untuk Google Cast ke aplikasi awal yang Anda download. Berikut adalah beberapa istilah Google Cast yang akan kita gunakan dalam codelab ini:
- aplikasi pengirim berjalan di perangkat seluler atau laptop,
- aplikasi penerima berjalan di perangkat Google Cast.
Sekarang Anda siap untuk mengerjakan project awal menggunakan Android Studio:
- Pilih direktori
app-start
dari kode contoh yang Anda download (Pilih Import Project di layar sambutan atau opsi menu File > New > Import Project...). - Klik tombol Sync Project with Gradle Files.
- Klik tombol Run untuk menjalankan aplikasi dan menjelajahi UI.
Desain aplikasi
Aplikasi ini mengambil daftar video dari server web jarak jauh dan menyediakan daftar untuk dijelajahi pengguna. Pengguna dapat memilih video untuk melihat detailnya atau memutar video secara lokal di perangkat seluler.
Aplikasi ini terdiri dari dua aktivitas utama: VideoBrowserActivity
dan LocalPlayerActivity
. Untuk mengintegrasikan fungsi Google Cast, Aktivitas perlu mewarisi dari AppCompatActivity
atau induknya, FragmentActivity
. Batasan ini ada karena kita perlu menambahkan MediaRouteButton
(disediakan di support library MediaRouter) sebagai MediaRouteActionProvider
dan ini hanya akan berfungsi jika aktivitas mewarisi dari class yang disebutkan di atas. Support library MediaRouter bergantung pada support library AppCompat yang menyediakan class yang diperlukan.
VideoBrowserActivity
Aktivitas ini berisi Fragment
(VideoBrowserFragment
). Daftar ini didukung oleh ArrayAdapter
(VideoListAdapter
). Daftar video dan metadata terkaitnya dihosting di server jarak jauh sebagai file JSON. AsyncTaskLoader
(VideoItemLoader
) mengambil JSON ini dan memprosesnya untuk membuat daftar objek MediaItem
.
Objek MediaItem
memodelkan video dan metadatanya yang terkait, seperti judul, deskripsi, URL untuk streaming, URL untuk gambar pendukung, dan Trek Teks terkait (untuk teks tertutup) jika ada. Objek MediaItem
diteruskan di antara aktivitas, sehingga MediaItem
memiliki metode utilitas untuk mengonversinya menjadi Bundle
dan sebaliknya.
Saat loader membuat daftar MediaItems
, loader akan meneruskan daftar tersebut ke VideoListAdapter
yang kemudian menyajikan daftar MediaItems
dalam VideoBrowserFragment
. Pengguna akan diberikan daftar thumbnail video dengan deskripsi singkat untuk setiap video. Saat item dipilih, MediaItem
yang sesuai akan dikonversi menjadi Bundle
dan diteruskan ke LocalPlayerActivity
.
LocalPlayerActivity
Aktivitas ini menampilkan metadata tentang video tertentu dan memungkinkan pengguna memutar video secara lokal di perangkat seluler.
Aktivitas ini menghosting VideoView
, beberapa kontrol media, dan area teks untuk menampilkan deskripsi video yang dipilih. Pemutar menutupi bagian atas layar, dengan menyisakan ruang untuk deskripsi mendetail video di bawahnya. Pengguna dapat memutar/menjeda atau mencari pemutaran lokal video.
Dependensi
Karena menggunakan AppCompatActivity
, kita memerlukan support library AppCompat. Untuk mengelola daftar video dan mendapatkan gambar secara asinkron untuk daftar, kita menggunakan library Volley.
Pertanyaan umum (FAQ)
5. Menambahkan tombol Cast
Aplikasi yang kompatibel untuk Cast menampilkan tombol Cast di setiap aktivitasnya. Mengklik tombol Cast akan menampilkan daftar perangkat Cast yang dapat dipilih pengguna. Jika pengguna memutar konten secara lokal di perangkat pengirim, memilih perangkat Cast akan memulai atau melanjutkan pemutaran di perangkat Cast tersebut. Kapan saja selama sesi Cast, pengguna dapat mengklik tombol Cast dan menghentikan transmisi aplikasi ke perangkat Cast. Pengguna harus dapat menghubungkan ke atau memutuskan sambungan dari perangkat Cast saat dalam aktivitas aplikasi Anda, seperti yang dijelaskan dalam Checklist Desain Google Cast.
Dependensi
Perbarui file build.gradle aplikasi untuk menyertakan dependensi library yang diperlukan:
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"
}
Sinkronkan project untuk mengonfirmasikan project dibuat tanpa error.
Inisialisasi
Framework Cast memiliki objek singleton global, CastContext
, yang mengoordinasikan semua interaksi Cast.
Anda harus menerapkan antarmuka OptionsProvider
untuk menyediakan CastOptions
yang diperlukan untuk menginisialisasi singleton CastContext
. Opsi yang paling penting adalah ID aplikasi penerima, yang digunakan untuk memfilter hasil penemuan perangkat Cast dan meluncurkan aplikasi penerima saat sesi Cast dimulai.
Saat mengembangkan aplikasi yang kompatibel untuk Cast, Anda harus mendaftar sebagai developer Cast, lalu mendapatkan ID aplikasi untuk aplikasi tersebut. Untuk codelab ini, kita akan menggunakan contoh ID aplikasi.
Tambahkan file CastOptionsProvider.kt
baru berikut ke paket com.google.sample.cast.refplayer
project:
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
}
}
Sekarang deklarasikan OptionsProvider
dalam tag "application
" dari file AndroidManifest.xml
aplikasi:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />
Menginisialisasi dengan mudah CastContext
dalam metode onCreate VideoBrowserActivity
:
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)
}
Tambahkan logika inisialisasi yang sama ke LocalPlayerActivity
.
Tombol Cast
Setelah CastContext
diinisialisasi, kita perlu menambahkan tombol Cast untuk memungkinkan pengguna memilih perangkat Cast. Tombol Transmisi diimplementasikan oleh MediaRouteButton
dari support library MediaRouter. Seperti ikon tindakan apa pun yang dapat ditambahkan ke aktivitas (menggunakan ActionBar
atau Toolbar
), Anda harus menambahkan item menu yang sesuai ke menu terlebih dahulu.
Edit file res/menu/browse.xml
dan tambahkan item MediaRouteActionProvider
di menu sebelum item setelan:
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
Ganti metode onCreateOptionsMenu()
VideoBrowserActivity
dengan menggunakan CastButtonFactory
untuk menghubungkan MediaRouteButton
ke framework Cast:
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
}
Ganti onCreateOptionsMenu
di LocalPlayerActivity
dengan cara yang sama.
Klik tombol Run untuk menjalankan aplikasi di perangkat seluler Anda. Anda akan melihat tombol Cast di panel tindakan aplikasi dan saat diklik, tombol Cast akan mencantumkan perangkat Cast di jaringan lokal. Penemuan perangkat dikelola secara otomatis oleh CastContext
. Pilih perangkat Cast dan contoh aplikasi penerima yang akan dimuat di perangkat Cast. Anda dapat menavigasi antara aktivitas penjelajahan dan aktivitas pemutar lokal, dan status tombol Cast akan tetap sinkron.
Kami belum menyediakan dukungan untuk pemutaran media, jadi Anda belum dapat memutar video di perangkat Cast. Klik tombol Cast untuk memutuskan sambungan.
6. Mentransmisikan konten video
Kami akan memperluas contoh aplikasi untuk memutar video dari jarak jauh di perangkat Cast juga. Untuk melakukannya, kita harus memantau berbagai peristiwa yang dihasilkan oleh framework Cast.
Mentransmisikan media
Pada level tinggi, jika ingin memutar media di perangkat Cast, Anda perlu melakukan hal berikut:
- Buat objek
MediaInfo
yang memodelkan item media. - Hubungkan ke perangkat Cast dan luncurkan aplikasi penerima.
- Muat objek
MediaInfo
ke penerima Anda dan putar kontennya. - Lacak status media.
- Kirim perintah pemutaran ke penerima berdasarkan interaksi pengguna.
Kita telah menyelesaikan Langkah 2 di bagian sebelumnya. Langkah 3 mudah dilakukan dengan framework Cast. Langkah 1 berarti memetakan satu objek ke objek lainnya; MediaInfo
adalah sesuatu yang dipahami oleh framework Cast dan MediaItem
adalah enkapsulasi aplikasi kita untuk item media; kita dapat memetakan MediaItem
ke MediaInfo
dengan mudah.
Aplikasi contoh LocalPlayerActivity
sudah membedakan antara pemutaran lokal vs jarak jauh dengan menggunakan enum ini:
private var mLocation: PlaybackLocation? = null
enum class PlaybackLocation {
LOCAL, REMOTE
}
enum class PlaybackState {
PLAYING, PAUSED, BUFFERING, IDLE
}
Dalam codelab ini Anda tidak perlu memahami keseluruhan cara kerja semua logika pemutar contoh. Tetapi Anda perlu memahami bahwa pemutar media aplikasi harus dimodifikasi agar mengetahui dua lokasi pemutaran dengan cara yang serupa.
Saat ini pemutar lokal selalu dalam status pemutaran lokal karena belum mengetahui apa pun tentang status Transmisi. Kita perlu mengupdate UI berdasarkan transisi status yang terjadi dalam framework Cast. Misalnya, jika mulai melakukan transmisi, kita perlu menghentikan pemutaran lokal dan menonaktifkan beberapa kontrol. Demikian pula, jika menghentikan transmisi saat berada dalam aktivitas ini, kita perlu beralih ke pemutaran lokal. Untuk menanganinya, kita perlu memantau berbagai peristiwa yang dihasilkan oleh framework Cast.
Pengelolaan sesi transmisi
Untuk framework Cast, sesi Cast menggabungkan langkah-langkah untuk menghubungkan ke perangkat, meluncurkan (atau bergabung), menghubungkan ke aplikasi penerima, dan menginisialisasi saluran kontrol media jika sesuai. Saluran kontrol media adalah cara framework Cast mengirim dan menerima pesan dari pemutar media penerima.
Sesi Transmisi akan dimulai secara otomatis saat pengguna memilih perangkat dari tombol Cast, dan akan dihentikan secara otomatis saat pengguna memutuskan sambungan. Menyambungkan kembali ke sesi penerima karena masalah jaringan juga ditangani secara otomatis oleh SDK Cast.
Mari tambahkan SessionManagerListener
ke LocalPlayerActivity
:
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()
}
}
}
Dalam aktivitas LocalPlayerActivity
, kita ingin diberi tahu saat tersambung atau terputus dari perangkat Cast sehingga kita dapat beralih ke atau dari pemutar lokal. Perhatikan, konektivitas dapat terganggu bukan hanya oleh instance aplikasi Anda yang berjalan pada perangkat seluler, tetapi juga bisa terganggu oleh instance aplikasi lainnya (atau hal lainnya) yang berjalan pada perangkat seluler berbeda.
Sesi yang saat ini aktif dapat diakses sebagai SessionManager.getCurrentSession()
. Sesi dibuat dan dihapus secara otomatis sebagai respons terhadap interaksi pengguna dengan dialog Cast.
Kita harus mendaftarkan pemroses sesi dan menginisialisasi beberapa variabel yang akan kita gunakan dalam aktivitas. Ubah metode LocalPlayerActivity
onCreate
menjadi:
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)
}
}
...
}
Memuat media
Di SDK Cast, RemoteMediaClient
menyediakan kumpulan API yang mudah digunakan untuk mengelola pemutaran media jarak jauh pada penerima. Untuk CastSession
yang mendukung pemutaran media, instance RemoteMediaClient
akan dibuat secara otomatis oleh SDK. Ini dapat diakses dengan memanggil metode getRemoteMediaClient()
pada instance CastSession
. Tambahkan metode berikut ke LocalPlayerActivity
untuk memuat video yang saat ini dipilih di penerima:
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()
}
}
Sekarang perbarui berbagai metode yang ada untuk menggunakan logika sesi Cast guna mendukung pemutaran jarak jauh:
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()
}
Untuk metode updatePlayButton
, ubah nilai variabel isConnected
:
private fun updatePlayButton(state: PlaybackState?) {
...
val isConnected = (mCastSession != null
&& (mCastSession!!.isConnected || mCastSession!!.isConnecting))
...
}
Sekarang, klik tombol Run untuk menjalankan aplikasi di perangkat seluler Anda. Sambungkan ke perangkat Cast dan mulai putar video. Anda akan melihat video yang diputar pada penerima.
7. Pengontrol mini
Checklist Desain Cast mengharuskan semua aplikasi Cast menyediakan pengontrol mini yang muncul saat pengguna keluar dari halaman konten saat ini. Pengontrol mini menyediakan akses instan dan pengingat yang terlihat untuk sesi Cast saat ini.
SDK Cast menyediakan tampilan kustom, MiniControllerFragment
, yang dapat ditambahkan ke file tata letak aplikasi dari aktivitas tempat Anda ingin menampilkan pengontrol mini.
Tambahkan definisi fragmen berikut di bagian bawah res/layout/player_activity.xml
dan res/layout/video_browser.xml
:
<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"/>
Klik tombol Run untuk menjalankan aplikasi dan mentransmisikan video. Saat pemutaran dimulai pada penerima, Anda akan melihat pengontrol mini muncul di bagian bawah setiap aktivitas. Anda dapat mengontrol pemutaran jarak jauh menggunakan pengontrol mini. Jika Anda bernavigasi antara aktivitas penjelajahan dan aktivitas pemutar lokal, status pengontrol mini harus tetap sinkron dengan status pemutaran media penerima.
8. Notifikasi dan layar kunci
Checklist desain Google Cast memerlukan aplikasi pengirim untuk menerapkan kontrol media dari notifikasi dan layar kunci.
SDK Cast menyediakan MediaNotificationService
untuk membantu aplikasi pengirim membuat kontrol media untuk notifikasi dan layar kunci. Layanan secara otomatis akan digabungkan ke dalam manifes aplikasi Anda berdasarkan gradle.
MediaNotificationService
akan berjalan di latar belakang saat pengirim melakukan transmisi, dan akan menampilkan notifikasi dengan thumbnail gambar dan metadata tentang item transmisi saat ini, tombol putar/jeda, dan tombol berhenti.
Kontrol notifikasi dan layar kunci dapat diaktifkan dengan CastOptions
saat menginisialisasi CastContext
. Kontrol media untuk notifikasi dan layar kunci diaktifkan secara default. Fitur layar kunci diaktifkan selama notifikasi diaktifkan.
Edit CastOptionsProvider
dan ubah implementasi getCastOptions
agar cocok dengan kode ini:
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()
}
Klik tombol Run untuk menjalankan aplikasi di perangkat seluler Anda. Transmisikan video dan keluar dari aplikasi contoh. Harus ada notifikasi untuk video yang sedang diputar di penerima. Kunci perangkat seluler Anda dan layar kunci akan menampilkan kontrol untuk pemutaran media di perangkat Cast.
9. Overlay perkenalan
Checklist desain Google Cast memerlukan aplikasi pengirim untuk memperkenalkan tombol Cast kepada pengguna yang ada guna memberi tahu bahwa aplikasi pengirim kini mendukung transmisi dan juga membantu pengguna yang baru menggunakan Google Cast.
SDK Cast menyediakan tampilan kustom, IntroductoryOverlay
, yang dapat digunakan untuk menyorot tombol Cast saat pertama kali ditampilkan kepada pengguna. Tambahkan kode berikut ke VideoBrowserActivity
:
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()
}
}
}
Sekarang, tambahkan CastStateListener
dan panggil metode showIntroductoryOverlay
saat perangkat Cast tersedia dengan mengubah metode onCreate
dan mengganti metode onResume
dan onPause
agar cocok dengan kode berikut:
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!!)
}
Hapus data aplikasi atau hapus aplikasi dari perangkat Anda. Kemudian, klik tombol Run untuk menjalankan aplikasi di perangkat seluler dan Anda akan melihat overlay perkenalan (hapus data aplikasi jika overlay tidak ditampilkan).
10. Pengontrol yang diperluas
Checklist desain Google Cast mengharuskan aplikasi pengirim untuk menyediakan pengontrol yang diperluas untuk media yang ditransmisi. Pengontrol yang diperluas adalah versi layar penuh dari pengontrol mini.
SDK Cast menyediakan widget untuk pengontrol yang diperluas yang disebut ExpandedControllerActivity
. Ini adalah class abstrak yang harus dibuat subclass untuk menambahkan tombol Cast.
Pertama, buat file resource menu baru, yang disebut expanded_controller.xml
, agar pengontrol yang diperluas dapat menyediakan tombol Cast:
<?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>
Buat paket baru expandedcontrols
dalam paket com.google.sample.cast.refplayer
. Selanjutnya, buat file baru bernama ExpandedControlsActivity.kt
dalam paket com.google.sample.cast.refplayer.expandedcontrols
.
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
}
}
Sekarang, deklarasikan ExpandedControlsActivity
di AndroidManifest.xml
dalam tag application
di atas OPTIONS_PROVIDER_CLASS_NAME
:
<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>
Edit CastOptionsProvider
dan ubah NotificationOptions
dan CastMediaOptions
untuk menetapkan aktivitas target ke ExpandedControlsActivity
:
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()
}
Perbarui metode LocalPlayerActivity
loadRemoteMedia
untuk menampilkan ExpandedControlsActivity
saat media jarak jauh dimuat:
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())
}
Klik tombol Run untuk menjalankan aplikasi di perangkat seluler dan mentransmisikan video. Anda akan melihat pengontrol yang diperluas. Kembali ke daftar video dan saat Anda mengklik pengontrol mini, pengontrol yang diperluas akan dimuat lagi. Keluar dari aplikasi untuk melihat notifikasi. Klik gambar notifikasi untuk memuat pengontrol yang diperluas.
11. Menambahkan dukungan Cast Connect
Library Cast Connect memungkinkan aplikasi pengirim yang ada untuk berkomunikasi dengan aplikasi Android TV melalui protokol Cast. Cast Connect dibuat di atas infrastruktur Cast, dengan aplikasi Android TV yang bertindak sebagai penerima.
Dependensi
Catatan: Untuk menerapkan Cast Connect, play-services-cast-framework
harus 19.0.0
atau yang lebih tinggi.
LaunchOptions
Untuk meluncurkan aplikasi Android TV, yang juga disebut sebagai Penerima Android, kita perlu menetapkan tanda setAndroidReceiverCompatible
ke benar di objek LaunchOptions
. Objek LaunchOptions
ini menentukan cara penerima diluncurkan dan diteruskan ke CastOptions
yang ditampilkan oleh class CastOptionsProvider
. Menetapkan tanda yang disebutkan di atas ke false
akan meluncurkan penerima web untuk ID Aplikasi yang ditentukan di Konsol Developer Cast.
Di file CastOptionsProvider.kt
, tambahkan kode berikut ke metode getCastOptions
:
import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
.setAndroidReceiverCompatible(true)
.build()
return new CastOptions.Builder()
.setLaunchOptions(launchOptions)
...
.build()
Menetapkan Kredensial Peluncuran
Di sisi pengirim, Anda dapat menentukan CredentialsData
untuk mewakili siapa yang bergabung ke sesi. credentials
adalah string yang dapat ditentukan pengguna, selama aplikasi ATV Anda dapat memahaminya. CredentialsData
hanya diteruskan ke aplikasi Android TV Anda selama waktu peluncuran atau bergabung. Jika Anda menyetelnya lagi saat terhubung, setelan tersebut tidak akan diteruskan ke aplikasi Android TV Anda.
Untuk menetapkan Kredensial Peluncuran, CredentialsData
harus ditentukan dan diteruskan ke objek LaunchOptions
. Tambahkan kode berikut ke metode getCastOptions
di file CastOptionsProvider.kt
Anda:
import com.google.android.gms.cast.CredentialsData
...
val credentialsData = CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build()
val launchOptions = LaunchOptions.Builder()
...
.setCredentialsData(credentialsData)
.build()
Menetapkan Kredensial saat LoadRequest
Jika aplikasi Web Receiver dan aplikasi Android TV Anda menangani credentials
secara berbeda, Anda mungkin perlu menentukan credentials
terpisah untuk masing-masing. Untuk menanganinya, tambahkan kode berikut di file LocalPlayerActivity.kt
Anda di bagian fungsi loadRemoteMedia
:
remoteMediaClient.load(MediaLoadRequestData.Builder()
...
.setCredentials("user-credentials")
.setAtvCredentials("atv-user-credentials")
.build())
Bergantung pada aplikasi penerima yang menjadi tujuan transmisi pengirim, SDK kini akan otomatis menangani kredensial mana yang akan digunakan untuk sesi saat ini.
Menguji Cast Connect
Langkah-langkah untuk menginstal APK Android TV di Chromecast dengan Google TV
- Temukan Alamat IP perangkat Android TV Anda. Biasanya, opsi ini tersedia di bagian Setelan > Jaringan & Internet > (Nama jaringan yang terhubung ke perangkat Anda). Di sebelah kanan, Anda akan melihat detail dan IP perangkat Anda di jaringan.
- Gunakan alamat IP untuk perangkat Anda agar terhubung melalui ADB menggunakan terminal:
$ adb connect <device_ip_address>:5555
- Dari jendela terminal, buka folder tingkat atas untuk mendapatkan contoh codelab yang Anda download di awal codelab ini. Contoh:
$ cd Desktop/android_codelab_src
- Instal file .apk di folder ini ke Android TV dengan menjalankan:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Sekarang Anda akan dapat melihat aplikasi bernama Transmisikan Video di menu Aplikasi Anda di perangkat Android TV.
- Kembali ke project Android Studio Anda, lalu klik tombol Run untuk menginstal &menjalankan aplikasi pengirim di perangkat seluler fisik Anda. Di sudut kanan atas, klik ikon transmisi dan pilih perangkat Android TV Anda dari opsi yang tersedia. Sekarang Anda akan melihat aplikasi Android TV diluncurkan di perangkat Android TV dan memutar video akan memungkinkan Anda mengontrol pemutaran video menggunakan remote Android TV.
12. Menyesuaikan widget Cast
Anda dapat menyesuaikan widget Transmisikan dengan menyetel warna, menyesuaikan gaya tombol, teks, dan tampilan thumbnail, serta dengan memilih jenis tombol yang akan ditampilkan.
Mengupdate res/values/styles_castvideo.xml
<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>
Deklarasikan tema khusus berikut:
<!-- 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. Selamat
Kini Anda telah mengetahui cara agar aplikasi video kompatibel untuk Cast menggunakan widget SDK Cast di Android.
Untuk detail selengkapnya, lihat panduan developer Pengirim Android.