เปิดใช้แอป 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 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. เรียกใช้แอปตัวอย่าง

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

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

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

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

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

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

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

เสียบอุปกรณ์ Android แล้วคลิกปุ่ม ปุ่ม Run ของ 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 จากการดาวน์โหลดโค้ดตัวอย่าง (เลือก Import Project ในหน้าจอต้อนรับ หรือเลือกตัวเลือกเมนู File > New > Import Project...)
  2. คลิกปุ่ม "ซิงค์โปรเจ็กต์กับ Gradle" ของ Android Studio ปุ่ม ซิงค์โปรเจ็กต์ด้วยไฟล์ Gradle
  3. คลิกปุ่มปุ่ม Run ของ Android Studio รูปสามเหลี่ยมสีเขียวที่ชี้ไปทางขวาเรียกใช้เพื่อเรียกใช้แอปและสำรวจ 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

การอ้างอิง

อัปเดตไฟล์ create.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 ที่จำเป็นในการเริ่มต้น Singleton 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 แบบ Lazy Loading ในเมธอด VideoBrowserActivity onCreate:

import com.google.android.gms.cast.framework.CastContext

private var mCastContext: CastContext? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.video_browser)
    setupActionBar()

    mCastContext = CastContext.getSharedInstance(this)
}

เพิ่มตรรกะการเริ่มต้นเดียวกันใน LocalPlayerActivity

ปุ่ม "แคสต์"

เมื่อเริ่มต้น 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 ไปยังเฟรมเวิร์กของ Cast ดังนี้

import com.google.android.gms.cast.framework.CastButtonFactory

private var mediaRouteMenuItem: MenuItem? = null

override fun onCreateOptionsMenu(menu: Menu): Boolean {
     super.onCreateOptionsMenu(menu)
     menuInflater.inflate(R.menu.browse, menu)
     mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu,
                R.id.media_route_menu_item)
     return true
}

ลบล้าง onCreateOptionsMenu ใน LocalPlayerActivity ด้วยวิธีที่คล้ายกัน

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

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

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

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

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

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

หากคุณต้องการเล่นสื่อบนอุปกรณ์ 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
}

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

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

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

9. การวางซ้อนบทนำ

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

ภาพประกอบแสดงการวางซ้อนการแคสต์แนะนำรอบปุ่ม &quot;แคสต์&quot; ในแอป &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

LaunchOptions

ในการเปิดแอปพลิเคชัน Android TV หรือที่เรียกว่าตัวรับสัญญาณ Android เราต้องตั้งค่า Flag setAndroidReceiverCompatible เป็น "จริง" ในออบเจ็กต์ 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. จากหน้าต่างเทอร์มินัล ให้ไปที่โฟลเดอร์ระดับบนสุดเพื่อดูตัวอย่าง 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