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

1. ภาพรวม

โลโก้ Google Cast

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

Google Cast คืออะไร

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

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

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

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

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

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

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

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

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

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

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

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

อ่านอย่างเดียว อ่านแบบฝึกหัดจนจบ

คุณจะให้คะแนนประสบการณ์ในการสร้างแอป Android มากน้อยเพียงใด

มือใหม่ ขั้นกลาง เชี่ยวชาญ

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

ผู้ฝึกหัด ขั้นกลาง ผู้ชํานาญ

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

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

และคลายไฟล์ ZIP ที่ดาวน์โหลด

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

ไอคอนเข็มทิศคู่หนึ่ง

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

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

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

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

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

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

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

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

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

การเริ่มต้น

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

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

ขณะพัฒนาแอปที่พร้อมใช้งาน Cast ของคุณเอง คุณจะต้องลงทะเบียนเป็นนักพัฒนา 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 แบบ Lazy Loading ดังนี้

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 ด้วยวิธีที่คล้ายกัน

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

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

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

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

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

กําลังแคสต์สื่อ

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

  1. สร้างออบเจ็กต์ MediaInfo ที่สร้างแบบจําลองรายการสื่อ
  2. เชื่อมต่ออุปกรณ์ Cast และเปิดแอปพลิเคชันตัวรับสัญญาณ
  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
}

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

เข้าถึงเซสชันที่ใช้งานอยู่เป็น 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 ที่รองรับการเล่นสื่อ 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()
    }
}

อัปเดตเมธอดต่างๆ ที่มีอยู่เพื่อใช้ตรรกะเซสชันแคสต์เพื่อรองรับการเล่นระยะไกล ดังนี้

private fun play(position: Int) {
    startControllersTimer()
    when (mLocation) {
        PlaybackLocation.LOCAL -> {
            mVideoView!!.seekTo(position)
            mVideoView!!.start()
        }
        PlaybackLocation.REMOTE -> {
            mPlaybackState = PlaybackState.BUFFERING
            updatePlayButton(mPlaybackState)
            //seek to a new position within the current media item's new position 
            //which is in milliseconds from the beginning of the stream
            mCastSession!!.remoteMediaClient?.seek(position.toLong())
        }
        else -> {}
    }
    restartTrickplayTimer()
}
private fun togglePlayback() {
    ...
    PlaybackState.IDLE -> when (mLocation) {
        ...
        PlaybackLocation.REMOTE -> {
            if (mCastSession != null && mCastSession!!.isConnected) {
                loadRemoteMedia(mSeekbar!!.progress, true)
            }
        }
        else -> {}
    }
    ...
}
override fun onPause() {
    ...
    mCastContext!!.sessionManager.removeSessionManagerListener(
                mSessionManagerListener!!, CastSession::class.java)
}
override fun onResume() {
    Log.d(TAG, "onResume() was called")
    mCastContext!!.sessionManager.addSessionManagerListener(
            mSessionManagerListener!!, CastSession::class.java)
    if (mCastSession != null && mCastSession!!.isConnected) {
        updatePlaybackLocation(PlaybackLocation.REMOTE)
    } else {
        updatePlaybackLocation(PlaybackLocation.LOCAL)
    }
    super.onResume()
}

สําหรับเมธอด updatePlayButton ให้เปลี่ยนค่าของตัวแปร isConnected ดังนี้

private fun updatePlayButton(state: PlaybackState?) {
    ...
    val isConnected = (mCastSession != null
                && (mCastSession!!.isConnected || mCastSession!!.isConnecting))
    ...
}

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

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

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

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

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

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

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

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

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

แก้ไข CastOptionsProvider และเปลี่ยนแปลงการใช้งาน getCastOptions เพื่อให้ตรงกับโค้ดนี้

import com.google.android.gms.cast.framework.media.CastMediaOptions
import com.google.android.gms.cast.framework.media.NotificationOptions

override fun getCastOptions(context: Context): CastOptions {
   val notificationOptions = NotificationOptions.Builder()
            .setTargetActivityClassName(VideoBrowserActivity::class.java.name)
            .build()
    val mediaOptions = CastMediaOptions.Builder()
            .setNotificationOptions(notificationOptions)
            .build()
   return CastOptions.Builder()
                .setReceiverApplicationId(context.getString(R.string.app_id))
                .setCastMediaOptions(mediaOptions)
                .build()
}

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

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

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

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

ภาพแสดงการวางซ้อนการแคสต์ที่แนะนํารอบปุ่ม &quot;แคสต์&quot; ในแอปแคสต์วิดีโอ 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!!)
}

ล้างข้อมูลแอปหรือนําแอปออกจากอุปกรณ์ จากนั้นคลิกปุ่ม ปุ่ม Run ของ 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())
}

คลิกปุ่มปุ่ม Run ของ 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 Receiver เราจําเป็นต้องตั้งค่าสถานะของ setAndroidReceiverCompatible เป็น true ในออบเจ็กต์ LaunchOptions ออบเจ็กต์ LaunchOptions นี้กําหนดวิธีเปิดใช้ตัวรับและส่งต่อไปยัง CastOptions ที่คลาส CastOptionsProvider แสดงผล การตั้งค่าแฟล็กที่กล่าวไว้ด้านบนเป็น false จะเปิดรีซีฟเวอร์ของเว็บสําหรับรหัสแอปที่กําหนดไว้ใน Developer Console ของ Cast

ในไฟล์ CastOptionsProvider.kt ให้เพิ่มค่าต่อไปนี้ลงในเมธอด getCastOptions

import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
            .setAndroidReceiverCompatible(true)
            .build()
return new CastOptions.Builder()
        .setLaunchOptions(launchOptions)
        ...
        .build()

ตั้งค่าข้อมูลรับรองการเปิด

ทางด้านผู้ส่ง คุณสามารถระบุ CredentialsData เพื่อเป็นตัวแทนผู้เข้าร่วมเซสชัน credentials คือสตริงที่ผู้ใช้กําหนดได้ ตราบใดที่แอป ATV เข้าใจได้ ระบบจะส่ง CredentialsData ไปยังแอป Android TV ของคุณระหว่างเวลาเริ่มหรือเข้าร่วมเท่านั้น หากคุณตั้งค่าอีกครั้งขณะเชื่อมต่อ ระบบจะไม่ส่งแอป Android TV ของคุณไปให้

หากต้องการตั้งค่าข้อมูลรับรองการเปิดตัว 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