۱. مرور کلی

این آزمایشگاه کد به شما آموزش میدهد که چگونه یک برنامه ویدیویی اندروید موجود را برای پخش محتوا روی دستگاهی که از Google Cast پشتیبانی میکند، تغییر دهید.
گوگل کست چیست؟
گوگل کست به کاربران اجازه میدهد محتوا را از دستگاه تلفن همراه خود به تلویزیون منتقل کنند. سپس کاربران میتوانند از دستگاه تلفن همراه خود به عنوان کنترل از راه دور برای پخش رسانه در تلویزیون استفاده کنند.
کیت توسعه نرمافزار (SDK) گوگل کست (Google Cast) به شما امکان میدهد برنامه خود را برای کنترل تلویزیون یا سیستم صوتی گسترش دهید. کیت توسعه نرمافزار کست (Cast SDK) به شما امکان میدهد اجزای رابط کاربری لازم را بر اساس چکلیست طراحی گوگل کست (Google Cast Design Checklist) اضافه کنید.
چک لیست طراحی گوگل کست (Google Cast) ارائه شده است تا تجربه کاربری کست (Cast) را در تمام پلتفرمهای پشتیبانیشده ساده و قابل پیشبینی کند.
قرار است چه چیزی بسازیم؟
وقتی این آزمایشگاه کدنویسی را تکمیل کردید، یک برنامه ویدیویی اندروید خواهید داشت که قادر است ویدیوها را به یک دستگاه دارای قابلیت Google Cast منتقل کند.
آنچه یاد خواهید گرفت
- نحوه اضافه کردن SDK گوگل کست به یک برنامه ویدیویی نمونه.
- نحوه اضافه کردن دکمه Cast برای انتخاب دستگاه Google Cast.
- نحوه اتصال به دستگاه Cast و راهاندازی گیرنده رسانه.
- نحوه ارسال ویدیو.
- نحوه اضافه کردن یک کنترلر Cast mini به برنامه شما.
- نحوه پشتیبانی از اعلانهای رسانهای و کنترلهای قفل صفحه.
- نحوه اضافه کردن یک کنترلر توسعهیافته.
- چگونه یک مقدمه مقدماتی ارائه دهیم.
- نحوه سفارشیسازی ویجتهای Cast.
- نحوه ادغام با Cast Connect
آنچه نیاز دارید
- جدیدترین SDK اندروید .
- اندروید استودیو نسخه ۳.۲+
- یک دستگاه تلفن همراه با اندروید ۴.۱+ جیلی بین (سطح API ۱۶).
- یک کابل داده USB برای اتصال دستگاه تلفن همراه به رایانه توسعهدهنده.
- یک دستگاه گوگل کست مانند کروم کست یا تلویزیون اندروید که به اینترنت دسترسی داشته باشد.
- تلویزیون یا مانیتوری که ورودی HDMI داشته باشد.
- برای آزمایش ادغام Cast Connect، یک Chromecast با Google TV مورد نیاز است، اما برای بقیه Codelab اختیاری است. اگر Chromecast ندارید، میتوانید از مرحله افزودن پشتیبانی Cast Connect که در انتهای این آموزش آمده است، صرف نظر کنید.
تجربه
- شما باید دانش قبلی در مورد توسعه Kotlin و Android داشته باشید.
- همچنین به دانش قبلی در مورد تماشای تلویزیون نیاز خواهید داشت :)
چگونه از این آموزش استفاده خواهید کرد؟
تجربه خود را در ساخت برنامههای اندروید چگونه ارزیابی میکنید؟
تجربه خود را با تماشای تلویزیون چگونه ارزیابی میکنید؟
۲. کد نمونه را دریافت کنید
شما میتوانید تمام کدهای نمونه را روی کامپیوتر خود دانلود کنید...
و فایل زیپ دانلود شده را از حالت فشرده خارج کنید.
۳. برنامه نمونه را اجرا کنید

