เปิดใช้แอป Android ได้

1. ภาพรวม

โลโก้ Google Cast

Codelab นี้จะสอนวิธีแก้ไขแอปวิดีโอ Android ที่มีอยู่เพื่อแคสต์เนื้อหาบนอุปกรณ์ที่พร้อมใช้งาน Google Cast

Google Cast คืออะไร

Google Cast ช่วยให้ผู้ใช้แคสต์เนื้อหาจากอุปกรณ์เคลื่อนที่ไปยังทีวีได้ จากนั้นผู้ใช้จะใช้อุปกรณ์เคลื่อนที่เป็นรีโมตคอนโทรลสำหรับการเล่นสื่อบนทีวีได้

Google Cast SDK ช่วยให้คุณขยายแอปเพื่อควบคุมทีวีหรือระบบเสียงได้ Cast SDK ช่วยให้คุณเพิ่มคอมโพเนนต์ UI ที่จำเป็นตามรายการตรวจสอบการออกแบบ Google Cast ได้

รายการตรวจสอบการออกแบบ Google Cast มีไว้เพื่อให้ประสบการณ์การใช้งาน Cast ของผู้ใช้ง่ายและคาดการณ์ได้ในทุกแพลตฟอร์มที่รองรับ

เราจะสร้างอะไร

เมื่อทำ Codelab นี้เสร็จแล้ว คุณจะมีแอปวิดีโอ Android ที่แคสต์วิดีโอไปยังอุปกรณ์ที่พร้อมใช้งาน Google Cast ได้

สิ่งที่คุณจะได้เรียนรู้

  • วิธีเพิ่ม Google Cast SDK ลงในแอปวิดีโอตัวอย่าง
  • วิธีเพิ่มปุ่มแคสต์เพื่อเลือกอุปกรณ์ Google Cast
  • วิธีเชื่อมต่อกับอุปกรณ์แคสต์และเปิดใช้งานตัวรับสื่อ
  • วิธีแคสต์วิดีโอ
  • วิธีเพิ่มตัวควบคุมขนาดเล็กของ Cast ลงในแอป
  • วิธีรองรับการแจ้งเตือนสื่อและการควบคุมหน้าจอล็อก
  • วิธีเพิ่มตัวควบคุมแบบขยาย
  • วิธีใส่ข้อความวางซ้อนแนะนำ
  • วิธีปรับแต่งวิดเจ็ตแคสต์
  • วิธีผสานรวมกับ Cast Connect

สิ่งที่คุณต้องมี

  • Android SDK เวอร์ชันล่าสุด
  • Android Studio เวอร์ชัน 3.2 ขึ้นไป
  • อุปกรณ์เคลื่อนที่ 1 เครื่องที่ใช้ Android 4.1 ขึ้นไป Jelly Bean (API ระดับ 16)
  • สายข้อมูล USB เพื่อเชื่อมต่ออุปกรณ์เคลื่อนที่กับคอมพิวเตอร์การพัฒนา
  • อุปกรณ์ Google Cast เช่น Chromecast หรือ Android TV ที่กำหนดค่าการเข้าถึงอินเทอร์เน็ต
  • ทีวีหรือจอภาพที่มีอินพุต HDMI
  • คุณต้องใช้ Chromecast พร้อม Google TV เพื่อทดสอบการผสานรวม Cast Connect แต่จะไม่บังคับสำหรับส่วนอื่นของ Codelab หากไม่มี ให้ข้ามขั้นตอนเพิ่มการรองรับ Cast Connect ในช่วงท้ายของบทแนะนำนี้

ประสบการณ์การใช้งาน

  • คุณจะต้องมีความรู้ด้านการพัฒนา Kotlin และ Android มาก่อน
  • นอกจากนี้ คุณจะต้องมีความรู้เกี่ยวกับการดูทีวีมาก่อนด้วย :)

คุณจะใช้บทแนะนำนี้อย่างไร

อ่านอย่างเดียว อ่านและทำแบบฝึกหัดให้เสร็จ

