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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ภาพโทรศัพท์ Android ที่กำลังเปิดแอป "แคสต์วิดีโอ"

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

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

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

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

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

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

แอปประกอบด้วยกิจกรรมหลัก 2 อย่าง ได้แก่ VideoBrowserActivity และ LocalPlayerActivity ในการผสานรวมฟังก์ชัน Google Cast นั้น กิจกรรมจะต้องรับค่าจาก AppCompatActivity หรือ FragmentActivity ระดับบนสุด มีข้อจำกัดนี้เนื่องจากเราต้องเพิ่ม MediaRouteButton (มีไว้ให้ในไลบรารีการสนับสนุน MediaRouter) เป็น MediaRouteActionProvider และจะใช้ได้ต่อเมื่อกิจกรรมรับค่ามาจากคลาสที่กล่าวถึงข้างต้น ไลบรารีการสนับสนุนของ MediaRouter ขึ้นอยู่กับไลบรารีการสนับสนุนของ AppCompat ซึ่งมีคลาสที่จำเป็น

VideoBrowserActivity

กิจกรรมนี้มี Fragment (VideoBrowserFragment) รายการนี้สนับสนุนโดย ArrayAdapter (VideoListAdapter) รายการวิดีโอและข้อมูลเมตาที่เกี่ยวข้องจะโฮสต์บนเซิร์ฟเวอร์ระยะไกลเป็นไฟล์ JSON AsyncTaskLoader (VideoItemLoader) ดึงข้อมูล JSON นี้และประมวลผลเพื่อสร้างรายการออบเจ็กต์ MediaItem รายการ

ออบเจ็กต์ MediaItem จำลองวิดีโอและข้อมูลเมตาที่เกี่ยวข้อง เช่น ชื่อ, คำอธิบาย, URL สำหรับสตรีม, URL สำหรับรูปภาพสนับสนุน และแทร็กข้อความที่เกี่ยวข้อง (สำหรับคำบรรยาย) หากมี ระบบจะส่งออบเจ็กต์ MediaItem ระหว่างกิจกรรม ดังนั้น MediaItem จึงมีเมธอดยูทิลิตีเพื่อแปลงเป็น Bundle และในทางกลับกันด้วย

เมื่อตัวโหลดสร้างรายการ MediaItems ระบบจะส่งรายการนั้นไปยัง VideoListAdapter ซึ่งจะแสดงรายการ MediaItems ใน VideoBrowserFragment ระบบจะแสดงรายการภาพขนาดย่อของวิดีโอแก่ผู้ใช้พร้อมคำอธิบายสั้นๆ สำหรับแต่ละวิดีโอ เมื่อเลือกรายการแล้ว MediaItem ที่เกี่ยวข้องจะแปลงเป็น Bundle และส่งไปยัง LocalPlayerActivity

LocalPlayerActivity

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

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

การอ้างอิง

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

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

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

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

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

คุณต้องใช้อินเทอร์เฟซ 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 แบบ Lazy Loading ในเมธอด onCreate ของ VideoBrowserActivity ดังนี้

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

private var mCastContext: CastContext? = null

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

    mCastContext = CastContext.getSharedInstance(this)
}

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

ปุ่ม "แคสต์"

เมื่อเริ่มต้น CastContext แล้ว เราต้องเพิ่มปุ่ม "แคสต์" เพื่ออนุญาตให้ผู้ใช้เลือกอุปกรณ์แคสต์ได้ MediaRouteButton จากไลบรารีการสนับสนุน MediaRouter จะใช้ปุ่ม "แคสต์" ได้ เช่นเดียวกับไอคอนการทำงานใดๆ ที่เพิ่มไปยังกิจกรรมได้ (โดยใช้ ActionBar หรือ Toolbar) คุณต้องเพิ่มรายการในเมนูที่เกี่ยวข้องลงในเมนูก่อน

แก้ไขไฟล์ res/menu/browse.xml แล้วเพิ่มรายการ MediaRouteActionProvider ในเมนูหน้ารายการการตั้งค่า ดังนี้

<item
    android:id="@+id/media_route_menu_item"
    android:title="@string/media_route_menu_title"
    app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
    app:showAsAction="always"/>

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

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

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
}

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

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

การจัดการเซสชันการแคสต์

สำหรับเฟรมเวิร์ก Cast เซสชัน Cast จะรวมขั้นตอนการเชื่อมต่ออุปกรณ์ การเปิด (หรือเข้าร่วม) เชื่อมต่อกับแอปพลิเคชันตัวรับสัญญาณ และการเริ่มต้นช่องควบคุมสื่อตามความเหมาะสม ช่องควบคุมสื่อคือวิธีที่เฟรมเวิร์ก Cast ส่งและรับข้อความจากโปรแกรมเล่นสื่อของเครื่องรับ

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

มาเพิ่ม SessionManagerListener ไปยัง LocalPlayerActivity กัน

import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
...

private var mSessionManagerListener: SessionManagerListener<CastSession>? = null
private var mCastSession: CastSession? = null
...

private fun setupCastListener() {
    mSessionManagerListener = object : SessionManagerListener<CastSession> {
        override fun onSessionEnded(session: CastSession, error: Int) {
            onApplicationDisconnected()
        }

        override fun onSessionResumed(session: CastSession, wasSuspended: Boolean) {
            onApplicationConnected(session)
        }

        override fun onSessionResumeFailed(session: CastSession, error: Int) {
            onApplicationDisconnected()
        }

        override fun onSessionStarted(session: CastSession, sessionId: String) {
            onApplicationConnected(session)
        }

        override fun onSessionStartFailed(session: CastSession, error: Int) {
            onApplicationDisconnected()
        }

        override fun onSessionStarting(session: CastSession) {}
        override fun onSessionEnding(session: CastSession) {}
        override fun onSessionResuming(session: CastSession, sessionId: String) {}
        override fun onSessionSuspended(session: CastSession, reason: Int) {}
        private fun onApplicationConnected(castSession: CastSession) {
            mCastSession = castSession
            if (null != mSelectedMedia) {
                if (mPlaybackState == PlaybackState.PLAYING) {
                    mVideoView!!.pause()
                    loadRemoteMedia(mSeekbar!!.progress, true)
                    return
                } else {
                    mPlaybackState = PlaybackState.IDLE
                    updatePlaybackLocation(PlaybackLocation.REMOTE)
                }
            }
            updatePlayButton(mPlaybackState)
            invalidateOptionsMenu()
        }

        private fun onApplicationDisconnected() {
            updatePlaybackLocation(PlaybackLocation.LOCAL)
            mPlaybackState = PlaybackState.IDLE
            mLocation = PlaybackLocation.LOCAL
            updatePlayButton(mPlaybackState)
            invalidateOptionsMenu()
       }
   }
}

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

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

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

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

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

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

ภาพแสดงการวางซ้อน &quot;แคสต์&quot; เบื้องต้นรอบปุ่ม &quot;แคสต์&quot; ในแอปแคสต์วิดีโอ Android

SDK ของ Cast มีมุมมองที่กำหนดเอง 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 ทำหน้าที่เป็นตัวรับสัญญาณ

การอ้างอิง

หมายเหตุ: play-services-cast-framework ในการใช้ Cast Connect จะต้องไม่ต่ำกว่า 19.0.0

LaunchOptions

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