تفعيل بث تطبيق Android

1. نظرة عامة

شعار Google Cast

يشرح لك هذا الدرس التطبيقي حول الترميز كيفية تعديل تطبيق فيديو حالي على Android لبث محتوى إلى جهاز يعمل بتكنولوجيا Google Cast.

ما المقصود بتكنولوجيا Google Cast؟

تسمح تكنولوجيا Google Cast للمستخدمين ببث المحتوى من جهاز جوّال إلى تلفزيون. يمكن للمستخدمين بعد ذلك استخدام أجهزتهم الجوّالة كوحدة تحكم عن بُعد لتشغيل الوسائط على التلفزيون.

تتيح لك حزمة تطوير البرامج (SDK) لتكنولوجيا Google Cast إمكانية توسيع نطاق تطبيقك للتحكم في التلفزيون أو نظام الصوت. تسمح لك حزمة تطوير البرامج (SDK) لتكنولوجيا Cast بإضافة مكونات واجهة المستخدم اللازمة بناءً على قائمة التحقق من تصميم Google Cast.

يتم توفير قائمة التحقّق من تصميم Google Cast لجعل تجربة مستخدم Google Cast بسيطة ويمكن توقُّعها على جميع الأنظمة الأساسية المتوافقة.

ما الذي سنبنيه؟

عند الانتهاء من هذا الدرس التطبيقي، سيكون لديك تطبيق فيديو على Android يمكنه إرسال فيديوهات إلى جهاز يعمل بتكنولوجيا Google Cast.

المُعطيات

  • كيفية إضافة حزمة تطوير البرامج (SDK) لتكنولوجيا Google Cast إلى نموذج فيديو
  • كيفية إضافة زر البث لاختيار جهاز Google Cast
  • كيفية الاتصال بجهاز بث وتشغيل جهاز استقبال وسائط
  • كيفية إرسال فيديو
  • كيفية إضافة وحدة تحكم مصغّرة للبث إلى تطبيقك.
  • كيفية إتاحة إشعارات الوسائط وعناصر التحكّم في شاشة القفل
  • كيفية إضافة وحدة تحكُّم موسّعة.
  • كيفية توفير تراكب تمهيدي
  • طريقة تخصيص التطبيقات المصغّرة للبث
  • كيفية الدمج مع Cast Connect

المتطلبات

  • أحدث إصدار من حزمة تطوير البرامج (SDK) لنظام التشغيل Android
  • استوديو Android الإصدار 3.2 أو الإصدارات الأحدث
  • جهاز جوّال يعمل بالإصدار Android 4.1 أو الإصدارات الأحدث Jelly Bean (المستوى 16 من واجهة برمجة التطبيقات).
  • كابل بيانات USB لتوصيل جهازك الجوّال بجهاز كمبيوتر التطوير.
  • جهاز Google Cast، مثل Chromecast أو Android TV تم ضبطه على الاتصال بالإنترنت
  • تلفزيون أو شاشة مزوّدة بمنفذ إدخال HDMI.
  • يجب توفّر "Chromecast مع Google TV" لاختبار عملية دمج Cast Connect، ولكنه اختياري في بقية الدرس التطبيقي حول الترميز. إذا لم يكن لديك هذا البرنامج، يُرجى تخطّي خطوة إضافة دعم Cast Connect في نهاية هذا الدليل التوجيهي.

التجربة

  • يجب أن يكون لديك معرفة سابقة بتطوير Kotlin وAndroid.
  • كما ستحتاج أيضًا إلى معرفة سابقة بكيفية مشاهدة التلفزيون :)

كيف ستستخدم هذا البرنامج التعليمي؟

القراءة فقط اقرأها وأكمِل التمارين

كيف تقيّم تجربتك في إنشاء تطبيقات Android؟

حديث متوسط بارعة

كيف تقيّم تجربتك في مشاهدة التلفزيون؟

حديث متوسط بارع

2. الحصول على رمز النموذج

يمكنك تنزيل نموذج الرمز بالكامل على جهاز الكمبيوتر...

وفك ضغط ملف zip الذي تم تنزيله.

3- تشغيل نموذج التطبيق

رمز لزوج من بوصلة

