הפעלה של אפליקציית Android

קל לארגן דפים בעזרת אוספים אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.

1. סקירה כללית

הלוגו של Google Cast

ב-Codelab הזה תלמדו איך לשנות אפליקציית וידאו קיימת ל-Android כדי להעביר תוכן ממכשיר תומך ב-Google Cast.

מה זה Google Cast?

Google Cast מאפשר למשתמשים להעביר תוכן מהנייד לטלוויזיה. לאחר מכן, המשתמשים יוכלו להשתמש במכשיר הנייד שלהם כשלט רחוק להפעלת מדיה בטלוויזיה.

ה-SDK של Google Cast מאפשר לך להרחיב את האפליקציה כדי לשלוט בטלוויזיה או במערכת אודיו. ה-SDK של Cast מאפשר להוסיף את רכיבי ממשק המשתמש הנחוצים על סמך רשימת המשימות של Google Cast Design.

רשימת המשימות לעיצוב של Google Cast זמינה כדי להפוך את חוויית המשתמש ב-Cast לפשוטה וניתנת לחיזוי בכל הפלטפורמות הנתמכות.

מה תכננת לבנות?

לאחר השלמת ה-Codelab הזה, תהיה לך אפליקציית וידאו ל-Android שתוכל להעביר (cast) סרטונים למכשיר שמופעל בו Google Cast.

מה תלמדו

  • איך מוסיפים את Google Cast SDK לאפליקציית וידאו לדוגמה.
  • איך מוסיפים את לחצן הפעלת Cast לבחירת מכשיר Google Cast
  • איך להתחבר למכשיר CAST ולהפעיל מקלט מדיה.
  • איך מעבירים סרטון?
  • איך מוסיפים שלט רחוק להעברה אל האפליקציה.
  • איך לתמוך בהתראות מדיה ובפקדי נעילת מסך.
  • איך להוסיף שלט רחוק מורחב.
  • איך מספקים שכבת-על של מבוא?
  • איך מתאימים אישית את הווידג'טים של Cast?
  • איך לבצע שילוב עם Cast Connect

מה הדרישות כדי להצטרף לתוכנית?

  • ב-Android SDK האחרון.
  • Android Studio בגרסה 3.2 ואילך
  • מכשיר נייד אחד עם Android מגרסה 4.1 ואילך (Jely Bean (רמת API 16).
  • כבל נתונים מסוג USB לחיבור המכשיר הנייד למחשב הפיתוח.
  • מכשיר Google Cast כמו Chromecast או Android TV שהוגדר עם גישה לאינטרנט.
  • טלוויזיה או צג עם קלט HDMI.
  • כדי לבדוק את השילוב של Cast Connect, צריך להשתמש ב-Chromecast with Google TV, אבל בשאר המקרים אפשר ליהנות מ-Codelab. אם אין לכם קוד כזה, אפשר לדלג על השלב הוספת תמיכה ב-Cast Connect לקראת סוף המדריך.

ניסיון

  • נדרש ידע קודם לפיתוח של Kotlin ושל Android.
  • כדי לצפות בטלוויזיה תצטרכו גם ידע קודם :)

איך תשתמשו במדריך הזה?

לקריאה בלבד לקריאה ולהשלמת התרגילים

איזה דירוג מגיע לדעתך לחוויה שלך עם בניית אפליקציות ל-Android?

מתחילים בינוניים בקיאים

איזה דירוג מתאים לדעתך לחוויית הצפייה בטלוויזיה?

מתחילים בינוניים בקיאים

2. קבל את הקוד לדוגמה

אפשר להוריד למחשב את כל הקוד לדוגמה...

ופרקים את קובץ ה-ZIP שהורדתם.

3. הרצת האפליקציה לדוגמה

סמל של זוג מצפן

קודם צריך לבדוק איך האפליקציה לדוגמה מסתיימת. האפליקציה היא נגן וידאו בסיסי. המשתמש יכול לבחור סרטון מתוך רשימה ולאחר מכן להפעיל את הסרטון באופן מקומי במכשיר או להעביר (cast) אותו למכשיר Google Cast.