คุณจะให้คะแนนประสบการณ์ในการสร้างแอป Android อย่างไร

ผู้ฝึกหัด ระดับกลาง ผู้ชำนาญ

คุณจะให้คะแนนประสบการณ์ในการดูทีวีอย่างไร

มือใหม่ ระดับกลาง เชี่ยวชาญ

2. รับโค้ดตัวอย่าง

คุณสามารถดาวน์โหลดโค้ดตัวอย่างทั้งหมดลงในคอมพิวเตอร์ได้...

แล้วแตกไฟล์ ZIP ที่ดาวน์โหลดมา

3. เรียกใช้แอปตัวอย่าง

ไอคอนเข็มทิศ 2 คู่

ก่อนอื่น มาดูกันว่าแอปตัวอย่างที่เสร็จสมบูรณ์มีลักษณะเป็นอย่างไร แอปนี้เป็นโปรแกรมเล่นวิดีโอพื้นฐาน ผู้ใช้สามารถเลือกวิดีโอจากรายการ แล้วเล่นวิดีโอในอุปกรณ์หรือแคสต์ไปยังอุปกรณ์ Google Cast ได้

เมื่อดาวน์โหลดโค้ดแล้ว วิธีการต่อไปนี้จะอธิบายวิธีเปิดและเรียกใช้แอปตัวอย่างที่เสร็จสมบูรณ์ใน Android Studio

เลือกนําเข้าโปรเจ็กต์ในหน้าจอต้อนรับหรือตัวเลือกเมนูไฟล์ > ใหม่ > นําเข้าโปรเจ็กต์...

เลือกไดเรกทอรี ไอคอนโฟลเดอร์app-done จากโฟลเดอร์โค้ดตัวอย่าง แล้วคลิก "ตกลง"

คลิก File > ปุ่ม "ซิงค์โปรเจ็กต์กับ Gradle" ของ Android Studio Sync Project with Gradle Files

เปิดใช้การแก้ไขข้อบกพร่องผ่าน USB ในอุปกรณ์ Android - ใน Android 4.2 ขึ้นไป หน้าจอตัวเลือกสำหรับนักพัฒนาแอปจะซ่อนอยู่โดยค่าเริ่มต้น หากต้องการแสดงรหัส ให้ไปที่การตั้งค่า > เกี่ยวกับโทรศัพท์ แล้วแตะหมายเลขบิลด์ 7 ครั้ง กลับไปที่หน้าจอก่อนหน้า แล้วไปที่ระบบ > ขั้นสูง แล้วแตะตัวเลือกสำหรับนักพัฒนาแอปใกล้กับด้านล่าง จากนั้นแตะการแก้ไขข้อบกพร่อง USB เพื่อเปิด

เสียบอุปกรณ์ Android แล้วคลิกปุ่ม ปุ่ม Run ของ Android Studio รูปสามเหลี่ยมสีเขียวที่ชี้ไปทางขวาRun ใน Android Studio คุณควรเห็นแอปวิดีโอชื่อ Cast Videos ปรากฏขึ้นหลังจากผ่านไป 2-3 วินาที

คลิกปุ่มแคสต์ในแอปวิดีโอ แล้วเลือกอุปกรณ์ Google Cast

เลือกวิดีโอแล้วคลิกปุ่มเล่น

วิดีโอจะเริ่มเล่นในอุปกรณ์ Google Cast

ตัวควบคุมแบบขยายจะปรากฏขึ้น คุณใช้ปุ่มเล่น/หยุดชั่วคราวเพื่อควบคุมการเล่นได้

กลับไปที่รายการวิดีโอ

ตอนนี้ตัวควบคุมขนาดเล็กจะปรากฏที่ด้านล่างของหน้าจอ ภาพโทรศัพท์ Android ที่ใช้แอป "แคสต์วิดีโอ" โดยมีรีโมตคอนโทรลขนาดเล็กปรากฏที่ด้านล่างของหน้าจอ