أولاً، لنرى كيف يبدو نموذج التطبيق المكتمل. هذا التطبيق هو مشغّل فيديو أساسي. يمكن للمستخدم اختيار فيديو من قائمة، ثمّ تشغيل الفيديو على الجهاز أو إرساله على جهاز Google Cast.

بعد تنزيل الرمز، توضّح التعليمات التالية كيفية فتح نموذج التطبيق المكتمل وتشغيله في استوديو Android:

اختَر استيراد مشروع في شاشة الترحيب أو انقر على ملف > جديد > استيراد مشروع...، خيارات القائمة

اختَر الدليل رمز المجلدapp-done من مجلد "نموذج الرموز" وانقر على "حسنًا".

انقر على ملف > "مزامنة المشروع باستخدام Gradle" في "استوديو Android" زر مزامنة المشروع مع ملفات Gradle

فعِّل تصحيح أخطاء USB على جهاز Android، علمًا بأنّ شاشة "خيارات المطوّرين" تكون مخفية تلقائيًا في الإصدار 4.2 من نظام التشغيل Android والإصدارات الأحدث. لإظهارها، انتقِل إلى الإعدادات > لمحة عن الهاتف ثم النقر على رقم الإصدار سبع مرات ارجع إلى الشاشة السابقة، ثم انتقل إلى النظام > إعدادات متقدّمة وانقر على خيارات المطوّرين بالقرب من أسفل الصفحة، ثم انقر على تصحيح أخطاء USB لتفعيله.

يمكنك توصيل جهاز Android بالطاقة والنقر على الزر الزر "تشغيل" في "استوديو Android"، وهو مثلث أخضر يشير إلى اليمينتشغيل في "استوديو Android". من المفترض أن يظهر تطبيق الفيديو المُسمّى Cast Videos بعد بضع ثوانٍ.

انقر على زر البث في تطبيق الفيديو واختَر جهاز Google Cast.

حدد فيديو وانقر على زر التشغيل.

سيبدأ تشغيل الفيديو على جهاز Google Cast.

سيتم عرض وحدة التحكّم الموسّعة. يمكنك استخدام زر التشغيل أو الإيقاف المؤقت للتحكم في التشغيل.

انتقِل مرة أخرى إلى قائمة الفيديوهات.

تظهر الآن وحدة تحكُّم مصغّرة في أسفل الشاشة. صورة توضيحية لهاتف Android يستخدم ميزة "بث الفيديوهات" تطبيق يظهر فيه وحدة التحكّم الصغيرة في أسفل الشاشة

انقر على زر الإيقاف المؤقت في وحدة التحكّم المصغّرة لإيقاف الفيديو مؤقتًا على جهاز الاستقبال. انقر على زر التشغيل في وحدة التحكّم المصغّرة لمواصلة تشغيل الفيديو مرة أخرى.

انقر على زر الشاشة الرئيسية للجهاز الجوّال. اسحب الإشعارات للأسفل وسترى الآن إشعارًا لجلسة البث.

يمكنك قفل هاتفك وعندما تفتح قفله، من المفترض أن يظهر لك إشعار على شاشة القفل للتحكّم في تشغيل الوسائط أو إيقاف البث.

ارجع إلى تطبيق الفيديو وانقر على زر البث لإيقاف البث على جهاز Google Cast.

الأسئلة الشائعة

4. تجهيز مشروع البدء

صورة توضيحية لهاتف Android يستخدم ميزة "بث الفيديوهات" تطبيق واحد

نحتاج إلى إمكانية استخدام Google Cast في تطبيق البدء الذي نزّلته. في ما يلي بعض مصطلحات Google Cast التي سنستخدمها في هذا الدرس التطبيقي حول الترميز:

  • تشغيل تطبيق المرسِل على جهاز جوّال أو كمبيوتر محمول،
  • تشغيل تطبيق مستلِم على جهاز Google Cast

أصبحت جاهزًا الآن للانطلاق في هذا المشروع الأوّلي باستخدام "استوديو Android":

  1. اختَر الدليل رمز المجلدapp-start من تنزيل نموذج الرمز (اختَر استيراد مشروع في شاشة الترحيب أو خيار القائمة ملف > جديد > استيراد مشروع...).
  2. انقر على زرّ "مزامنة المشروع باستخدام Gradle" في "استوديو Android" زر مزامنة المشروع مع ملفات Gradle.
  3. انقر على الزر الزر "تشغيل" في "استوديو Android"، وهو مثلث أخضر يشير إلى اليمينتشغيل لتشغيل التطبيق واستكشاف واجهة المستخدم.