לאחר הורדת הקוד, ההוראות הבאות מתארות איך לפתוח ולהפעיל את האפליקציה לדוגמה לדוגמה ב-Android Studio:

בוחרים באפשרות Import Project (ייבוא פרויקט) או בתפריט File > New > Import Project....

מאתרים את הספרייה סמל תיקייהapp-done מהתיקייה של הקוד לדוגמה ולוחצים על 'אישור'.

לוחצים על קובץ > Android Studio 'Sync Project with Gradle' button סנכרון פרויקט עם קובצי Gradle.

הפעלת ניפוי באגים ב-USB במכשיר Android – ב-Android 4.2 ואילך, מסך האפשרויות למפתחים מוסתר כברירת מחדל. כדי להגדיר את המספר כגלוי, עוברים אל הגדרות > מידע על הטלפון ומקישים על מספר Build 7 פעמים. חוזרים למסך הקודם, עוברים אל מערכת > מתקדם ומקישים על אפשרויות למפתחים בתחתית המסך. לאחר מכן מקישים על ניפוי באגים ב-USB כדי להפעיל אותו.

מחברים את מכשיר ה-Android ולוחצים על לחצן הלחצן הפעלה של Android Studio& 33, משולש ירוק שמצביע ימינההפעלה ב-Android Studio. לאחר מספר שניות אמורה להופיע אפליקציית הווידאו סרטוני העברה.

לוחצים על לחצן ההעברה באפליקציית הווידאו ובוחרים את מכשיר ה-Google Cast.

בוחרים סרטון ולוחצים על לחצן ההפעלה.

הסרטון יתחיל לפעול במכשיר Google Cast.

הבקר המורחב יוצג. אפשר להשתמש בלחצן ההפעלה/השהיה כדי לשלוט בהפעלה.

חוזרים לרשימת הסרטונים.

שלט רחוק קטן מוצג עכשיו בתחתית המסך. איור של טלפון Android שבו פועלת האפליקציה 'העברה (Cast)' אפליקציית מיני-בקר שמופיעה בחלק התחתון של המסך

לוחצים על לחצן ההשהיה במיני-נגן כדי להשהות את הסרטון במקלט. יש ללחוץ על לחצן ההפעלה במיני-נגן כדי להמשיך ולהפעיל את הסרטון שוב.

לוחצים על הלחצן הראשי במכשיר הנייד. יש למשוך למטה התראות, ועכשיו אמורה להופיע התראה על סשן ההעברה.

לנעול את הטלפון וכשמבטלים את הנעילה שלו, אמורה להופיע התראה במסך הנעילה כדי לשלוט בהפעלת המדיה או להפסיק את ההעברה.

חוזרים לאפליקציית הווידאו ולוחצים על לחצן ההעברה כדי להפסיק את ההעברה במכשיר Google Cast.

שאלות נפוצות

4. מכינים את פרויקט ההתחלה

איור של טלפון Android שבו פועלת האפליקציה 'העברה (Cast) של סרטונים'

עלינו להוסיף תמיכה ב-Google Cast לאפליקציה להתחלה שהורדתם. הנה כמה מונחי Google Cast שבהם נשתמש ב-Codelab הזה:

  • אפליקציית השולח פועלת במכשיר נייד או במחשב נייד,
  • אפליקציית מקלט פועלת במכשיר Google Cast.

עכשיו אפשר לבנות מעל הפרויקט למתחילים באמצעות Android Studio:

  1. בוחרים את הספרייה סמל תיקייהapp-start מהורדת הקוד לדוגמה (בוחרים באפשרות ייבוא פרויקט במסך הפתיחה, או באפשרות התפריט קובץ > חדש > ייבוא פרויקט...).
  2. לוחצים על הלחצן Android Studio 'Sync Project with Gradle' button Project Project (סנכרון פרויקט עם קובצי Gradle).
  3. לוחצים על הלחצן לחצן הפעלה של Android Studio& 33, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה ולעיין בממשק המשתמש.

עיצוב אפליקציות

האפליקציה מאחזרת רשימה של סרטונים משרת אינטרנט מרוחק ומספקת רשימה עבור המשתמש לעיון. משתמשים יכולים לבחור סרטון כדי לראות את הפרטים או להפעיל אותו באופן מקומי בנייד.