ابتدا، بیایید ببینیم برنامه نمونه تکمیلشده چگونه است. این برنامه یک پخشکننده ویدیوی ساده است. کاربر میتواند یک ویدیو را از یک لیست انتخاب کند و سپس آن را بهصورت محلی روی دستگاه پخش کند یا آن را به یک دستگاه Google Cast منتقل کند.
با دانلود کد، دستورالعملهای زیر نحوه باز کردن و اجرای برنامه نمونه تکمیل شده در اندروید استودیو را شرح میدهند:
در صفحه خوشامدگویی یا از طریق منوی File > New > Import Project... گزینه Import Project را انتخاب کنید.
انتخاب کنید
پوشهی app-done را از پوشهی کد نمونه انتخاب کنید و روی تأیید کلیک کنید.
روی فایل کلیک کنید >
همگامسازی پروژه با فایلهای Gradle
اشکالزدایی USB را در دستگاه اندروید خود فعال کنید - در اندروید ۴.۲ و بالاتر، صفحه گزینههای توسعهدهندگان به طور پیشفرض پنهان است. برای اینکه آن را قابل مشاهده کنید، به تنظیمات > درباره تلفن بروید و هفت بار روی شماره ساخت (Build number) ضربه بزنید. به صفحه قبل برگردید، به سیستم > پیشرفته (System > Advanced) بروید و روی گزینههای توسعهدهندگان (Developer options) در نزدیکی پایین صفحه ضربه بزنید، سپس روی اشکالزدایی USB ضربه بزنید تا روشن شود.
دستگاه اندروید خود را وصل کنید و روی
دکمه اجرا (Run ) را در اندروید استودیو فشار دهید. باید بعد از چند ثانیه برنامه ویدیویی با نام Cast Videos را ببینید.
روی دکمهی Cast در برنامهی ویدیو کلیک کنید و دستگاه Google Cast خود را انتخاب کنید.
یک ویدیو را انتخاب کنید و روی دکمه پخش کلیک کنید.
پخش ویدیو در دستگاه Google Cast شما شروع خواهد شد.
کنترلکنندهی باز شده نمایش داده میشود. میتوانید از دکمهی پخش/مکث برای کنترل پخش استفاده کنید.
به لیست ویدیوها برگردید.
اکنون یک مینی کنترلر در پایین صفحه قابل مشاهده است. 
برای مکث ویدیو در گیرنده، روی دکمه مکث در مینی کنترلر کلیک کنید. برای ادامه پخش ویدیو، روی دکمه پخش در مینی کنترلر کلیک کنید.
روی دکمه خانه دستگاه همراه کلیک کنید. اعلانها را پایین بکشید و اکنون باید اعلانی برای جلسه Cast ببینید.
گوشی خود را قفل کنید و وقتی قفل آن را باز میکنید، باید اعلانی روی صفحه قفل مشاهده کنید تا پخش رسانه را کنترل کنید یا پخش را متوقف کنید.
به برنامه ویدیو برگردید و روی دکمه Cast کلیک کنید تا پخش در دستگاه Google Cast متوقف شود.
سوالات متداول
۴. پروژه شروع را آماده کنید