تصميم التطبيقات

يجلب التطبيق قائمة فيديوهات من خادم ويب بعيد ويعرض قائمة للمستخدم لتصفّحها. ويمكن للمستخدمين اختيار فيديو للاطّلاع على التفاصيل أو تشغيله محليًا على الجهاز الجوّال.

يتكون التطبيق من نشاطين رئيسيين: VideoBrowserActivity وLocalPlayerActivity. لدمج وظائف Google Cast، يجب اكتساب الأنشطة من AppCompatActivity أو من عنصرها الرئيسي FragmentActivity. فرضنا ذلك لأنّنا سنحتاج إلى إضافة MediaRouteButton (المتوفّرة في مكتبة دعم MediaRouter) على أنّها MediaRouteActionProvider، ولن يعمل ذلك إلا إذا كان النشاط مكتسبًا من الفئات المذكورة أعلاه. تعتمد مكتبة دعم MediaRouter على مكتبة دعم AppCompat التي توفر الفئات المطلوبة.

VideoBrowserActivity

يحتوي هذا النشاط على Fragment (VideoBrowserFragment). تدعم هذه القائمة ArrayAdapter (VideoListAdapter). قائمة الفيديوهات والبيانات الوصفية المرتبطة بها مستضافة على خادم بعيد كملف JSON. يجلب AsyncTaskLoader (VideoItemLoader) ملف JSON هذا ويعالجه لإنشاء قائمة بكائنات MediaItem.

ينشئ عنصر MediaItem نموذجًا لفيديو والبيانات الوصفية المرتبطة به، مثل العنوان والوصف وعنوان URL للبث وعنوان URL للصور الداعمة والمقاطع الصوتية المرتبطة (للترجمة والشرح) في حال توفّرها. يتم تمرير الكائن MediaItem بين الأنشطة، لذلك تتوفر في MediaItem طرق فائدة لتحويله إلى Bundle والعكس صحيح.

عندما تنشئ أداة التحميل قائمة MediaItems، فإنّها تمرِّر هذه القائمة إلى VideoListAdapter التي تعرض بعد ذلك قائمة MediaItems في VideoBrowserFragment. يتم عرض قائمة بالصور المصغّرة للفيديو مع وصف موجز لكل فيديو. عند اختيار عنصر، يتم تحويل قيمة MediaItem المقابلة إلى Bundle وتمريرها إلى LocalPlayerActivity.

LocalPlayerActivity

يعرض هذا النشاط البيانات الوصفية حول فيديو معين ويسمح للمستخدم بتشغيل الفيديو محليًا على جهاز الجوال.

يستضيف النشاط VideoView وبعض عناصر التحكّم في الوسائط ومنطقة نص لعرض وصف الفيديو الذي اخترته. يغطي المشغل الجزء العلوي من الشاشة، مما يترك مكانًا للوصف التفصيلي للفيديو أدناه. يمكن للمستخدم تشغيل مقاطع الفيديو أو إيقافها مؤقتًا أو طلب تشغيلها على الجهاز.

التبعيات

بما أنّنا نستخدم AppCompatActivity، نحتاج إلى مكتبة دعم AppCompat. نستخدم مكتبة Volley لإدارة قائمة الفيديوهات والحصول على صور لها بشكل غير متزامن في القائمة.

الأسئلة الشائعة

5- إضافة زر البث

صورة توضيحية للجزء العلوي من هاتف Android حيث يتم تشغيل تطبيق Cast Video. ظهور زر البث في أعلى يسار الشاشة

يعرض تطبيق يعمل بتكنولوجيا Google Cast زر البث في كل نشاط من أنشطته. يؤدي النقر على زر البث إلى عرض قائمة بأجهزة البث التي يمكن للمستخدم اختيارها. إذا كان المستخدم يشغِّل المحتوى محليًا على جهاز المُرسِل، سيؤدي اختيار جهاز بث إلى بدء التشغيل أو استئناف تشغيله على جهاز البث هذا. يمكن للمستخدم النقر على زر البث وإيقاف بث تطبيقك على جهاز البث في أي وقت أثناء جلسة البث. يجب أن يكون المستخدم قادرًا على الاتصال بجهاز البث أو إلغاء ربطه أثناء ممارسة أي نشاط لتطبيقك، كما هو موضح في قائمة التحقق من تصميم Google Cast.