האפליקציה מורכבת משתי פעילויות עיקריות: VideoBrowserActivity וLocalPlayerActivity. כדי לשלב את הפונקציונליות של Google Cast, הפעילויות צריכות לרשת בירושה מ-AppCompatActivity או מההורה שלה FragmentActivity. המגבלה הזו קיימת מפני שנצטרך להוסיף את MediaRouteButton (שמסופק בספריית התמיכה של MediaRouter) בתור MediaRouteActionProvider, והוא יפעל רק אם הפעילות עוברת בירושה מהכיתות שצוינו למעלה. ספריית התמיכה של MediaRouter תלויה בספריית התמיכה של AppCompat הכוללת את הכיתות הנדרשות.

פעילות בדפדפני וידאו

פעילות זו מכילה Fragment (VideoBrowserFragment). הרשימה הזו מגובת ב-ArrayAdapter (VideoListAdapter). רשימת הסרטונים והמטא-נתונים המשויכים אליהם מתארחים בשרת מרוחק כקובץ JSON. AsyncTaskLoader (VideoItemLoader) מאחזר את ה-JSON ומעבד אותו כדי ליצור רשימה של אובייקטים מסוג MediaItem.

אובייקט MediaItem יוצר מודל של סרטון והמטא-נתונים המשויכים אליו, כמו השם, התיאור, כתובת ה-URL של השידור, כתובת ה-URL של התמונות הנתמכות וקובצי הטקסט המשויכים (לכתוביות) אם יש כאלה. האובייקט MediaItem מועבר בין פעילויות, כך של-MediaItem יש שיטות שירות להמיר אותו ל-Bundle, ולהפך.

כאשר הכלי לטעינת אתרים בונה את הרשימה MediaItems, היא מעבירה את הרשימה אל VideoListAdapter שמציגה את הרשימה MediaItems ב-VideoBrowserFragment. למשתמש מוצגת רשימה של תמונות ממוזערות של סרטונים, עם תיאור קצר של כל סרטון. אם בוחרים פריט, הערך של MediaItem התואם מומר ל-Bundle ומועבר אל LocalPlayerActivity.

פעילות של LocalPlayer

פעילות זו מציגה את המטא נתונים של סרטון מסוים ומאפשרת למשתמש להפעיל את הסרטון באופן מקומי במכשיר הנייד.

בפעילות מוצג VideoView, פקדי מדיה ואזור טקסט כדי להציג את התיאור של הסרטון שנבחר. הנגן מכסה את החלק העליון של המסך ומשאיר מקום לתיאור המפורט של הסרטון למטה. המשתמש יכול להפעיל/להשהות או לחפש הפעלה מקומית של סרטונים.

יחסי תלות

מכיוון שאנחנו משתמשים ב-AppCompatActivity, אנחנו צריכים את ספריית התמיכה של AppCompat. כדי לנהל את רשימת הסרטונים ולקבל אסינכרוני של התמונות של הרשימה, אנחנו משתמשים בספריית Volly.

שאלות נפוצות

5. הוספת לחצן ההעברה

איור של החלק העליון של טלפון Android שבו פועלת אפליקציית Cast Video. לחצן ההעברה מופיע בפינה השמאלית העליונה של המסך

אפליקציה שתומכת ב-Cast מציגה את לחצן ההעברה בכל אחת מהפעילויות שלה. לחיצה על לחצן ההעברה מציגה רשימה של מכשירי CAST שמשתמשים יכולים לבחור. אם המשתמש הפעיל תוכן באופן מקומי במכשיר השולח, בחירת מכשיר CAST תפעיל או תמשיך את ההפעלה במכשיר ה-CAST. בכל שלב במהלך פעילות העברה, המשתמש יכול ללחוץ על לחצן ההעברה ולהפסיק את העברת האפליקציה למכשיר ה-CAST. המשתמש חייב להתחבר למכשיר ה-CAST או להתנתק ממנו בכל פעילות של האפליקציה שלך, כפי שמתואר ברשימת המשימות לעיצוב של Google 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"
}

צריך לסנכרן את הפרויקט כדי לאשר את יצירת הפרויקט ללא שגיאות.