ما باید پشتیبانی از گوگل کست را به برنامهی شروع که دانلود کردهاید اضافه کنیم. در اینجا برخی از اصطلاحات گوگل کست که در این آزمایشگاه کد استفاده خواهیم کرد، آورده شده است:
- یک برنامه فرستنده روی دستگاه تلفن همراه یا لپتاپ اجرا میشود،
- یک برنامه گیرنده روی دستگاه Google Cast اجرا میشود.
حالا شما آمادهاید تا با استفاده از اندروید استودیو، پروژهی اولیه را روی آن بسازید:
- انتخاب کنید
پوشه app-startرا از کد نمونه دانلود شده خود انتخاب کنید (گزینه Import Project را در صفحه خوشامدگویی یا از منوی File > New > Import Project... انتخاب کنید). - کلیک کنید
دکمهی همگامسازی پروژه با فایلهای Gradle . - کلیک کنید
دکمهی اجرا (Run) برای اجرای برنامه و بررسی رابط کاربری (UI)
طراحی اپلیکیشن
این برنامه لیستی از ویدیوها را از یک وب سرور راه دور دریافت میکند و لیستی را برای مرور در اختیار کاربر قرار میدهد. کاربران میتوانند یک ویدیو را برای مشاهده جزئیات انتخاب کنند یا ویدیو را به صورت محلی در دستگاه تلفن همراه پخش کنند.
این برنامه از دو اکتیویتی اصلی تشکیل شده است: VideoBrowserActivity و LocalPlayerActivity . برای ادغام قابلیت Google Cast، اکتیویتیها باید از AppCompatActivity یا والد آن، FragmentActivity ارثبری کنند. این محدودیت وجود دارد زیرا ما باید MediaRouteButton (که در کتابخانه پشتیبانی MediaRouter ارائه شده است) را به عنوان یک MediaRouteActionProvider اضافه کنیم و این فقط در صورتی کار میکند که اکتیویتی از کلاسهای فوقالذکر ارثبری کند. کتابخانه پشتیبانی MediaRouter به کتابخانه پشتیبانی AppCompat بستگی دارد که کلاسهای مورد نیاز را ارائه میدهد.
فعالیت مرورگر ویدیو
این activity شامل یک Fragment ( VideoBrowserFragment ) است. این لیست توسط یک ArrayAdapter ( VideoListAdapter ) پشتیبانی میشود. لیست ویدیوها و متادیتای مرتبط با آنها به صورت یک فایل JSON روی یک سرور راه دور میزبانی میشوند. یک AsyncTaskLoader ( VideoItemLoader ) این JSON را دریافت و پردازش میکند تا لیستی از اشیاء MediaItem بسازد.
یک شیء MediaItem یک ویدیو و ابردادههای مرتبط با آن، مانند عنوان، توضیحات، URL برای پخش زنده، URL برای تصاویر پشتیبان و در صورت وجود، مسیرهای متنی مرتبط (برای زیرنویسها) را مدلسازی میکند. شیء MediaItem بین فعالیتها منتقل میشود، بنابراین MediaItem دارای متدهای کاربردی برای تبدیل آن به یک Bundle و برعکس است.
وقتی لودر لیست MediaItems را میسازد، آن لیست را به VideoListAdapter ارسال میکند که سپس لیست MediaItems را در VideoBrowserFragment نمایش میدهد. لیستی از تصاویر کوچک ویدیو به همراه توضیح کوتاهی برای هر ویدیو به کاربر نمایش داده میشود. وقتی یک آیتم انتخاب میشود، MediaItem مربوطه به یک Bundle تبدیل شده و به LocalPlayerActivity ارسال میشود.
فعالیت پخشکننده محلی
این فعالیت، فرادادههای مربوط به یک ویدیوی خاص را نمایش میدهد و به کاربر اجازه میدهد ویدیو را به صورت محلی در دستگاه تلفن همراه پخش کند.
این فعالیت میزبان یک VideoView ، برخی کنترلهای رسانهای و یک ناحیه متنی برای نمایش توضیحات ویدیوی انتخاب شده است. پخشکننده قسمت بالای صفحه را میپوشاند و جایی برای توضیحات دقیق ویدیو در زیر آن باقی میگذارد. کاربر میتواند ویدیوها را پخش/متوقف کند یا پخش محلی را جستجو کند.
وابستگیها
از آنجایی که ما از AppCompatActivity استفاده میکنیم، به کتابخانه پشتیبانی AppCompat نیاز داریم. برای مدیریت لیست ویدیوها و دریافت ناهمگام تصاویر برای لیست، از کتابخانه Volley استفاده میکنیم.
سوالات متداول
۵. اضافه کردن دکمهی Cast