التبعيات

حدِّث ملف create.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"
}

قم بمزامنة المشروع للتأكد من إنشاء المشروع بدون أخطاء.

الإعداد

يحتوي إطار عمل Google Cast على كائن مفردات عام، وهو CastContext، الذي ينسق جميع تفاعلات البث.

يجب تنفيذ واجهة OptionsProvider لتوفير CastOptions اللازم لإعداد CastContext المفردة. وأهم خيار هو رقم تعريف تطبيق جهاز الاستقبال الذي يُستخدم لتصفية نتائج اكتشاف جهاز البث وتشغيل تطبيق الاستقبال عند بدء جلسة البث.

عند تطوير تطبيقك الخاص الذي يعمل بتكنولوجيا Google Cast، عليك التسجيل كمطوِّر لتكنولوجيا Google 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، علينا إضافة زر البث للسماح للمستخدم باختيار جهاز بث. ينفّذ MediaRouteButton زر البث من مكتبة دعم MediaRouter. مثل أي رمز إجراء يمكنك إضافته إلى نشاطك (باستخدام 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"/>

إلغاء طريقة onCreateOptionsMenu() في VideoBrowserActivity باستخدام CastButtonFactory لتوصيل MediaRouteButton بإطار عمل البث:

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 بطريقة مماثلة.

انقر على الزر الزر &quot;تشغيل&quot; في &quot;استوديو Android&quot;، وهو مثلث أخضر يشير إلى اليمينتشغيل لتشغيل التطبيق على جهازك الجوّال. من المفترض أن يظهر لك زر البث في شريط الإجراءات الخاص بالتطبيق، وعند النقر عليه، سيتم عرض قائمة بأجهزة البث على شبكتك المحلية. تتم إدارة ميزة "اكتشاف الجهاز" تلقائيًا من خلال "CastContext". اختَر جهاز البث وسيتم تحميل نموذج تطبيق الاستقبال على جهاز البث. ويمكنك التنقل بين نشاط التصفّح ونشاط المشغّل المحلي بحيث تبقى حالة زر البث متزامنة.

لم يتم توفير أي دعم لتشغيل الوسائط، لذلك لا يمكنك تشغيل فيديوهات على جهاز البث بعد. انقر على زر البث لإلغاء الربط.

6- بث محتوى الفيديو

صورة توضيحية لهاتف Android يستخدم ميزة &quot;بث الفيديوهات&quot; تطبيق واحد

سيتم توسيع نطاق نموذج التطبيق لتشغيل الفيديوهات عن بُعد أيضًا على جهاز بث. لتنفيذ ذلك، نحتاج إلى الاستماع إلى الأحداث المختلفة التي أنشأها إطار العمل Cast.

بث الوسائط

على المستوى العالي، إذا كنت تريد تشغيل وسائط على جهاز بث، يجب تنفيذ الإجراءات التالية:

  1. أنشئ عنصر MediaInfo لإنشاء نموذج لعنصر وسائط.
  2. اتصِل بجهاز البث وشغِّل تطبيق الاستقبال.
  3. ما عليك سوى تحميل كائن MediaInfo إلى جهاز الاستقبال وتشغيل المحتوى.
  4. تتبُّع حالة الوسائط
  5. إرسال أوامر التشغيل إلى المستلِم استنادًا إلى تفاعلات المستخدم

لقد أكملنا الخطوة 2 في القسم السابق. من السهل تنفيذ الخطوة الثالثة باستخدام إطار عمل Cast. تمثل الخطوة 1 ارتباط كائن بآخر؛ MediaInfo هو ما يفهمه إطار عمل Cast، وMediaItem هو تغليف التطبيق لعنصر من الوسائط. يمكننا بسهولة ربط MediaItem بـ MediaInfo.

يميّز نموذج التطبيق LocalPlayerActivity حاليًا بين التشغيل المحلي والتشغيل عن بُعد باستخدام هذا التعداد:

private var mLocation: PlaybackLocation? = null

enum class PlaybackLocation {
    LOCAL, REMOTE
}

enum class PlaybackState {
    PLAYING, PAUSED, BUFFERING, IDLE
}

ليس من المهم في هذا الدرس التطبيقي حول الترميز التعرّف بدقة على آلية عمل نموذج منطق المشغّل بالكامل. من المهم أن تفهم أنه يجب تعديل مشغّل الوسائط في تطبيقك ليكون على علم بموقعي التشغيل بطريقة مماثلة.

في الوقت الحالي، يكون المشغّل المحلي دائمًا في حالة التشغيل المحلي لأنّه لا تتوفّر لديه معلومات عن حالات الإرسال بعد. نحتاج إلى تحديث واجهة المستخدم بناءً على عمليات نقل الحالة التي تحدث في إطار عمل Cast. على سبيل المثال، إذا بدأنا البث، علينا إيقاف التشغيل على الجهاز وإيقاف بعض عناصر التحكّم. وبالمثل، إذا توقفنا عن البث عندما نكون في هذا النشاط، علينا الانتقال إلى وضع التشغيل المحلي. لمعالجة ذلك، علينا الاستماع إلى الأحداث المختلفة التي ينشئها إطار عمل Cast.

إدارة جلسة البث

بالنسبة إلى إطار عمل Google 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"، يهمّنا أن يتم إبلاغك عندما نتصل بجهاز البث أو عندما نقطع الاتصال به حتى نتمكّن من التبديل إلى المشغّل المحلي أو منه. يُرجى العِلم أنّه يمكن أن يتم إيقاف الاتصال بالإنترنت ليس فقط من خلال مثيل التطبيق الذي يعمل على جهازك الجوّال، ولكن يمكن أيضًا أن ينقطع الاتصال به بسبب تشغيل مثيل آخر من التطبيق (أو التطبيق الآخر) على جهاز جوّال آخر.

يمكن الوصول إلى الجلسة النشطة حاليًا باسم SessionManager.getCurrentSession(). يتم إنشاء الجلسات وإزالتها تلقائيًا استجابةً لتفاعلات المستخدم مع مربّعات حوار البث.

نحتاج إلى تسجيل مستمع الجلسة الخاص بنا وتهيئة بعض المتغيرات التي سنستخدمها في النشاط. تغيير طريقة 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)
        }
    }
    ...
}