คลิกปุ่มหยุดชั่วคราวในตัวควบคุมขนาดเล็กเพื่อหยุดวิดีโอบนตัวรับชั่วคราว คลิกปุ่มเล่นในตัวควบคุมขนาดเล็กเพื่อเล่นวิดีโอต่อ

คลิกปุ่มหน้าแรกบนอุปกรณ์เคลื่อนที่ ดึงการแจ้งเตือนลง คุณควรเห็นการแจ้งเตือนสำหรับเซสชันแคสต์

ล็อกโทรศัพท์และเมื่อปลดล็อก คุณควรเห็นการแจ้งเตือนบนหน้าจอล็อกเพื่อควบคุมการเล่นสื่อหรือหยุดการแคสต์

กลับไปที่แอปวิดีโอแล้วคลิกปุ่ม "แคสต์" เพื่อหยุดแคสต์ในอุปกรณ์ Google Cast

คำถามที่พบบ่อย

4. เตรียมโปรเจ็กต์เริ่มต้น

ภาพโทรศัพท์ Android ที่ใช้แอป "แคสต์วิดีโอ"

เราต้องเพิ่มการรองรับ Google Cast ไปยังแอปเริ่มต้นที่คุณดาวน์โหลด คำศัพท์เกี่ยวกับ Google Cast บางส่วนที่เราจะใช้ใน Codelab มีดังนี้

  • แอปผู้ส่งที่ทำงานบนอุปกรณ์เคลื่อนที่หรือแล็ปท็อป
  • แอปตัวรับที่ทำงานบนอุปกรณ์ Google Cast

ตอนนี้คุณพร้อมที่จะต่อยอดจากโปรเจ็กต์เริ่มต้นโดยใช้ Android Studio แล้ว โดยทำดังนี้

  1. เลือกไดเรกทอรี ไอคอนโฟลเดอร์app-start จากการดาวน์โหลดโค้ดตัวอย่าง (เลือกนําเข้าโปรเจ็กต์ในหน้าจอต้อนรับหรือตัวเลือกเมนูไฟล์ > ใหม่ > นําเข้าโปรเจ็กต์...)
  2. คลิกปุ่ม ปุ่ม "ซิงค์โปรเจ็กต์กับ Gradle" ของ Android Studio ซิงค์โปรเจ็กต์กับไฟล์ Gradle
  3. คลิกปุ่ม ปุ่มเรียกใช้ของ Android Studio ซึ่งเป็นสามเหลี่ยมสีเขียวชี้ไปทางขวาRun เพื่อเรียกใช้แอปและสำรวจ UI

การออกแบบแอป

แอปจะดึงข้อมูลรายการวิดีโอจากเว็บเซิร์ฟเวอร์ระยะไกลและแสดงรายการให้ผู้ใช้เรียกดู ผู้ใช้สามารถเลือกวิดีโอเพื่อดูรายละเอียดหรือเล่นวิดีโอบนอุปกรณ์เคลื่อนที่ก็ได้

แอปประกอบด้วยกิจกรรมหลัก 2 อย่าง ได้แก่ 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 ทำงานอยู่ ปุ่มแคสต์จะปรากฏที่มุมขวาบนของหน้าจอ

แอปพลิเคชันที่พร้อมใช้งาน Cast จะแสดงปุ่มแคสต์ในกิจกรรมแต่ละรายการ การคลิกปุ่มแคสต์จะแสดงรายการอุปกรณ์แคสต์ที่ผู้ใช้เลือกได้ หากผู้ใช้เล่นเนื้อหาในเครื่องบนอุปกรณ์ผู้ส่ง การเลือกอุปกรณ์แคสต์จะเป็นการเริ่มหรือเล่นต่อบนอุปกรณ์แคสต์นั้น ผู้ใช้สามารถคลิกปุ่มแคสต์และหยุดแคสต์แอปพลิเคชันไปยังอุปกรณ์แคสต์ได้ทุกเมื่อในระหว่างเซสชันแคสต์ ผู้ใช้ต้องสามารถเชื่อมต่อหรือยกเลิกการเชื่อมต่อจากอุปกรณ์ Cast ขณะอยู่ในกิจกรรมใดๆ ของแอปพลิเคชัน ตามที่อธิบายไว้ในรายการตรวจสอบการออกแบบของ Google Cast