یک برنامهی دارای قابلیت Cast، دکمهی Cast را در هر یک از فعالیتهای خود نمایش میدهد. کلیک بر روی دکمهی Cast، فهرستی از دستگاههای Cast را نمایش میدهد که کاربر میتواند آنها را انتخاب کند. اگر کاربر در حال پخش محتوا به صورت محلی در دستگاه فرستنده بوده باشد، انتخاب یک دستگاه Cast، پخش را در آن دستگاه Cast شروع یا از سر میگیرد. در هر زمانی در طول یک جلسهی Cast، کاربر میتواند بر روی دکمهی Cast کلیک کند و ارسال برنامهی خود به دستگاه Cast را متوقف کند. کاربر باید بتواند در هر فعالیتی از برنامهی شما، همانطور که در چک لیست طراحی Google Cast توضیح داده شده است، به دستگاه Cast متصل شود یا از آن جدا شود.
وابستگیها
فایل build.gradle برنامه را بهروزرسانی کنید تا وابستگیهای کتابخانهای لازم را شامل شود:
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"
}
پروژه را همگامسازی کنید تا ساخت پروژه بدون خطا تأیید شود.
مقداردهی اولیه
چارچوب Cast یک شیء سینگلتون سراسری به CastContext دارد که تمام تعاملات Cast را هماهنگ میکند.
شما باید رابط OptionsProvider را برای تأمین CastOptions مورد نیاز برای مقداردهی اولیه CastContext singleton پیادهسازی کنید. مهمترین گزینه، شناسه برنامه گیرنده است که برای فیلتر کردن نتایج کشف دستگاه Cast و راهاندازی برنامه گیرنده هنگام شروع یک جلسه Cast استفاده میشود.
وقتی برنامهی خود را که قابلیت Cast دارد توسعه میدهید، باید به عنوان توسعهدهندهی Cast ثبتنام کنید و سپس یک شناسهی برنامه برای برنامهی خود دریافت کنید. برای این آزمایشگاه کد، ما از یک شناسهی برنامهی نمونه استفاده خواهیم کرد.
فایل جدید CastOptionsProvider.kt زیر را به پکیج com.google.sample.cast.refplayer پروژه اضافه کنید:
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
}
}
حالا OptionsProvider را درون تگ " application " از فایل AndroidManifest.xml اپلیکیشن تعریف کنید:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />
مقداردهی اولیهی تنبلانهی CastContext در متد 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)
}
همان منطق مقداردهی اولیه را به LocalPlayerActivity اضافه کنید.
دکمهی ارسال
حالا که CastContext مقداردهی اولیه شده است، باید دکمهی Cast را اضافه کنیم تا کاربر بتواند دستگاه Cast را انتخاب کند. دکمهی Cast توسط MediaRouteButton از کتابخانهی پشتیبانی MediaRouter پیادهسازی شده است. مانند هر آیکون عملیاتی که میتوانید به activity خود اضافه کنید (با استفاده از ActionBar یا Toolbar )، ابتدا باید آیتم منوی مربوطه را به منوی خود اضافه کنید.
فایل res/menu/browse.xml را ویرایش کنید و آیتم MediaRouteActionProvider را در منو، قبل از آیتم تنظیمات اضافه کنید:
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
با استفاده از CastButtonFactory برای اتصال MediaRouteButton به فریمورک Cast، متد onCreateOptionsMenu() از VideoBrowserActivity را بازنویسی کنید:
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
}
به همین ترتیب، onCreateOptionsMenu در LocalPlayerActivity لغو کنید.
کلیک کنید
دکمه اجرا (Run ) را برای اجرای برنامه روی دستگاه تلفن همراه خود فشار دهید. باید دکمه Cast را در نوار عملکرد برنامه مشاهده کنید و وقتی روی آن کلیک کنید، دستگاههای Cast موجود در شبکه محلی شما فهرست میشوند. کشف دستگاه به طور خودکار توسط CastContext مدیریت میشود. دستگاه Cast خود را انتخاب کنید و برنامه گیرنده نمونه روی دستگاه Cast بارگذاری میشود. میتوانید بین فعالیت مرور (browse activity) و فعالیت پخشکننده محلی (local player activity) حرکت کنید و وضعیت دکمه Cast همگامسازی میشود.
ما هنوز هیچ پشتیبانی برای پخش رسانهای برقرار نکردهایم، بنابراین هنوز نمیتوانید ویدیوها را در دستگاه Cast پخش کنید. برای قطع اتصال، روی دکمه Cast کلیک کنید.
۶. پخش محتوای ویدیویی