אתחול

למסגרת ההעברה יש אובייקט יחיד של סינגל, CastContext, שמרכז את כל האינטראקציות של Cast.

עליך ליישם את הממשק OptionsProvider כדי לספק את CastOptions הדרוש להפעלת הסינגל CastContext. האפשרות החשובה ביותר היא מזהה האפליקציה של המקבל, שמשמש לסינון של תוצאות גילוי מכשירי 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 באופן VideoBrowserActivity בשיטת onCreate:

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.

לחצן הפעלת Cast

עכשיו, לאחר הפעלת ה-CastContext, עלינו להוסיף את לחצן ההעברה כדי לאפשר למשתמש לבחור מכשיר CAST. לחצן ההעברה מוטמע על ידי 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 ל-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
}

שינוי הערך onCreateOptionsMenu בשיטת LocalPlayerActivity באופן דומה.

לוחצים על הלחצן לחצן הפעלה של Android Studio& 33, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה בנייד. אמור להופיע לחצן 'העברה' בסרגל הפעולות של האפליקציה. לחיצה עליו תציג את מכשירי ה-Cast ברשת המקומית שלך. חיפוש המכשיר מנוהל באופן אוטומטי על ידי CastContext. בוחרים את מכשיר ה-CAST, ואפליקציית דגם המקבל תיטען במכשיר ה-Cast. אתם יכולים לעבור בין פעילות הגלישה לפעילות הנגן המקומי והמצב של לחצן ההעברה מסונכרן.

עדיין לא סייענו בהפעלת מדיה, ולכן עדיין לא ניתן להפעיל סרטונים במכשיר ה-Cast. לוחצים על לחצן ההעברה כדי להתנתק.

6. העברה (cast) של תוכן וידאו

איור של טלפון Android שבו פועלת האפליקציה &#39;העברה (Cast) של סרטונים&#39;

אנחנו נרחיב את האפליקציה לדוגמה כדי להפעיל גם סרטונים מרחוק במכשיר CAST. לשם כך, אנחנו צריכים להאזין לאירועים השונים שנוצרים במסגרת מסגרת ההעברה.

העברת מדיה מתבצעת

ברמה גבוהה, אם רוצים להפעיל מדיה במכשיר CAST, צריך לבצע את הפעולות הבאות:

  1. יוצרים אובייקט MediaInfo שמציג מודל של פריט מדיה.
  2. מחברים את מכשיר ה-CAST ומפעילים את אפליקציית המקלט.
  3. יש לטעון את האובייקט MediaInfo אל המקלט ולהפעיל את התוכן.
  4. לעקוב אחרי סטטוס המדיה.
  5. שליחת פקודות הפעלה למקלט על סמך אינטראקציות של משתמשים.

כבר עשינו את השלב השני בקטע הקודם. שלב 3 קל לעשות עם מסגרת ההעברה. שלב 1 ממופה אובייקט אחד לאובייקט אחר; MediaInfo הוא משהו ש-Cast מסגרת מבינה ו-MediaItem היא הקפסולה של האפליקציה לפריט מדיה. אנחנו יכולים למפות בקלות MediaItem אל MediaInfo.

באמצעות האפליקציה 'enum' הזו, האפליקציה לדוגמה LocalPlayerActivity כבר מבחינה בין הפעלה מקומית לבין הפעלה מרחוק:

private var mLocation: PlaybackLocation? = null

enum class PlaybackLocation {
    LOCAL, REMOTE
}

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

ב-Codelab הזה לא חשוב להבין איך בדיוק פועלת הלוגיקה של הנגן לדוגמה. חשוב להבין שיש להפעיל את נגן המדיה של האפליקציה כדי להיות מודעים לשני מיקומי ההפעלה באופן דומה.

הנגן המקומי תמיד נמצא במצב הפעלה מקומי, כי אין לו עדיין מידע על מצבי ההעברה. אנחנו צריכים לעדכן את ממשק המשתמש בהתאם להעברות המדינה שמתרחשות במסגרת Cast Cast. לדוגמה, אם אנחנו מתחילים בהעברה (cast), אנחנו צריכים להפסיק את ההפעלה המקומית ולהשבית חלק מהפקדים. באופן דומה, אם נפסיק להשתמש בתוכן בזמן הפעילות, עלינו לעבור להפעלה מקומית. כדי לטפל בכך, אנחנו צריכים להאזין לאירועים השונים שנוצרו על ידי מסגרת ההעברה.