جارٍ تحميل الوسائط

في حزمة تطوير البرامج (SDK) الخاصة بالبث، توفّر RemoteMediaClient مجموعة من واجهات برمجة التطبيقات المناسبة لإدارة تشغيل الوسائط عن بُعد على المستلِم. بالنسبة إلى 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()
    }
}

يمكنك الآن تعديل طرق حالية متنوعة لاستخدام منطق جلسة البث لإتاحة التشغيل عن بُعد:

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))
    ...
}

انقر الآن على الزر الزر &quot;تشغيل&quot; في &quot;استوديو Android&quot;، وهو مثلث أخضر يشير إلى اليمينتشغيل لتشغيل التطبيق على جهازك الجوّال. اتصل بجهاز البث وابدأ في تشغيل الفيديو. من المفترض أن ترى الفيديو قيد التشغيل على جهاز الاستقبال.

7. وحدة تحكُّم صغيرة

تتطلب قائمة التحقّق من تصميم البثّ أن توفّر جميع تطبيقات البثّ وحدة تحكّم مصغّرة تظهر عندما ينتقل المستخدم من صفحة المحتوى الحالية. وتوفِّر وحدة التحكّم الصغيرة إمكانية الوصول الفوري وتذكيرًا مرئيًا بجلسة البث الحالية.

صورة توضيحية للجزء السفلي من هاتف Android يعرض المشغّل المصغّر في تطبيق Cast Videos

توفّر حزمة تطوير البرامج (SDK) لتكنولوجيا 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"/>

انقر على الزر الزر &quot;تشغيل&quot; في &quot;استوديو Android&quot;، وهو مثلث أخضر يشير إلى اليمينتشغيل لتشغيل التطبيق وإرسال فيديو. عند بدء التشغيل على جهاز الاستقبال، من المفترض أن تظهر وحدة التحكّم المصغَّرة أسفل كل نشاط. يمكنك التحكّم في التشغيل عن بُعد باستخدام وحدة التحكّم الصغيرة. إذا انتقلت بين نشاط التصفّح ونشاط المشغّل المحلي، يجب أن تبقى حالة وحدة التحكّم المصغّرة متزامنة مع حالة تشغيل الوسائط لدى المُستلِم.