ما برنامه نمونه را طوری توسعه خواهیم داد که ویدیوها را از راه دور روی دستگاه Cast نیز پخش کند. برای انجام این کار، باید به رویدادهای مختلف تولید شده توسط چارچوب Cast گوش دهیم.
رسانههای ریختهگری
در سطح بالا، اگر میخواهید یک رسانه را در دستگاه Cast پخش کنید، باید این کارها را انجام دهید:
- یک شیء
MediaInfoایجاد کنید که یک آیتم رسانهای را مدلسازی کند. - به دستگاه Cast متصل شوید و برنامه گیرنده خود را اجرا کنید.
- شیء
MediaInfoرا در گیرنده خود بارگذاری کنید و محتوا را پخش کنید. - وضعیت رسانه را پیگیری کنید.
- ارسال دستورات پخش به گیرنده بر اساس تعاملات کاربر.
ما قبلاً مرحله ۲ را در بخش قبلی انجام دادهایم. انجام مرحله ۳ با چارچوب Cast آسان است. مرحله ۱ به نگاشت یک شیء به شیء دیگر مربوط میشود؛ MediaInfo چیزی است که چارچوب Cast آن را میفهمد و MediaItem کپسولهسازی برنامه ما برای یک آیتم رسانهای است؛ ما میتوانیم به راحتی یک MediaItem به یک MediaInfo نگاشت کنیم.
برنامه نمونه LocalPlayerActivity از قبل با استفاده از این enum بین پخش محلی و پخش از راه دور تمایز قائل میشود:
private var mLocation: PlaybackLocation? = null
enum class PlaybackLocation {
LOCAL, REMOTE
}
enum class PlaybackState {
PLAYING, PAUSED, BUFFERING, IDLE
}
در این آزمایشگاه کد، مهم نیست که دقیقاً بفهمید منطق پخشکنندهی نمونه چگونه کار میکند. مهم این است که بدانید پخشکنندهی رسانهی برنامهی شما باید اصلاح شود تا از دو مکان پخش به روشی مشابه آگاه باشد.
در حال حاضر، پخشکننده محلی همیشه در حالت پخش محلی است، زیرا هنوز چیزی در مورد حالتهای Casting نمیداند. ما باید رابط کاربری را بر اساس انتقال حالتهایی که در چارچوب Cast اتفاق میافتد، بهروزرسانی کنیم. برای مثال، اگر شروع به Casting کنیم، باید پخش محلی را متوقف کنیم و برخی از کنترلها را غیرفعال کنیم. به طور مشابه، اگر Casting را در حین حضور در این فعالیت متوقف کنیم، باید به پخش محلی منتقل شویم. برای مدیریت این موضوع، باید به رویدادهای مختلف تولید شده توسط چارچوب Cast گوش دهیم.
مدیریت جلسه بازیگران
برای چارچوب Cast، یک جلسه Cast مراحل اتصال به یک دستگاه، راهاندازی (یا پیوستن)، اتصال به یک برنامه گیرنده و در صورت لزوم، مقداردهی اولیه یک کانال کنترل رسانه را ترکیب میکند. کانال کنترل رسانه نحوه ارسال و دریافت پیامها از پخشکننده رسانه گیرنده توسط چارچوب Cast است.
جلسهی Cast به طور خودکار زمانی که کاربر دستگاهی را از طریق دکمهی Cast انتخاب میکند، آغاز میشود و با قطع اتصال کاربر، به طور خودکار متوقف میشود. اتصال مجدد به جلسهی گیرنده به دلیل مشکلات شبکه نیز به طور خودکار توسط Cast SDK مدیریت میشود.
بیایید یک SessionManagerListener به 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()
}
}
}
در اکتیویتی LocalPlayerActivity ، ما علاقهمندیم که هنگام اتصال یا قطع اتصال از دستگاه Cast مطلع شویم تا بتوانیم به پخشکننده محلی یا از آن تغییر وضعیت دهیم. توجه داشته باشید که اتصال نه تنها میتواند توسط نمونهای از برنامه شما که روی دستگاه تلفن همراه شما اجرا میشود، مختل شود، بلکه میتواند توسط نمونه دیگری از برنامه شما (یا برنامه دیگری) که روی یک دستگاه تلفن همراه دیگر اجرا میشود نیز مختل شود.
جلسه فعال فعلی از طریق SessionManager.getCurrentSession() قابل دسترسی است. جلسات به طور خودکار در پاسخ به تعاملات کاربر با کادرهای محاورهای Cast ایجاد و حذف میشوند.
ما باید شنوندهی جلسهی خود را ثبت کنیم و برخی از متغیرهایی را که در فعالیت استفاده خواهیم کرد، مقداردهی اولیه کنیم. متد onCreate به LocalPlayerActivity را به صورت زیر تغییر دهید:
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)
}
}
...
}
بارگیری رسانه
در Cast SDK، RemoteMediaClient مجموعهای از APIهای مناسب را برای مدیریت پخش رسانه از راه دور در گیرنده فراهم میکند. برای CastSession که از پخش رسانه پشتیبانی میکند، یک نمونه از RemoteMediaClient به طور خودکار توسط SDK ایجاد میشود. با فراخوانی متد getRemoteMediaClient() در نمونه CastSession میتوان به آن دسترسی پیدا کرد. متدهای زیر را به LocalPlayerActivity اضافه کنید تا ویدیوی انتخاب شده فعلی در گیرنده بارگذاری شود:
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()
}
}
اکنون متدهای مختلف موجود را بهروزرسانی کنید تا از منطق جلسهی Cast برای پشتیبانی از پخش از راه دور استفاده شود:
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 ، مقدار متغیر isConnected را تغییر دهید:
private fun updatePlayButton(state: PlaybackState?) {
...
val isConnected = (mCastSession != null
&& (mCastSession!!.isConnected || mCastSession!!.isConnecting))
...
}
حالا، روی کلیک کنید
برای اجرای برنامه روی دستگاه تلفن همراه خود، دکمه اجرا (Run) را فشار دهید . به دستگاه Cast خود متصل شوید و پخش ویدیو را شروع کنید. باید پخش ویدیو را روی گیرنده ببینید.
۷. مینی کنترلر
چک لیست طراحی Cast ایجاب میکند که تمام برنامههای Cast یک کنترلر کوچک داشته باشند که وقتی کاربر از صفحه محتوای فعلی خارج میشود، ظاهر شود. این کنترلر کوچک دسترسی فوری و یک یادآوری قابل مشاهده برای جلسه Cast فعلی فراهم میکند.