การอ้างอิง

อัปเดตไฟล์ build.gradle ของแอปให้รวมทรัพยากร Dependency ของไลบรารีที่จําเป็น

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"
}

ซิงค์โปรเจ็กต์เพื่อยืนยันว่าโปรเจ็กต์สร้างโดยไม่มีข้อผิดพลาด

การเริ่มต้น

เฟรมเวิร์กการแคสต์มีออบเจ็กต์ Singleton สำหรับใช้งานทั่วโลก ซึ่งก็คือ CastContext ซึ่งประสานงานเกี่ยวกับการโต้ตอบกับแคสต์ทั้งหมด

คุณต้องติดตั้งใช้งานอินเทอร์เฟซ OptionsProvider เพื่อระบุ CastOptions ที่จําเป็นสําหรับเริ่มต้น CastContext เดี่ยว ตัวเลือกที่สําคัญที่สุดคือรหัสแอปพลิเคชันผู้รับ ซึ่งใช้กรองผลการค้นหาอุปกรณ์แคสต์และเพื่อเปิดแอปพลิเคชันผู้รับเมื่อเริ่มเซสชันแคสต์

เมื่อพัฒนาแอปที่พร้อมใช้งาน 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 แล้ว เราต้องเพิ่มปุ่ม "แคสต์" เพื่อให้ผู้ใช้เลือกอุปกรณ์แคสต์ได้ ปุ่มแคสต์ติดตั้งใช้งานโดย 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 ด้วยวิธีที่คล้ายกัน

คลิกปุ่ม ปุ่มเรียกใช้ของ Android Studio ซึ่งเป็นสามเหลี่ยมสีเขียวชี้ไปทางขวาRun เพื่อเรียกใช้แอปบนอุปกรณ์เคลื่อนที่ คุณควรเห็นปุ่มแคสต์ในแถบการดำเนินการของแอป และเมื่อคลิกปุ่มดังกล่าว ระบบจะแสดงรายการอุปกรณ์แคสต์ในเครือข่ายภายใน CastContext จะจัดการการตรวจหาอุปกรณ์โดยอัตโนมัติ เลือกอุปกรณ์แคสต์ แล้วแอปตัวรับตัวอย่างจะโหลดในอุปกรณ์แคสต์ คุณสามารถไปยังส่วนต่างๆ ระหว่างกิจกรรมการเรียกดูและกิจกรรมของโปรแกรมเล่นในเครื่องได้ โดยที่สถานะปุ่มแคสต์จะซิงค์กันอยู่เสมอ

เรายังไม่ได้รองรับการเล่นสื่อ คุณจึงเล่นวิดีโอในอุปกรณ์แคสต์ไม่ได้ คลิกปุ่มแคสต์เพื่อยกเลิกการเชื่อมต่อ

6. การแคสต์เนื้อหาวิดีโอ

ภาพประกอบโทรศัพท์ Android ที่ใช้แอป &quot;แคสต์วิดีโอ&quot;

เราจะขยายความสามารถของแอปตัวอย่างให้เล่นวิดีโอจากระยะไกลบนอุปกรณ์ Cast ได้ด้วย ซึ่งเราต้องคอยฟังเหตุการณ์ต่างๆ ที่เฟรมเวิร์ก Cast สร้างขึ้น

การแคสต์สื่อ

ในระดับสูง หากต้องการเล่นสื่อในอุปกรณ์แคสต์ คุณต้องทำสิ่งต่อไปนี้

  1. สร้างออบเจ็กต์ MediaInfo ที่จำลองรายการสื่อ
  2. เชื่อมต่อกับอุปกรณ์แคสต์และเปิดแอปพลิเคชันตัวรับ
  3. โหลดออบเจ็กต์ MediaInfo ลงในเครื่องรับและเล่นเนื้อหา
  4. ติดตามสถานะสื่อ
  5. ส่งคําสั่งการเล่นไปยังอุปกรณ์รับตามการโต้ตอบของผู้ใช้

