1. ภาพรวม
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
เปิดใช้การแก้ไขข้อบกพร่อง USB บนอุปกรณ์ Android ใน Android 4.2 และเวอร์ชันที่สูงกว่า หน้าจอ "ตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์" จะถูกซ่อนไว้โดยค่าเริ่มต้น หากต้องการให้แสดงตัว ให้ไปที่การตั้งค่า > เกี่ยวกับโทรศัพท์ แล้วแตะหมายเลขบิลด์ 7 ครั้ง กลับไปที่หน้าจอก่อนหน้า ไปที่ระบบ > ขั้นสูง แล้วแตะตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์บริเวณด้านล่าง จากนั้นแตะการแก้ไขข้อบกพร่องผ่าน USB เพื่อเปิด
เสียบอุปกรณ์ Android แล้วคลิกปุ่มเรียกใช้ใน Android Studio คุณควรเห็นแอปวิดีโอชื่อแคสต์วิดีโอปรากฏขึ้นหลังจากผ่านไป 2-3 วินาที
คลิกปุ่ม "แคสต์" ในแอปวิดีโอ แล้วเลือกอุปกรณ์ Google Cast ของคุณ
เลือกวิดีโอแล้วคลิกปุ่มเล่น
วิดีโอจะเริ่มเล่นบนอุปกรณ์ Google Cast
ตัวควบคุมที่ขยายจะปรากฏขึ้น คุณใช้ปุ่มเล่น/หยุดชั่วคราวเพื่อควบคุมการเล่นได้
กลับไปที่รายการวิดีโอ
ตอนนี้ตัวควบคุมขนาดเล็กจะปรากฏที่ด้านล่างของหน้าจอ
คลิกปุ่มหยุดชั่วคราวในมินิคอนโทรลเลอร์เพื่อหยุดวิดีโอชั่วคราวบนอุปกรณ์รับสัญญาณ คลิกปุ่มเล่นในตัวควบคุมขนาดเล็กเพื่อเล่นวิดีโอต่ออีกครั้ง
คลิกปุ่มหน้าแรกของอุปกรณ์เคลื่อนที่ ดึงการแจ้งเตือนลง แล้วคุณจะเห็นการแจ้งเตือนสำหรับเซสชัน Cast
ล็อกโทรศัพท์และเมื่อปลดล็อก คุณจะเห็นการแจ้งเตือนในหน้าจอล็อกเพื่อควบคุมการเล่นสื่อหรือหยุดแคสต์
กลับไปที่แอปวิดีโอและคลิกปุ่ม "แคสต์" เพื่อหยุดแคสต์ในอุปกรณ์ Google Cast
คำถามที่พบบ่อย
4. เตรียมการเริ่มโปรเจ็กต์
เราต้องเพิ่มการรองรับ Google Cast ให้กับแอปเริ่มต้นที่คุณดาวน์โหลดมา ต่อไปนี้คือคำศัพท์ของ Google Cast ที่เราจะใช้ใน Codelab
- แอปของผู้ส่งทำงานบนอุปกรณ์เคลื่อนที่หรือแล็ปท็อป
- แอปตัวรับจะทำงานในอุปกรณ์ Google Cast
ตอนนี้คุณพร้อมที่จะสร้างโครงการเริ่มต้นเพิ่มเติมโดยใช้ Android Studio แล้ว วิธีการมีดังนี้
- เลือกไดเรกทอรี
app-start
จากการดาวน์โหลดโค้ดตัวอย่าง (เลือกนำเข้าโปรเจ็กต์บนหน้าจอต้อนรับ หรือตัวเลือกเมนูไฟล์ > ใหม่ > นำเข้าโปรเจ็กต์...) - คลิกปุ่ม ซิงค์โปรเจ็กต์ด้วยไฟล์ Gradle
- คลิกปุ่ม 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. การเพิ่มปุ่ม "แคสต์"
แอปพลิเคชันที่พร้อมใช้งาน 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
ด้วยวิธีที่คล้ายกัน
คลิกปุ่มเรียกใช้เพื่อเรียกใช้แอปบนอุปกรณ์เคลื่อนที่ คุณจะเห็นปุ่ม "แคสต์" ในแถบการทำงานของแอป และเมื่อคลิกที่ปุ่มดังกล่าว ปุ่ม "แคสต์" จะแสดงอุปกรณ์แคสต์ในเครือข่ายภายในของคุณ CastContext
จะเป็นผู้จัดการการค้นพบอุปกรณ์โดยอัตโนมัติ เลือกอุปกรณ์แคสต์ แล้วแอปตัวรับตัวอย่างจะโหลดในอุปกรณ์แคสต์ คุณจะสลับไปมาระหว่างกิจกรรมการท่องเว็บกับกิจกรรมของโปรแกรมเล่นในเครื่องได้ และสถานะของปุ่ม "แคสต์" จะซิงค์กันอยู่เสมอ
เรายังไม่ได้ให้การสนับสนุนการเล่นสื่อ คุณจึงยังไม่สามารถเล่นวิดีโอบนอุปกรณ์แคสต์ได้ คลิกปุ่ม "แคสต์" เพื่อยกเลิกการเชื่อมต่อ
6. กำลังแคสต์เนื้อหาวิดีโอ
เราจะขยายตัวอย่างแอปให้เล่นวิดีโอจากระยะไกลบนอุปกรณ์แคสต์ด้วย ในการทำเช่นนั้น เราต้องรับฟังเหตุการณ์ต่างๆ ที่สร้างขึ้นโดยเฟรมเวิร์กของ Cast
กำลังแคสต์สื่อ
หากต้องการเล่นสื่อในอุปกรณ์แคสต์ในระดับสูง คุณต้องทำดังนี้
- สร้างออบเจ็กต์
MediaInfo
ที่จำลองรายการสื่อ - เชื่อมต่อกับอุปกรณ์ Cast และเปิดแอปพลิเคชันเครื่องรับ
- โหลดออบเจ็กต์
MediaInfo
ลงในตัวรับและเล่นเนื้อหา - ติดตามสถานะสื่อ
- ส่งคำสั่งการเล่นไปยังเครื่องรับตามการโต้ตอบของผู้ใช้
เราทําตามขั้นตอนที่ 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))
...
}
จากนั้นคลิกปุ่มเรียกใช้เพื่อเรียกใช้แอปบนอุปกรณ์เคลื่อนที่ เชื่อมต่ออุปกรณ์ Cast และเริ่มเล่นวิดีโอ คุณควรเห็นวิดีโอเล่นบนตัวรับสัญญาณ
7. มินิคอนโทรล
รายการตรวจสอบการออกแบบของ Cast กำหนดให้แอป Cast ทั้งหมดต้องมีตัวควบคุมขนาดเล็กซึ่งจะปรากฏเมื่อผู้ใช้ออกจากหน้าเนื้อหาปัจจุบัน มินิคอนโทรลเลอร์ทำให้เข้าถึงได้ทันทีและการช่วยเตือนที่มองเห็นได้สำหรับเซสชันการแคสต์ปัจจุบัน
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"/>
คลิกปุ่มเรียกใช้เพื่อเรียกใช้แอปและแคสต์วิดีโอ เมื่อเริ่มเล่นบนอุปกรณ์รับสัญญาณ คุณจะเห็นมินิคอนโทรลเลอร์ปรากฏที่ด้านล่างของแต่ละกิจกรรม คุณควบคุมการเล่นจากระยะไกลได้โดยใช้ตัวควบคุมขนาดเล็ก หากคุณสลับไปมาระหว่างกิจกรรมการท่องเว็บและกิจกรรมโปรแกรมเล่นในเครื่อง สถานะตัวควบคุมขนาดเล็กควรซิงค์กับสถานะการเล่นสื่อของผู้รับ
8. การแจ้งเตือนและหน้าจอล็อก
รายการตรวจสอบการออกแบบของ Google Cast กำหนดให้แอปของผู้ส่งใช้การควบคุมสื่อจากการแจ้งเตือนและหน้าจอล็อก
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()
}
คลิกปุ่มเรียกใช้เพื่อเรียกใช้แอปบนอุปกรณ์เคลื่อนที่ แคสต์วิดีโอและออกจากแอปตัวอย่าง ควรมีการแจ้งเตือนสำหรับวิดีโอที่กำลังเล่นอยู่บนเครื่องรับ ล็อกอุปกรณ์เคลื่อนที่และหน้าจอล็อกจะแสดงตัวควบคุมการเล่นสื่อในอุปกรณ์แคสต์
9. การวางซ้อนแนะนํา
รายการตรวจสอบการออกแบบของ Google Cast กำหนดให้แอปของผู้ส่งแนะนำปุ่ม "แคสต์" แก่ผู้ใช้เดิมเพื่อแจ้งให้ทราบว่าแอปผู้ส่งรองรับการแคสต์แล้ว และยังช่วยให้ผู้ใช้ที่เพิ่งเคยใช้ Google Cast อีกด้วย
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!!)
}
ล้างข้อมูลแอปหรือนำแอปออกจากอุปกรณ์ จากนั้นคลิกปุ่มเรียกใช้เพื่อเรียกใช้แอปบนอุปกรณ์เคลื่อนที่ แล้วคุณควรเห็นโฆษณาซ้อนทับแนะนำ (ล้างข้อมูลแอปหากโฆษณาซ้อนทับไม่แสดง)
10. ตัวควบคุมที่ขยาย
รายการตรวจสอบการออกแบบของ Google Cast กำหนดให้แอปของผู้ส่งต้องมีตัวควบคุมแบบขยายสำหรับสื่อที่กำลังแคสต์ ตัวควบคุมที่ขยายคือเวอร์ชันเต็มหน้าจอของมินิคอนโทรลเลอร์
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())
}
คลิกปุ่มเรียกใช้เพื่อเรียกใช้แอปบนอุปกรณ์เคลื่อนที่และแคสต์วิดีโอ คุณจะเห็นตัวควบคุมที่ขยายแล้ว กลับไปที่รายการวิดีโอและเมื่อคลิกตัวควบคุมขนาดเล็ก ตัวควบคุมที่ขยายจะโหลดขึ้นอีกครั้ง ออกจากแอปเพื่อดูการแจ้งเตือน คลิกที่รูปภาพการแจ้งเตือนเพื่อโหลดตัวควบคุมที่ขยาย
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
- ค้นหาที่อยู่ IP ของอุปกรณ์ Android TV ซึ่งโดยปกติจะอยู่ในการตั้งค่า > เครือข่ายและอินเทอร์เน็ต > (ชื่อเครือข่ายที่อุปกรณ์เชื่อมต่ออยู่) ทางด้านขวาจะแสดงรายละเอียดและ IP ของอุปกรณ์ในเครือข่าย
- ใช้ที่อยู่ IP ของอุปกรณ์เพื่อเชื่อมต่อผ่าน ADB โดยใช้เทอร์มินัล โดยทำดังนี้
$ adb connect <device_ip_address>:5555
- จากหน้าต่างเทอร์มินัล ไปที่โฟลเดอร์ระดับบนสุดของตัวอย่าง Codelab ที่คุณดาวน์โหลดเมื่อเริ่มต้น Codelab นี้ เช่น
$ cd Desktop/android_codelab_src
- ติดตั้งไฟล์ .apk ในโฟลเดอร์นี้ไปยัง Android TV โดยเรียกใช้
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- ตอนนี้คุณควรเห็นแอปตามชื่อแคสต์วิดีโอในเมนูแอปของคุณบนอุปกรณ์ Android TV แล้ว
- กลับไปที่โปรเจ็กต์ 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