کیت توسعه نرمافزار Cast یک نمای سفارشی به نام MiniControllerFragment ارائه میدهد که میتوان آن را به فایل طرحبندی برنامه مربوط به فعالیتهایی که میخواهید مینی کنترلر را در آنها نمایش دهید، اضافه کرد.
تعریف قطعه کد زیر را به انتهای هر دو فایل res/layout/player_activity.xml و 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"/>
کلیک کنید
دکمه اجرا (Run ) را برای اجرای برنامه و پخش ویدیو فشار دهید. وقتی پخش در گیرنده شروع میشود، باید شاهد نمایش مینی کنترلر در پایین هر فعالیت باشید. میتوانید با استفاده از مینی کنترلر، پخش از راه دور را کنترل کنید. اگر بین فعالیت مرور و فعالیت پخش محلی حرکت کنید، وضعیت مینی کنترلر باید با وضعیت پخش رسانه گیرنده همگام بماند.
۸. اعلانها و قفل صفحه
چک لیست طراحی گوگل کست به یک برنامه فرستنده نیاز دارد تا کنترلهای رسانهای را از طریق اعلان و صفحه قفل پیادهسازی کند.

کیت توسعه نرمافزار Cast یک MediaNotificationService ارائه میدهد تا به برنامه فرستنده در ساخت کنترلهای رسانهای برای اعلان و قفل صفحه کمک کند. این سرویس به طور خودکار توسط gradle در مانیفست برنامه شما ادغام میشود.
MediaNotificationService هنگام ارسال پیام توسط فرستنده، در پسزمینه اجرا میشود و اعلانی حاوی تصویر کوچک و فرادادههایی درباره آیتم ارسال پیام فعلی، دکمه پخش/مکث و دکمه توقف نمایش میدهد.
کنترلهای اعلان و قفل صفحه را میتوان با CastOptions هنگام مقداردهی اولیه CastContext فعال کرد. کنترلهای رسانه برای اعلان و قفل صفحه به طور پیشفرض فعال هستند. ویژگی قفل صفحه تا زمانی که اعلان روشن باشد، فعال است.
CastOptionsProvider را ویرایش کنید و پیادهسازی getCastOptions را طوری تغییر دهید که با این کد مطابقت داشته باشد:
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()
}
کلیک کنید
دکمه اجرا (Run ) را برای اجرای برنامه روی دستگاه تلفن همراه خود فشار دهید. یک ویدیو را پخش کنید و از برنامه نمونه خارج شوید. باید یک اعلان برای ویدیویی که در حال پخش در گیرنده است، وجود داشته باشد. دستگاه تلفن همراه خود را قفل کنید و اکنون صفحه قفل باید کنترلهای پخش رسانه در دستگاه پخش را نمایش دهد.

۹. پوشش مقدماتی
چک لیست طراحی Google Cast از یک برنامه فرستنده میخواهد که دکمه Cast را به کاربران فعلی معرفی کند تا به آنها اطلاع دهد که برنامه فرستنده اکنون از Cast پشتیبانی میکند و همچنین به کاربران جدید Google Cast کمک میکند.