8. الإشعار وشاشة القفل

تتطلب قائمة التحقق من تصميم Google Cast أن ينفذ تطبيق المرسل عناصر التحكم في الوسائط من الإشعار وشاشة القفل.

صورة توضيحية لهاتف Android يعرض عناصر التحكّم في الوسائط في منطقة الإشعارات

توفّر حزمة تطوير البرامج (SDK) لتكنولوجيا 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()
}

انقر على الزر الزر &quot;تشغيل&quot; في &quot;استوديو Android&quot;، وهو مثلث أخضر يشير إلى اليمينتشغيل لتشغيل التطبيق على جهازك الجوّال. يمكنك إرسال فيديو والانتقال من التطبيق النموذجي. من المفترض أن يكون هناك إشعار بشأن الفيديو الذي يتم تشغيله حاليًا على جهاز الاستقبال. يمكنك قفل جهازك الجوّال ومن المفترض أن تعرض شاشة القفل الآن عناصر التحكّم في تشغيل الوسائط على جهاز البث.

صورة توضيحية لهاتف Android يعرض عناصر التحكّم في الوسائط على شاشة القفل

9. تراكب تمهيدي

تتطلب قائمة التحقق من تصميم Google Cast من أحد تطبيقات المرسل تقديم زر البث للمستخدمين الحاليين لإبلاغهم بأن تطبيق المرسل يتيح الآن البث ويساعد أيضًا المستخدمين الجدد على Google Cast.

صورة توضيحية تعرض تراكب &quot;البث&quot; التمهيدي حول زر الإرسال في تطبيق &quot;فيديوهات البث&quot; المتوافق مع Android

توفّر حزمة تطوير البرامج (SDK) لتقنية Cast طريقة عرض مخصّصة، IntroductoryOverlay، يمكن استخدامها لتمييز زر البث عند عرضه للمستخدمين لأول مرة. أضِف الرمز التالي إلى 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 واستدعِ الطريقة showIntroductoryOverlay عند توفُّر جهاز البث من خلال تعديل طريقة onCreate وإلغاء طريقة 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!!)
}

يمكنك محو بيانات التطبيق أو إزالته من جهازك. بعد ذلك، انقر على الزر الزر &quot;تشغيل&quot; في &quot;استوديو Android&quot;، وهو مثلث أخضر يشير إلى اليمينتشغيل لتشغيل التطبيق على جهازك الجوّال ومن المفترض أن يظهر لك التراكب التمهيدي (امسح بيانات التطبيق إذا لم يتم عرض التراكب).

10. تم توسيع وحدة التحكُّم

تتطلب قائمة التحقق من تصميم Google Cast أن يوفر تطبيق المرسل وحدة تحكم موسّعة للوسائط التي يتم بثها. وحدة التحكم الموسعة هي إصدار ملء الشاشة من وحدة التحكم المصغَّرة.

صورة توضيحية لفيديو يتم تشغيله على هاتف Android وتظهر فوقه وحدة تحكّم موسّعة

توفّر حزمة تطوير البرامج (SDK) لتكنولوجيا Cast أداةًا لوحدة التحكّم الموسّعة باسم ExpandedControllerActivity. هذه فئة مجردة يجب أن تتضمن فئة فرعية لإضافة زر البث.

أولاً، أنشئ ملف موارد قائمة جديدًا، باسم expanded_controller.xml، لوحدة التحكم الموسّعة من أجل توفير زر البث:

<?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())
}

انقر على الزر الزر &quot;تشغيل&quot; في &quot;استوديو Android&quot;، وهو مثلث أخضر يشير إلى اليمينتشغيل لتشغيل التطبيق على جهازك الجوّال وبث فيديو. من المفترض أن تظهر لك وحدة التحكّم الموسّعة. انتقل مرة أخرى إلى قائمة الفيديوهات وعند النقر على وحدة التحكم المصغَّرة، سيتم تحميل وحدة التحكم الموسعة مرة أخرى. انتقِل إلى مكان آخر خارج التطبيق للاطّلاع على الإشعار. انقر على صورة الإشعار لتحميل وحدة التحكّم الموسّعة.

