เปิดใช้แอป Cast บน Android

1. ภาพรวม

โลโก้ Google Cast

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

Google Cast คืออะไร

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

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

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

สิ่งที่เรากําลังสร้าง

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

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

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

สิ่งที่ต้องมี

  • Android SDK เวอร์ชันล่าสุด
  • Android Studio เวอร์ชัน 3.2 ขึ้นไป
  • อุปกรณ์เคลื่อนที่เครื่องหนึ่งที่ใช้ 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 จากโฟลเดอร์โค้ดตัวอย่าง แล้วคลิก "ตกลง"

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

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

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

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

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

แอปประกอบด้วยกิจกรรมหลัก 2 อย่าง ได้แก่ 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

กิจกรรมโปรแกรมเล่นในพื้นที่

กิจกรรมนี้แสดงข้อมูลเมตาเกี่ยวกับวิดีโอที่เฉพาะเจาะจงและอนุญาตให้ผู้ใช้เล่นวิดีโอในเครื่องได้

กิจกรรมนี้จะมีVideoView ตัวควบคุมสื่อบางรายการ และพื้นที่ข้อความสําหรับแสดงคําอธิบายวิดีโอที่เลือก โปรแกรมเล่นครอบคลุมพื้นที่ด้านบนของหน้าจอ รวมถึงคําอธิบายวิดีโอด้านล่าง ผู้ใช้สามารถเล่น/หยุดชั่วคราวหรือค้นหาการเล่นวิดีโอในเครื่องได้

การอ้างอิง

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

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

5. การเพิ่มปุ่ม "แคสต์"

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

แอปพลิเคชันที่พร้อมใช้งาน 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 ซึ่งจะประสานการโต้ตอบกับ Cast ทั้งหมด

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

เมื่อคุณพัฒนาแอปที่พร้อมใช้งาน Cast ของคุณเอง คุณจะต้องลงทะเบียนเป็นนักพัฒนาซอฟต์แวร์การแคสต์ แล้วรับรหัสแอปพลิเคชันสําหรับแอปของคุณ สําหรับ Codelab นี้ เราจะใช้รหัสแอปตัวอย่าง

เพิ่มไฟล์ 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 ในเมธอด VideoBrowserActivityCreate on

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

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

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

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

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

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

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

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

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

เราจําเป็นต้องลงทะเบียน Listener เซสชันและเริ่มต้นตัวแปรบางตัวซึ่งเราจะใช้ในกิจกรรม เปลี่ยนวิธี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))
    ...
}

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

7. ตัวควบคุมขนาดเล็ก

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

ภาพส่วนล่างของโทรศัพท์ 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"/>

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

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

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

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

Cast SDK มี MediaNotificationService เพื่อช่วยให้แอปผู้ส่งสร้างตัวควบคุมสื่อสําหรับการแจ้งเตือนและหน้าจอล็อก บริการจะผสานเข้ากับไฟล์ 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()
}

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

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

9. การวางซ้อนที่แนะนํา

รายการตรวจสอบการออกแบบของ Google Cast กําหนดให้แอปผู้ส่งต้องแนะนําปุ่ม "แคสต์" ให้กับผู้ใช้ที่มีอยู่เพื่อแจ้งให้ทราบว่าแอปของผู้ส่งรองรับการแคสต์และยังช่วยให้ผู้ใช้เพิ่งเริ่มใช้ Google 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 เมื่ออุปกรณ์แคสต์พร้อมใช้งาน โดยแก้ไขเมธอด 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; ของ Android Studio รูปสามเหลี่ยมสีเขียวชี้ไปทางขวาเรียกใช้เพื่อเรียกใช้แอปบนอุปกรณ์เคลื่อนที่ และคุณควรเห็นการวางซ้อนบทนํา (ล้างข้อมูลแอปหากการวางซ้อนไม่แสดง)

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

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

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 เป็น "จริง" ในออบเจ็กต์ LaunchOptions ออบเจ็กต์ LaunchOptions นี้จะกําหนดวิธีเปิดใช้ผู้รับและส่งต่อไปยัง CastOptions ที่คลาส CastOptionsProvider แสดงผล การตั้งค่าแฟล็กที่กล่าวถึงข้างต้นเป็น false จะเปิดตัวรับเว็บสําหรับรหัสแอปที่กําหนดไว้ใน Play 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. จากหน้าต่างเทอร์มินัล ให้ไปที่โฟลเดอร์ระดับบนสุดสําหรับตัวอย่าง 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 Sender