کیت توسعه نرمافزاری Cast یک نمای سفارشی به IntroductoryOverlay ارائه میدهد که میتواند برای برجسته کردن دکمه Cast هنگام اولین نمایش به کاربران استفاده شود. کد زیر را به 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()
}
}
}
حالا، یک CastStateListener اضافه کنید و وقتی یک دستگاه Cast در دسترس است، با تغییر متد onCreate متد showIntroductoryOverlay فراخوانی کنید و متدهای onResume و onPause را برای مطابقت با موارد زیر بازنویسی کنید:
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!!)
}
دادههای برنامه را پاک کنید یا برنامه را از دستگاه خود حذف کنید. سپس، روی
برای اجرای برنامه روی دستگاه تلفن همراه خود، دکمه اجرا (Run ) را بزنید تا صفحه مقدماتی را مشاهده کنید (در صورت عدم نمایش صفحه مقدماتی، دادههای برنامه را پاک کنید).
۱۰. کنترلر توسعهیافته
چک لیست طراحی گوگل کست به یک برنامه فرستنده نیاز دارد تا یک کنترلکننده گسترشیافته برای رسانهای که قرار است پخش شود، فراهم کند. این کنترلکننده گسترشیافته، نسخه تمامصفحهای از یک کنترلکننده کوچک است.