เราทำขั้นตอนที่ 2 ในส่วนก่อนหน้าไปแล้ว ขั้นตอนที่ 3 ทำได้ง่ายๆ ด้วยเฟรมเวิร์กของ Cast ขั้นตอนที่ 1 คือการแมปออบเจ็กต์หนึ่งกับอีกออบเจ็กต์หนึ่ง โดย MediaInfo คือสิ่งที่เฟรมเวิร์ก Cast เข้าใจ และ MediaItem คือการจัดแพ็กเกจรายการสื่อของแอป เราจึงแมป MediaItem กับ MediaInfo ได้อย่างง่ายดาย

แอปตัวอย่าง LocalPlayerActivity แยกความแตกต่างระหว่างการเล่นแบบภายในกับแบบระยะไกลอยู่แล้วโดยใช้ enum นี้

private var mLocation: PlaybackLocation? = null

enum class PlaybackLocation {
    LOCAL, REMOTE
}

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

ใน Codelab นี้ คุณไม่จำเป็นต้องเข้าใจอย่างถ่องแท้ว่าตรรกะของโปรแกรมเล่นตัวอย่างทั้งหมดทำงานอย่างไร โปรดทราบว่าจะต้องแก้ไขโปรแกรมเล่นสื่อของแอปเพื่อให้รับรู้ตำแหน่งการเล่น 2 ตำแหน่งในลักษณะที่คล้ายกัน

ขณะนี้โปรแกรมเล่นในเครื่องจะอยู่ในสถานะการเล่นในเครื่องเสมอ เนื่องจากยังไม่ทราบข้อมูลเกี่ยวกับสถานะการแคสต์ เราต้องอัปเดต UI ตามการเปลี่ยนสถานะที่จะเกิดขึ้นในเฟรมเวิร์กแคสต์ เช่น หากเริ่มแคสต์ เราต้องหยุดการเล่นในเครื่องและปิดใช้การควบคุมบางอย่าง ในทำนองเดียวกัน หากเราหยุดแคสต์ขณะที่ดำเนินการนี้อยู่ เราจะต้องเปลี่ยนไปเล่นในเครื่อง เราจึงจำเป็นต้องรับฟังเหตุการณ์ต่างๆ ที่เฟรมเวิร์กของ 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 เราต้องการทราบเมื่อเชื่อมต่อหรือยกเลิกการเชื่อมต่อกับอุปกรณ์แคสต์เพื่อให้เปลี่ยนจากหรือไปยังโปรแกรมเล่นในเครื่องได้ โปรดทราบว่าการเชื่อมต่ออาจถูกรบกวนไม่เพียงจากอินสแตนซ์ของแอปพลิเคชันที่ทำงานบนอุปกรณ์เคลื่อนที่เท่านั้น แต่ยังอาจถูกรบกวนจากอินสแตนซ์อื่นของแอปพลิเคชัน (หรือแอปพลิเคชันอื่น) ที่ทำงานบนอุปกรณ์เคลื่อนที่เครื่องอื่นด้วย

คุณเข้าถึงเซสชันที่ใช้งานอยู่ในปัจจุบันได้โดยใช้ SessionManager.getCurrentSession() ระบบจะสร้างและปิดเซสชันโดยอัตโนมัติเพื่อตอบสนองต่อการโต้ตอบของผู้ใช้กับกล่องโต้ตอบแคสต์

เราต้องลงทะเบียนโปรแกรมรับฟังเซสชันและเริ่มต้นตัวแปรบางอย่างที่จะใช้ในกิจกรรม เปลี่ยนวิธีการ 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 ที่รองรับการเล่นสื่อ SDK จะสร้างอินสแตนซ์ของ RemoteMediaClient โดยอัตโนมัติ คุณสามารถเข้าถึงได้โดยการเรียกใช้เมธอด 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))
    ...
}