ניהול סשנים של העברה

במסגרת ההעברה (cast), סשן העברה משלב את שלבי החיבור למכשיר, הפעלה (או הצטרפות), התחברות לאפליקציית מקלט ואתחול ערוץ בקרה של מדיה לפי הצורך. הערוץ של בקרת המדיה הוא האופן שבו מסגרת ההעברה שולחת הודעות מנגן המדיה והמקבל.

סשן ההעברה יתחיל באופן אוטומטי כשהמשתמש יבחר מכשיר מלחצן ההעברה, וייפסק באופן אוטומטי כשהמשתמש ינותק. החיבור מחדש לסשן של מקלט עקב בעיות ברשת מטופל גם באופן אוטומטי על ידי ה-SDK של Cast.

נוסיף 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.

עלינו לרשום את המאזינים שלנו לסשנים ולהפעיל כמה משתנים שבהם נשתמש בפעילות. שינוי השיטה LocalPlayerActivity onCreate ל:

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

עכשיו צריך לעדכן את השיטות הקיימות כדי להשתמש בלוגיקת הסשן כדי לתמוך בהפעלה מרחוק:

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

עכשיו, צריך ללחוץ על הלחצן לחצן הפעלה של Android Studio& 33, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה בנייד. מחברים את מכשיר ה-Cast ומתחילים להפעיל סרטון. הסרטון אמור להופיע במקלט.

7. מיני-בקר

רשימת המשימות לעיצובים של Cast דורשת שכל אפליקציית Cast תכלול בקר מיני שמופיע כשהמשתמש יוצא מדף התוכן הנוכחי. השלט הרחוק המקוצר מספק גישה מיידית ותזכורת גלויה לסשן הנוכחי.

איור של החלק התחתון של טלפון Android שבו מופיע המיני-נגן באפליקציית Cast Cast

ב-Cast SDK יש תצוגה מותאמת אישית, 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"/>

לוחצים על הלחצן לחצן הפעלה של Android Studio& 33, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה ולהעביר סרטון. כשההפעלה מתחילה במקלט, השלט הרחוק הקטן אמור להופיע בחלק התחתון של כל פעילות. אפשר לשלוט בהפעלה מרחוק באמצעות השלט הרחוק. אם מנווטים בין פעילות הגלישה לפעילות הנגן המקומי, המצב של המיני-בקר צריך להישאר מסונכרן עם סטטוס הפעלת המדיה של המקלט.

8. התראות ומסך הנעילה

ברשימת המשימות לעיצוב של Google Cast נדרשת אפליקציית שליחה כדי להטמיע פקדי מדיה מהודעה וממסך הנעילה.

איור של טלפון Android שבו מוצגים אמצעי הבקרה של מדיה באזור ההתראות

ב-Cast SDK יש MediaNotificationService כדי לעזור לאפליקציית השולח ליצור פקדי מדיה להתראות ולמסך הנעילה. השירות משולב באופן אוטומטי במניפסט של האפליקציה.

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

לוחצים על הלחצן לחצן הפעלה של Android Studio& 33, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה בנייד. העברה (cast) של סרטון וניווט חוץ מהאפליקציה לדוגמה. אמורה להופיע התראה לגבי הסרטון שמופעל כרגע במקלט. עכשיו צריך לנעול את המכשיר הנייד ומסך הנעילה אמור להציג עכשיו פקדים להפעלת מדיה במכשיר ה-Cast.

איור של טלפון Android שבו לחצני הבקרה מוצגים במסך הנעילה

9. שכבת-על של מבוא

כדי להשתמש ברשימת המשימות לעיצוב של Google Cast, צריך להשתמש באפליקציית שולח כדי להציג את לחצן ההעברה למשתמשים קיימים. כך, הם ידעו שאפליקציית השולח תומכת עכשיו בהעברה (cast) וגם תעזור למשתמשים חדשים ב-Google Cast.