کیت توسعه نرمافزار Cast یک ویجت برای کنترلر توسعهیافته به نام ExpandedControllerActivity ارائه میدهد. این یک کلاس انتزاعی است که برای افزودن دکمه Cast باید از آن زیرکلاس بسازید.
ابتدا، یک فایل منبع منو جدید به نام expanded_controller.xml ایجاد کنید تا کنترلر بسطیافته، دکمهی 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>
یک بسته جدید expandedcontrols در بسته com.google.sample.cast.refplayer ایجاد کنید. سپس، یک فایل جدید به نام ExpandedControlsActivity.kt در بسته 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
}
}
حالا ExpandedControlsActivity در فایل AndroidManifest.xml درون تگ application بالای 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>
CastOptionsProvider را ویرایش کنید و NotificationOptions و CastMediaOptions تغییر دهید تا فعالیت هدف روی 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()
}
متد loadRemoteMedia LocalPlayerActivity را بهروزرسانی کنید تا ExpandedControlsActivity هنگام بارگذاری رسانهی ریموت نمایش داده شود:
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())
}
کلیک کنید
برای اجرای برنامه روی دستگاه تلفن همراه خود و پخش ویدیو، دکمه اجرا (Run ) را بزنید. باید کنترلر باز شده را ببینید. به لیست ویدیوها برگردید و وقتی روی کنترلر کوچک کلیک میکنید، کنترلر باز شده دوباره بارگیری میشود. برای دیدن اعلان از برنامه خارج شوید. برای بارگیری کنترلر باز شده، روی تصویر اعلان کلیک کنید.
۱۱. اضافه کردن پشتیبانی از اتصال بازیگران (Cast Connect)
کتابخانه Cast Connect به برنامههای فرستنده موجود اجازه میدهد تا از طریق پروتکل Cast با برنامههای Android TV ارتباط برقرار کنند. Cast Connect بر روی زیرساخت Cast ساخته میشود و برنامه Android TV شما به عنوان گیرنده عمل میکند.
وابستگیها
توجه: برای پیادهسازی Cast Connect، نسخه play-services-cast-framework باید 19.0.0 یا بالاتر باشد.
گزینههای راهاندازی
برای اجرای برنامه Android TV که به عنوان Android Receiver نیز شناخته میشود، باید پرچم setAndroidReceiverCompatible را در شیء LaunchOptions روی true تنظیم کنیم. این شیء LaunchOptions نحوه اجرای گیرنده را تعیین میکند و به CastOptions که توسط کلاس CastOptionsProvider برگردانده میشود، منتقل میشود. تنظیم پرچم فوق روی false ، گیرنده وب را برای شناسه برنامه تعریف شده در کنسول توسعهدهنده Cast اجرا میکند.
در فایل CastOptionsProvider.kt کد زیر را به متد getCastOptions اضافه کنید:
import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
.setAndroidReceiverCompatible(true)
.build()
return new CastOptions.Builder()
.setLaunchOptions(launchOptions)
...
.build()
اعتبارنامههای راهاندازی را تنظیم کنید
در سمت فرستنده، میتوانید CredentialsData برای نشان دادن اینکه چه کسی به جلسه میپیوندد، مشخص کنید. credentials رشتهای هستند که میتوانند توسط کاربر تعریف شوند، تا زمانی که برنامه ATV شما بتواند آن را بفهمد. CredentialsData فقط در زمان راهاندازی یا اتصال به برنامه Android TV شما منتقل میشود. اگر آن را دوباره در حین اتصال تنظیم کنید، به برنامه Android TV شما منتقل نمیشود.
برای تنظیم اعتبارنامههای راهاندازی (Launch Credentials)، باید CredentialsData تعریف شده و به شیء LaunchOptions ارسال شود. کد زیر را به متد getCastOptions در فایل CastOptionsProvider.kt خود اضافه کنید:
import com.google.android.gms.cast.CredentialsData
...
val credentialsData = CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build()
val launchOptions = LaunchOptions.Builder()
...
.setCredentialsData(credentialsData)
.build()
تنظیم اعتبارنامهها در LoadRequest
در صورتی که برنامه گیرنده وب و برنامه تلویزیون اندروید شما credentials به طور متفاوتی مدیریت کنند، ممکن است لازم باشد برای هر کدام credentials جداگانهای تعریف کنید. برای انجام این کار، کد زیر را در فایل LocalPlayerActivity.kt خود در زیر تابع loadRemoteMedia اضافه کنید:
remoteMediaClient.load(MediaLoadRequestData.Builder()
...
.setCredentials("user-credentials")
.setAtvCredentials("atv-user-credentials")
.build())
بسته به برنامه گیرندهای که فرستنده شما به آن ارسال میکند، SDK اکنون به طور خودکار مدیریت میکند که از کدام اعتبارنامهها برای جلسه فعلی استفاده شود.
تست اتصال کست
مراحل نصب APK اندروید تیوی روی کرومکست با گوگل تیوی
- آدرس IP دستگاه Android TV خود را پیدا کنید. معمولاً این آدرس در قسمت تنظیمات > شبکه و اینترنت > (نام شبکهای که دستگاه شما به آن متصل است) موجود است. در سمت راست، جزئیات و IP دستگاه شما در شبکه نشان داده میشود.
- از آدرس IP دستگاه خود برای اتصال به آن از طریق ADB با استفاده از ترمینال استفاده کنید:
$ adb connect <device_ip_address>:5555
- از پنجره ترمینال خود، به پوشه سطح بالا برای نمونههای codelab که در ابتدای این codelab دانلود کردهاید، بروید. برای مثال:
$ cd Desktop/android_codelab_src
- فایل .apk موجود در این پوشه را با اجرای دستور زیر روی تلویزیون اندروید خود نصب کنید:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- اکنون باید بتوانید برنامهای با نام Cast Videos را در منوی برنامههای خود در دستگاه Android TV خود مشاهده کنید.
- به پروژه اندروید استودیو خود برگردید و روی دکمه اجرا (Run) کلیک کنید تا برنامه فرستنده روی دستگاه تلفن همراه فیزیکی شما نصب و اجرا شود. در گوشه بالا سمت راست، روی نماد پخش (cast) کلیک کنید و دستگاه تلویزیون اندروید خود را از بین گزینههای موجود انتخاب کنید. اکنون باید برنامه تلویزیون اندروید را که روی دستگاه تلویزیون اندروید شما اجرا شده است، مشاهده کنید و پخش ویدیو باید به شما امکان دهد پخش ویدیو را با استفاده از ریموت تلویزیون اندروید خود کنترل کنید.
۱۲. سفارشیسازی ویجتهای Cast
شما میتوانید ویجتهای Cast را با تنظیم رنگها، استایلدهی به دکمهها، متن و ظاهر تصویر بندانگشتی و با انتخاب نوع دکمههای نمایش داده شده، سفارشیسازی کنید.
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>
تمهای سفارشی زیر را اعلام کنید:
<!-- 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>
۱۳. تبریک
اکنون میدانید که چگونه با استفاده از ویجتهای Cast SDK در اندروید، قابلیت پخش ویدیو را در یک برنامهی ویدیویی فعال کنید.
برای جزئیات بیشتر، به راهنمای توسعهدهندهی Android Sender مراجعه کنید.