จากนั้นคลิกปุ่ม ปุ่มเรียกใช้ของ Android Studio ซึ่งเป็นสามเหลี่ยมสีเขียวชี้ไปทางขวาRun เพื่อเรียกใช้แอปบนอุปกรณ์เคลื่อนที่ เชื่อมต่อกับอุปกรณ์แคสต์แล้วเริ่มเล่นวิดีโอ คุณควรเห็นวิดีโอกำลังเล่นอยู่บนเครื่องรับ

7. รีโมตคอนโทรลเลอร์ขนาดเล็ก

รายการตรวจสอบการออกแบบ Cast กําหนดให้แอป Cast ทั้งหมดต้องมีตัวควบคุมขนาดเล็กที่ปรากฏขึ้นเมื่อผู้ใช้ออกจากหน้าเนื้อหาปัจจุบัน ตัวควบคุมขนาดเล็กช่วยให้เข้าถึงได้ทันทีและการช่วยเตือนที่มองเห็นได้สำหรับเซสชันการแคสต์ปัจจุบัน

ภาพส่วนด้านล่างของโทรศัพท์ Android ที่แสดงมินิเพลย์เยอร์ในแอปแคสต์วิดีโอ

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 ซึ่งเป็นสามเหลี่ยมสีเขียวชี้ไปทางขวาRun เพื่อเรียกใช้แอปและแคสต์วิดีโอ เมื่อการเล่นเริ่มขึ้นในเครื่องรับ คุณควรเห็นตัวควบคุมขนาดเล็กปรากฏที่ด้านล่างของกิจกรรมแต่ละรายการ คุณควบคุมการเล่นจากระยะไกลได้โดยใช้รีโมตคอนโทรลขนาดเล็ก หากคุณไปยังส่วนต่างๆ ระหว่างกิจกรรมการเรียกดูและกิจกรรมของโปรแกรมเล่นในเครื่อง สถานะตัวควบคุมมินิควรซิงค์กับสถานะการเล่นสื่อของตัวรับ

8. การแจ้งเตือนและหน้าจอล็อก

รายการตรวจสอบการออกแบบ Google Cast กําหนดให้แอปผู้ส่งต้องใช้การควบคุมสื่อจากการแจ้งเตือนและหน้าจอล็อก

ภาพประกอบโทรศัพท์ Android ที่แสดงตัวควบคุมสื่อในพื้นที่การแจ้งเตือน

Cast SDK มี MediaNotificationService เพื่อช่วยแอปผู้ส่งสร้างตัวควบคุมสื่อสำหรับการแจ้งเตือนและหน้าจอล็อก Gradle จะผสานบริการเข้ากับไฟล์ Manifest ของแอปโดยอัตโนมัติ

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 ซึ่งเป็นสามเหลี่ยมสีเขียวชี้ไปทางขวาเรียกใช้ เพื่อเรียกใช้แอปบนอุปกรณ์เคลื่อนที่ แคสต์วิดีโอและออกจากแอปตัวอย่าง คุณควรได้รับการแจ้งเตือนสำหรับวิดีโอที่เล่นอยู่ในอุปกรณ์รับ ล็อกอุปกรณ์เคลื่อนที่และหน้าจอล็อกควรแสดงตัวควบคุมการเล่นสื่อในอุปกรณ์แคสต์

ภาพโทรศัพท์ Android ที่แสดงการควบคุมสื่อบนหน้าจอล็อก

9. การซ้อนทับช่วงแนะนำ

รายการตรวจสอบการออกแบบ Google Cast กําหนดให้แอปส่งแสดงปุ่มแคสต์ให้ผู้ใช้ปัจจุบันทราบเพื่อให้ผู้ใช้ทราบว่าแอปส่งรองรับการแคสต์แล้ว และช่วยผู้ใช้ที่เพิ่งเริ่มใช้ Google Cast ด้วย