איור שמציג את שכבת-העל של ההעברה במסך מקיף את לחצן ההעברה (Cast) באפליקציה ל-Android

ב-Cast SDK יש תצוגה מותאמת אישית, 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 כשמכשיר CAST זמין, על ידי שינוי השיטה 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!!)
}

מנקים את נתוני האפליקציה או מסירים את האפליקציה מהמכשיר. לאחר מכן, לוחצים על הלחצן לחצן הפעלה של Android Studio& 33, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה בנייד. אם שכבת-העל לא מוצגת, אמורים לראות את שכבת-העל של האפליקציה (ניקוי נתוני האפליקציה).

10. בקר מורחב

רשימת המשימות לעיצוב של Google Cast מחייבת אפליקציית שליחה לספק בקר מורחב להעברת המדיה. הבקר המורחב הוא גרסה של מסך מלא של השלט הרחוק.

איור של סרטון שמופעל בטלפון Android עם שלט רחוק שמכסה אותו

ה-SDK של ה-SDK מספק ווידג'ט לבקר המורחב 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()
}

צריך לעדכן את השיטה LocalPlayerActivity loadRemoteMedia כדי להציג את 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())
}

לוחצים על הלחצן לחצן הפעלה של Android Studio& 33, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה במכשיר הנייד ולהעביר סרטון. הבקר המורחב אמור להופיע. הבקר בחזרה לרשימת הסרטונים וכשלוחצים על המיני-בקר, הבקר המורחב ייטען מחדש. יוצאים מהאפליקציה כדי לראות את ההתראה. לוחצים על תמונת ההתראה כדי לטעון את הבקר המורחב.

11. הוספת תמיכה של Cast Connect

ספריית Cast Connect מאפשרת לאפליקציות לשלוח קיימות לתקשר עם אפליקציות Android TV באמצעות פרוטוקול Cast. מכשיר Cast Connect מתווסף לתשתית ה-Cast, כשאפליקציית Android TV פועלת כמקלט.

יחסי תלות

הערה: כדי להטמיע את Cast Connect, הערך של play-services-cast-framework צריך להיות 19.0.0 או יותר.

אפשרויות פתיחה

כדי להפעיל את האפליקציה ל-Android TV, שנקראת גם מקלט Android, עלינו להגדיר את הסימון של setAndroidReceiverCompatible כ-True באובייקט LaunchOptions. אובייקט LaunchOptions הזה קובע את אופן ההפעלה של המקבל וההעברה שלו אל CastOptions שמוחזרת על ידי הכיתה CastOptionsProvider. הגדרת הדגל שצוין למעלה כ-false תפעיל את מקלט האינטרנט עבור מזהה האפליקציה שהוגדר ב-Cast Developer 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 יטפל באופן אוטומטי בפרטי הכניסה שבהם יש להשתמש בסשן הנוכחי.

בדיקת חיבור Cast

שלבים להתקנת ה-APK של Android TV ב-Chromecast with Google TV

  1. מאתרים את כתובת ה-IP של מכשיר ה-Android TV. בדרך כלל, הוא זמין בקטע הגדרות > רשת & אינטרנט > (שם הרשת שאליו המכשיר מחובר). בצד שמאל יוצגו פרטי ה-IP של המכשיר ושל הרשת שלו.
  2. צריך להשתמש בכתובת ה-IP של המכשיר כדי להתחבר אליו דרך ADB באמצעות המסוף:
$ adb connect <device_ip_address>:5555
  1. בחלון הטרמינל, עוברים לתיקייה ברמה העליונה עם דוגמאות ה-Codelab שהורדתם בתחילת שיעור ה-Codelab הזה. למשל:
$ 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 Studio ולוחצים על לחצן ההפעלה כדי להתקין את האפליקציה; מפעילים את אפליקציית השולח במכשיר הפיזי. בפינה השמאלית העליונה, לוחצים על סמל ההעברה ובוחרים את מכשיר ה-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. מזל טוב

עכשיו אתם יודעים איך להפעיל אפליקציית וידאו באמצעות הווידג'טים של Cast SDK ב-Android.

לפרטים נוספים, עיינו במדריך למפתחים של שולח Android.