11. إضافة دعم Cast Connect

تسمح مكتبة Cast Connect لتطبيقات المُرسِلين الحالية بالتواصل مع تطبيقات Android TV عبر بروتوكول Cast. تعتمد خدمة Cast Connect على البنية الأساسية للبث، ويعمل تطبيق Android TV كوحدة استقبال.

التبعيات

ملاحظة: لتنفيذ Cast Connect، يجب أن يكون play-services-cast-framework 19.0.0 أو أعلى.

LaunchOptions

لتشغيل تطبيق Android TV، الذي يُشار إليه أيضًا باسم "مستقبل Android"، نحتاج إلى ضبط علامة setAndroidReceiverCompatible على "صحيح" في كائن LaunchOptions. يوضح عنصر LaunchOptions هذا كيفية تشغيل جهاز الاستقبال وتمريره إلى CastOptions التي تعرضها الفئة CastOptionsProvider. يؤدي ضبط العلامة المذكورة أعلاه على false إلى تشغيل جهاز استقبال الويب لمعرّف التطبيق المحدّد في Play Console.

في ملف 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.

لضبط بيانات اعتماد الإطلاق، يجب تحديد 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

إذا كان التعامل مع تطبيق "استقبال الويب" وتطبيق Android TV يختلف عن credentials، قد تحتاج إلى تحديد credentials منفصل لكل منهما. ولتنفيذ ذلك، أضِف الرمز التالي في ملف LocalPlayerActivity.kt ضمن الدالة loadRemoteMedia:

remoteMediaClient.load(MediaLoadRequestData.Builder()
       ...
       .setCredentials("user-credentials")
       .setAtvCredentials("atv-user-credentials")
       .build())

استنادًا إلى تطبيق المُستلِم الذي يرسِل إليه المُرسِل، ستتعامل حزمة SDK الآن تلقائيًا مع بيانات الاعتماد التي سيتم استخدامها للجلسة الحالية.

اختبار الاتصال بالبث

خطوات تثبيت حزمة APK Android TV على جهاز "Chromecast مع Google TV"

  1. ابحث عن عنوان IP لجهاز Android TV. وعادةً ما تكون متاحة ضمن الإعدادات > الشبكة الإنترنت > (اسم الشبكة التي يتصل بها جهازك) على يمين الشاشة، ستعرض هذه النافذة التفاصيل وعنوان IP لجهازك على الشبكة.
  2. استخدِم عنوان IP لجهازك للاتصال به عبر ADB باستخدام الوحدة الطرفية:
$ adb connect <device_ip_address>:5555
  1. من النافذة الطرفية، انتقِل إلى مجلد المستوى الأعلى لعيّنات الدروس التطبيقية حول الترميز التي نزّلتها في بداية هذا الدرس التطبيقي حول الترميز. على سبيل المثال:
$ cd Desktop/android_codelab_src
  1. ثبِّت ملف apk .في هذا المجلد على Android TV من خلال تنفيذ ما يلي:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. من المفترض أن تتمكّن الآن من رؤية أحد التطبيقات باسم بث الفيديوهات في قائمة تطبيقاتك على جهاز Android TV.
  2. ارجع إلى مشروع "استوديو Android" وانقر على الزر "تشغيل" لتثبيت تشغيل تطبيق المرسِل على جهازك الجوّال الفعلي. في أعلى يسار الشاشة، انقر على رمز البث واختَر جهاز Android TV من الخيارات المتاحة. من المفترض أن ترى الآن أنّه تم إطلاق تطبيق Android TV على جهاز Android TV، ومن المفترض أن يتيح لك تشغيل فيديو التحكّم في تشغيل الفيديو باستخدام جهاز التحكّم عن بُعد في Android TV.

12. تخصيص التطبيقات المصغّرة للبث

يمكنك تخصيص أدوات البث من خلال ضبط الألوان وتصميم الأزرار والنص ومظهر الصورة المصغّرة واختيار أنواع الأزرار التي سيتم عرضها.

تحديث 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>

13. تهانينا

تعرفت الآن على كيفية تفعيل ميزة Google Cast في تطبيق فيديو باستخدام أدوات Cast SDK على نظام التشغيل Android.

لمزيد من التفاصيل، يُرجى الاطّلاع على دليل المطوِّر لمرسلي Android.