ภาพแสดงการวางซ้อน Cast เบื้องต้นรอบปุ่ม Cast ในแอป Cast Videos บน 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 ซึ่งเป็นสามเหลี่ยมสีเขียวชี้ไปทางขวาRun เพื่อเรียกใช้แอปในอุปกรณ์เคลื่อนที่ และคุณควรเห็นการวางซ้อนข้อมูลเบื้องต้น (ล้างข้อมูลแอปหากการวางซ้อนไม่แสดง)

10. ตัวควบคุมแบบขยาย

รายการตรวจสอบการออกแบบ Google Cast กําหนดให้แอปผู้ส่งต้องมีตัวควบคุมแบบขยายสําหรับสื่อที่แคสต์ ตัวควบคุมที่ขยายเป็นตัวควบคุมขนาดเล็กเวอร์ชันเต็มหน้าจอ

ภาพประกอบวิดีโอที่เล่นบนโทรศัพท์ Android โดยมีตัวควบคุมแบบขยายวางซ้อนอยู่

Cast 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 ซึ่งเป็นสามเหลี่ยมสีเขียวชี้ไปทางขวาRun เพื่อเรียกใช้แอปในอุปกรณ์เคลื่อนที่และแคสต์วิดีโอ คุณจะเห็นตัวควบคุมที่ขยายแล้ว กลับไปที่รายการวิดีโอ และเมื่อคลิกตัวควบคุมขนาดเล็ก ระบบจะโหลดตัวควบคุมแบบขยายอีกครั้ง ออกจากแอปเพื่อดูการแจ้งเตือน คลิกรูปภาพการแจ้งเตือนเพื่อโหลดตัวควบคุมแบบขยาย

11. เพิ่มการรองรับ Cast Connect

คลัง Cast Connect ช่วยให้แอปพลิเคชันผู้ส่งที่มีอยู่สามารถสื่อสารกับแอปพลิเคชัน Android TV ผ่านโปรโตคอล Cast Cast Connect สร้างขึ้นจากโครงสร้างพื้นฐานของ Cast โดยมีแอป Android TV ทำหน้าที่เป็นตัวรับ

การอ้างอิง

หมายเหตุ: หากต้องการใช้ Cast Connect play-services-cast-framework ต้องเป็น 19.0.0 ขึ้นไป

LaunchOptions

หากต้องการเปิดแอปพลิเคชัน Android TV หรือที่เรียกว่าตัวรับ Android เราต้องตั้งค่า Flag setAndroidReceiverCompatible เป็น true ในออบเจ็กต์ LaunchOptions ออบเจ็กต์ LaunchOptions นี้จะกำหนดวิธีเปิดใช้งานตัวรับและส่งไปยัง CastOptions ที่คลาส CastOptionsProvider แสดงผล การตั้งค่า Flag ที่กล่าวถึงข้างต้นเป็น 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

ในกรณีที่แอป Web Receiver และแอป Android TV จัดการ credentials แตกต่างกัน คุณอาจต้องกำหนด credentials แยกกันสำหรับแต่ละแอป หากต้องการแก้ปัญหานี้ ให้เพิ่มโค้ดต่อไปนี้ในไฟล์ LocalPlayerActivity.kt ในส่วนฟังก์ชัน loadRemoteMedia

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

SDK จะจัดการโดยอัตโนมัติว่าจะใช้ข้อมูลเข้าสู่ระบบใดสำหรับเซสชันปัจจุบัน ทั้งนี้ขึ้นอยู่กับแอปตัวรับสัญญาณที่ผู้ส่งกำลังแคสต์ไป

กำลังทดสอบ Cast Connect

ขั้นตอนการติดตั้ง 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. ตอนนี้คุณควรเห็นแอปชื่อ Cast Videos ในเมนูแอปของคุณบนอุปกรณ์ Android TV
  2. กลับไปที่โปรเจ็กต์ Android Studio แล้วคลิกปุ่ม Run เพื่อติดตั้งและเรียกใช้แอปผู้ส่งบนอุปกรณ์เคลื่อนที่จริง ที่มุมขวาบน ให้คลิกไอคอนแคสต์ แล้วเลือกอุปกรณ์ 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 Sender