Google Assistant ช่วยให้คุณใช้คำสั่งเสียงเพื่อควบคุมอุปกรณ์ต่างๆ ได้มากมาย เช่น Google Home, โทรศัพท์ และอื่นๆ โดยมีความสามารถในตัวที่จะ เข้าใจคำสั่งสื่อ ("เปิดเพลงของบียอนเซ่หน่อย") และรองรับ การควบคุมสื่อ (เช่น หยุดชั่วคราว ข้าม กรอกลับ กดชอบ)
Assistant สื่อสารกับแอปสื่อของ Android โดยใช้เซสชัน สื่อ โดยสามารถใช้ Intent หรือบริการเพื่อ เปิดแอปและเริ่มเล่น แอปของคุณควรใช้ฟีเจอร์ทั้งหมดที่อธิบายไว้ในหน้านี้เพื่อให้ได้ผลลัพธ์ที่ดีที่สุด
ใช้เซสชันสื่อ
แอปเสียงและวิดีโอทุกแอปต้องใช้เซสชันสื่อ เพื่อให้ Assistant สามารถควบคุม การควบคุมการขนส่งเมื่อการเล่นเริ่มขึ้น
โปรดทราบว่าแม้ว่า Assistant จะใช้เฉพาะการดำเนินการที่ระบุไว้ในส่วนนี้ แต่แนวทางปฏิบัติแนะนำคือการใช้ API การเตรียมและการเล่นทั้งหมดเพื่อให้มั่นใจว่าแอปพลิเคชันจะเข้ากันได้กับแอปพลิเคชันอื่นๆ สำหรับการดำเนินการใดๆ ที่คุณไม่รองรับ
การเรียกกลับของเซสชันสื่อสามารถแสดงข้อผิดพลาดได้โดยใช้
ERROR_CODE_NOT_SUPPORTED
เปิดใช้ตัวควบคุมสื่อและการขนส่งโดยการตั้งค่าสถานะต่อไปนี้ในออบเจ็กต์ MediaSession ของแอป
Kotlin
session.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS )
Java
session.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
เซสชันสื่อของแอปต้องประกาศการดำเนินการที่รองรับ และใช้
การเรียกกลับของเซสชันสื่อที่เกี่ยวข้อง ประกาศการดำเนินการที่รองรับใน
setActions()
โปรเจ็กต์ตัวอย่าง Universal Android Music Player เป็นตัวอย่างที่ดีของวิธีตั้งค่าเซสชันสื่อ
การดำเนินการในการเล่น
หากต้องการเริ่มเล่นจากบริการ เซสชันสื่อต้องมีPLAYการดำเนินการเหล่านี้และฟังก์ชันเรียกกลับ
| การทำงาน | ติดต่อกลับ |
|---|---|
ACTION_PLAY |
onPlay() |
ACTION_PLAY_FROM_SEARCH |
onPlayFromSearch() |
ACTION_PLAY_FROM_URI (*) |
onPlayFromUri() |
เซสชันควรใช้PREPAREการดำเนินการเหล่านี้และฟังก์ชันเรียกกลับที่เกี่ยวข้องด้วย
| การทำงาน | ติดต่อกลับ |
|---|---|
ACTION_PREPARE |
onPrepare() |
ACTION_PREPARE_FROM_SEARCH |
onPrepareFromSearch() |
ACTION_PREPARE_FROM_URI (*) |
onPrepareFromUri() |
(*) การดำเนินการตาม URI ของ Google Assistant จะใช้ได้เฉพาะกับบริษัท ที่ระบุ URI ให้กับ Google ดูข้อมูลเพิ่มเติมเกี่ยวกับการอธิบายเนื้อหาสื่อให้ Google ทราบได้ที่การใช้สื่อ
การใช้ API การเตรียมข้อมูลจะช่วยลดเวลาในการตอบสนองของการเล่นหลังจากคำสั่งเสียง ได้ แอปสื่อที่ต้องการปรับปรุงเวลาในการตอบสนองของการเล่นสามารถใช้ เวลาเพิ่มเติมเพื่อเริ่มแคชเนื้อหาและเตรียมการเล่นสื่อ
แยกวิเคราะห์คำค้นหา
เมื่อผู้ใช้ค้นหารายการสื่อที่เฉพาะเจาะจง เช่น "เปิดเพลงแจ๊สใน [ชื่อแอปของคุณ]" หรือ "ฟังเพลง [ชื่อเพลง]" เมธอดเรียกกลับ
onPrepareFromSearch() หรือ
onPlayFromSearch()
จะได้รับพารามิเตอร์การค้นหาและชุดข้อมูลเพิ่มเติม
แอปของคุณควรแยกวิเคราะห์คำค้นหาด้วยเสียงและเริ่มเล่นโดยทำตามขั้นตอนต่อไปนี้
- ใช้ชุดข้อมูลเพิ่มเติมและสตริงคำค้นหาที่ได้จากการค้นหาด้วยเสียง เพื่อกรองผลการค้นหา
- สร้างคิวการเล่นตามผลการค้นหาเหล่านี้
- เล่นรายการสื่อที่เกี่ยวข้องมากที่สุดจากผลการค้นหา
เมธอด onPlayFromSearch()
จะใช้พารามิเตอร์ส่วนเสริมที่มีข้อมูลโดยละเอียดเพิ่มเติมจากการค้นหาด้วยเสียง
ซึ่งจะช่วยให้คุณค้นหาเนื้อหาเสียงในแอปเพื่อเล่นได้
หากผลการค้นหาไม่สามารถให้ข้อมูลนี้ได้ คุณสามารถใช้ตรรกะ
เพื่อแยกวิเคราะห์คำค้นหาดิบและเล่นแทร็กที่เหมาะสมตามคำค้นหา
ได้
Android Automotive OS และ Android Auto รองรับฟีเจอร์เพิ่มเติมต่อไปนี้
ข้อมูลโค้ดต่อไปนี้แสดงวิธีแทนที่เมธอด onPlayFromSearch()
ในส่วนการติดตั้งใช้งาน MediaSession.Callback
เพื่อแยกวิเคราะห์คำค้นหาด้วยเสียงและเริ่มเล่น
Kotlin
override fun onPlayFromSearch(query: String?, extras: Bundle?) { if (query.isNullOrEmpty()) { // The user provided generic string e.g. 'Play music' // Build appropriate playlist queue } else { // Build a queue based on songs that match "query" or "extras" param val mediaFocus: String? = extras?.getString(MediaStore.EXTRA_MEDIA_FOCUS) if (mediaFocus == MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE) { isArtistFocus = true artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST) } else if (mediaFocus == MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE) { isAlbumFocus = true album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM) } // Implement additional "extras" param filtering } // Implement your logic to retrieve the queue var result: String? = when { isArtistFocus -> artist?.also { searchMusicByArtist(it) } isAlbumFocus -> album?.also { searchMusicByAlbum(it) } else -> null } result = result ?: run { // No focus found, search by query for song title query?.also { searchMusicBySongTitle(it) } } if (result?.isNotEmpty() == true) { // Immediately start playing from the beginning of the search results // Implement your logic to start playing music playMusic(result) } else { // Handle no queue found. Stop playing if the app // is currently playing a song } }
Java
@Override public void onPlayFromSearch(String query, Bundle extras) { if (TextUtils.isEmpty(query)) { // The user provided generic string e.g. 'Play music' // Build appropriate playlist queue } else { // Build a queue based on songs that match "query" or "extras" param String mediaFocus = extras.getString(MediaStore.EXTRA_MEDIA_FOCUS); if (TextUtils.equals(mediaFocus, MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE)) { isArtistFocus = true; artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST); } else if (TextUtils.equals(mediaFocus, MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE)) { isAlbumFocus = true; album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM); } // Implement additional "extras" param filtering } // Implement your logic to retrieve the queue if (isArtistFocus) { result = searchMusicByArtist(artist); } else if (isAlbumFocus) { result = searchMusicByAlbum(album); } if (result == null) { // No focus found, search by query for song title result = searchMusicBySongTitle(query); } if (result != null && !result.isEmpty()) { // Immediately start playing from the beginning of the search results // Implement your logic to start playing music playMusic(result); } else { // Handle no queue found. Stop playing if the app // is currently playing a song } }
ดูตัวอย่างโดยละเอียดเพิ่มเติมเกี่ยวกับวิธีใช้การค้นหาด้วยเสียงเพื่อเล่นเนื้อหาเสียงในแอปได้ที่ตัวอย่าง Universal Android Music Player
จัดการการค้นหาที่ว่างเปล่า
หากมีการเรียกใช้ onPrepare(), onPlay(), onPrepareFromSearch() หรือ onPlayFromSearch()
โดยไม่มีคำค้นหา แอปสื่อควรเล่นสื่อ "ปัจจุบัน"
หากไม่มีสื่อที่กำลังเล่นอยู่ แอปควรพยายามเล่นอะไรบางอย่าง เช่น
เพลงจากเพลย์ลิสต์ล่าสุดหรือคิวแบบสุ่ม ผู้ช่วยจะใช้ API เหล่านี้เมื่อผู้ใช้ขอให้"เปิดเพลงใน [ชื่อแอปของคุณ]" โดยไม่มีข้อมูลเพิ่มเติม
เมื่อผู้ใช้พูดว่า "เปิดเพลงใน [ชื่อแอปของคุณ]", Android Automotive OS หรือ
Android Auto จะพยายามเปิดแอปและเล่นเสียงโดยเรียกใช้เมธอด onPlayFromSearch()
ของแอป อย่างไรก็ตาม เนื่องจากผู้ใช้ไม่ได้พูดชื่อรายการสื่อ เมธอด onPlayFromSearch()
จึงได้รับพารามิเตอร์การค้นหาที่ว่างเปล่า ในกรณีเช่นนี้ แอปควร
ตอบสนองด้วยการเล่นเสียงทันที เช่น เพลงจากเพลย์ลิสต์ล่าสุด
หรือคิวแบบสุ่ม
ประกาศการรองรับการสั่งงานด้วยเสียงเวอร์ชันเดิม
ในกรณีส่วนใหญ่ การจัดการการดำเนินการเล่นที่อธิบายไว้ข้างต้นจะทำให้แอปมีฟังก์ชันการทำงานของการเล่นทั้งหมดที่จำเป็น อย่างไรก็ตาม บางระบบกำหนดให้แอปของคุณต้อง มีตัวกรอง Intent สำหรับการค้นหา คุณควรประกาศการรองรับ Intent filter นี้ในไฟล์ Manifest ของแอป
ใส่โค้ดนี้ในไฟล์ Manifest สำหรับแอปโทรศัพท์
<activity>
<intent-filter>
<action android:name=
"android.media.action.MEDIA_PLAY_FROM_SEARCH" />
<category android:name=
"android.intent.category.DEFAULT" />
</intent-filter>
</activity>
การควบคุมการนำส่ง
หลังจากเซสชันสื่อของแอปทำงานแล้ว Assistant จะออกคำสั่งเสียง เพื่อควบคุมการเล่นและอัปเดตข้อมูลเมตาของสื่อได้ หากต้องการให้ฟีเจอร์นี้ทำงานได้ โค้ดของคุณควรเปิดใช้การดำเนินการต่อไปนี้และใช้การเรียกกลับที่เกี่ยวข้อง
| การทำงาน | ติดต่อกลับ | คำอธิบาย |
|---|---|---|
ACTION_SKIP_TO_NEXT |
onSkipToNext() |
วิดีโอถัดไป |
ACTION_SKIP_TO_PREVIOUS |
onSkipToPrevious() |
เพลงก่อนหน้า |
ACTION_PAUSE, ACTION_PLAY_PAUSE |
onPause() |
หยุดชั่วคราว |
ACTION_STOP |
onStop() |
หยุด |
ACTION_PLAY |
onPlay() |
ทำต่อ |
ACTION_SEEK_TO |
onSeekTo() |
กรอกลับ 30 วินาที |
ACTION_SET_RATING |
onSetRating(android.support.v4.media.RatingCompat) |
ชอบ/ไม่ชอบ |
ACTION_SET_CAPTIONING_ENABLED |
onSetCaptioningEnabled(boolean) |
เปิด/ปิดคำบรรยายแทนเสียง |
โปรดทราบว่า
- หากต้องการให้คำสั่งข้ามทำงาน
PlaybackStateต้องเป็นเวอร์ชันล่าสุดที่ตรงกับstate, position, playback speed, and update timeแอปต้องเรียกใช้setPlaybackState()เมื่อสถานะเปลี่ยนแปลง - นอกจากนี้ แอปสื่อยังต้องอัปเดตข้อมูลเมตาของเซสชันสื่อให้เป็นข้อมูลล่าสุดอยู่เสมอ ซึ่งรองรับคำถามต่างๆ เช่น "เปิดเพลงอะไรอยู่" แอปต้องเรียกใช้
setMetadata()เมื่อฟิลด์ที่เกี่ยวข้อง (เช่น ชื่อแทร็ก ศิลปิน และชื่อ) เปลี่ยนแปลง MediaSession.setRatingType()ต้องตั้งค่าเพื่อระบุประเภทการจัดประเภทที่แอปรองรับ และแอปต้องใช้onSetRating()หากแอปไม่รองรับการจัดประเภท ควรตั้งค่าประเภทการจัดประเภทเป็นRATING_NONE
การดำเนินการด้วยเสียงที่คุณรองรับมีแนวโน้มที่จะแตกต่างกันไปตามประเภทเนื้อหา
| ประเภทเนื้อหา | การดำเนินการที่จำเป็น |
|---|---|
| เพลง |
ต้องรองรับ: เล่น หยุดชั่วคราว หยุด ข้ามไปเพลงถัดไป และข้ามไปเพลงก่อนหน้า ขอแนะนำให้รองรับ: Seek To |
| พอดแคสต์ |
ต้องรองรับ: เล่น หยุดชั่วคราว หยุด และกรอไปยัง แนะนำให้รองรับ: ข้ามไปยังรายการถัดไปและข้ามไปยังรายการก่อนหน้า |
| หนังสือเสียง | ต้องรองรับ: เล่น หยุดชั่วคราว หยุด และกรอไปยัง |
| วิทยุ | ต้องรองรับ: เล่น หยุดชั่วคราว และหยุด |
| ข่าวสาร | ต้องรองรับ: เล่น หยุดชั่วคราว หยุด ข้ามไปเพลงถัดไป และข้ามไปเพลงก่อนหน้า |
| วิดีโอ |
ต้องรองรับ: เล่น หยุดชั่วคราว หยุด ค้นหา กรอไปข้างหน้า และกรอกลับ ขอแนะนำให้รองรับ: ข้ามไปยังรายการถัดไปและข้ามไปยังรายการก่อนหน้า |
คุณต้องรองรับการดำเนินการที่ระบุไว้ข้างต้นให้มากที่สุดเท่าที่ข้อเสนอผลิตภัณฑ์ของคุณ อนุญาต แต่ก็ยังคงต้องตอบสนองต่อการดำเนินการอื่นๆ อย่างเหมาะสม เช่น หากมีเพียงผู้ใช้พรีเมียมเท่านั้นที่สามารถกลับไปยังรายการก่อนหน้าได้ คุณอาจแสดงข้อผิดพลาดหากผู้ใช้ในระดับฟรีขอให้ Assistant กลับไปยังรายการก่อนหน้า ดูคำแนะนำเพิ่มเติมได้ที่ส่วนการจัดการข้อผิดพลาด
ตัวอย่างคำค้นหาด้วยเสียงที่ลองใช้ได้
ตารางต่อไปนี้แสดงตัวอย่างการค้นหาบางรายการที่คุณควรใช้ขณะ ทดสอบการติดตั้งใช้งาน
| Callback ของ MediaSession | วลี "Ok Google" ที่ใช้ | |
|---|---|---|
onPlay() |
Google Play "ฟังต่อ" |
|
onPlayFromSearch()
onPlayFromUri() |
เพลง |
"เปิดเพลงใน (ชื่อแอป)" นี่คือคำค้นหาที่ไม่มีข้อมูล "เปิด(เพลง | ศิลปิน | อัลบั้ม | แนวเพลง | เพลย์ลิสต์) ใน (ชื่อแอป)" |
| วิทยุ | "เปิด (ความถี่ | สถานี) ใน (ชื่อแอป)" | |
| Audiobook |
"อ่านหนังสือเสียงของฉันใน (ชื่อแอป)" "อ่าน (หนังสือเสียง) ใน (ชื่อแอป)" |
|
| พอดแคสต์ | "เปิด (พอดแคสต์) บน (ชื่อแอป)" | |
onPause() |
"หยุดชั่วคราว" | |
onStop() |
"หยุด" | |
onSkipToNext() |
"(เพลง | ตอน | แทร็ก)ถัดไป" | |
onSkipToPrevious() |
"(เพลง | ตอน | แทร็ก)ก่อนหน้า" | |
onSeekTo() |
"รีสตาร์ท" "ข้ามไปข้างหน้า ## วินาที" "ย้อนกลับไป ## นาที" |
|
ไม่มี (โปรดอัปเดต
MediaMetadata
อยู่เสมอ) |
"เพลงอะไร" | |
ข้อผิดพลาด
Assistant จะจัดการข้อผิดพลาดจากเซสชันสื่อเมื่อเกิดข้อผิดพลาดขึ้น และรายงาน
ข้อผิดพลาดเหล่านั้นให้ผู้ใช้ทราบ ตรวจสอบว่าเซสชันสื่ออัปเดตสถานะการขนส่งและ
รหัสข้อผิดพลาดใน PlaybackState อย่างถูกต้องตามที่อธิบายไว้ในการทำงานกับเซสชันสื่อ ผู้ช่วย
จะจดจำรหัสข้อผิดพลาดทั้งหมดที่ getErrorCode() แสดงผล
กรณีที่มักจัดการไม่ถูกต้อง
ตัวอย่างกรณีข้อผิดพลาดที่คุณควรตรวจสอบว่าได้จัดการอย่างถูกต้องมีดังนี้
- ผู้ใช้ต้องลงชื่อเข้าใช้
- ตั้งรหัสข้อผิดพลาด
PlaybackStateเป็นERROR_CODE_AUTHENTICATION_EXPIRED - ตั้งค่าข้อความแสดงข้อผิดพลาด
PlaybackState - หากจำเป็นสำหรับการเล่น ให้ตั้งค่าสถานะ
PlaybackStateเป็นSTATE_ERRORมิฉะนั้นให้คงค่าPlaybackStateที่เหลือไว้ตามเดิม
- ตั้งรหัสข้อผิดพลาด
- ผู้ใช้ขอการดำเนินการที่ไม่พร้อมใช้งาน
- ตั้งค่า
PlaybackStateรหัสข้อผิดพลาดอย่างเหมาะสม เช่น ตั้งค่าPlaybackStateเป็นERROR_CODE_NOT_SUPPORTEDหากไม่รองรับการดำเนินการ หรือERROR_CODE_PREMIUM_ACCOUNT_REQUIREDหากการดำเนินการได้รับการปกป้องด้วยการลงชื่อเข้าใช้ - ตั้งค่าข้อความแสดงข้อผิดพลาด
PlaybackState - คงค่าที่เหลือของ
PlaybackStateไว้ตามเดิม
- ตั้งค่า
- ผู้ใช้ขอเนื้อหาที่ไม่มีในแอป
- ตั้งค่า
PlaybackStateรหัสข้อผิดพลาดอย่างเหมาะสม เช่น ใช้ERROR_CODE_NOT_AVAILABLE_IN_REGION - ตั้งค่าข้อความแสดงข้อผิดพลาด
PlaybackState - ตั้งค่า
PlaybackSateเป็นSTATE_ERRORเพื่อหยุดการเล่น หรือคงค่าPlaybackStateที่เหลือไว้ตามเดิม
- ตั้งค่า
- ผู้ใช้ขอเนื้อหาที่ไม่มีการจับคู่ที่ตรงกัน เช่น ผู้ใช้ในระดับฟรีขอเนื้อหาที่ใช้ได้เฉพาะกับผู้ใช้ในระดับพรีเมียม
- เราขอแนะนำว่าคุณไม่ควรแสดงข้อผิดพลาด แต่ควรให้ความสำคัญกับการค้นหาเนื้อหาที่คล้ายกันเพื่อเล่นแทน Assistant จะจัดการพูดคำตอบด้วยเสียงที่เกี่ยวข้องมากที่สุด ก่อนที่การเล่นจะเริ่มขึ้น
การเล่นโดยมีเจตนา
Assistant สามารถเปิดแอปเสียงหรือวิดีโอและเริ่มเล่นได้โดยส่ง Intent พร้อมDeep Link
เจตนาและ Deep Link อาจมาจากแหล่งที่มาต่างๆ ดังนี้
- เมื่อ Assistant เริ่มแอปบนอุปกรณ์เคลื่อนที่ Assistant จะใช้ Google Search เพื่อดึงเนื้อหาที่มาร์กอัปซึ่งมีการดำเนินการดูพร้อมลิงก์ได้
- เมื่อ Assistant เริ่มแอปทีวี แอปของคุณควรมี
ผู้ให้บริการค้นหาทีวี
เพื่อแสดง URI สำหรับเนื้อหาสื่อ Assistant จะส่งคำค้นหาไปยัง
ผู้ให้บริการเนื้อหา ซึ่งควรแสดงผล Intent ที่มี URI สำหรับ Deep Link และ
การดำเนินการที่ไม่บังคับ
หากการค้นหาแสดงผลการดำเนินการใน Intent
Assistant จะส่งการดำเนินการและ URI กลับไปยังแอปของคุณ
หากผู้ให้บริการไม่ได้ระบุ
การดำเนินการ Assistant จะเพิ่ม
ACTION_VIEWลงใน Intent
Assistant จะเพิ่มส่วนเสริม EXTRA_START_PLAYBACK ที่มีค่า true
ลงใน Intent ที่ส่งไปยังแอปของคุณ แอปควรเริ่มเล่นเมื่อได้รับ Intent ที่มี EXTRA_START_PLAYBACK
การจัดการ Intent ขณะที่ใช้งานอยู่
ผู้ใช้สามารถขอให้ Assistant เล่นอะไรบางอย่างในขณะที่แอปของคุณยังเล่น เนื้อหาจากคำขอก่อนหน้าอยู่ ซึ่งหมายความว่าแอปจะรับ Intent ใหม่เพื่อ เริ่มการเล่นได้ในขณะที่กิจกรรมการเล่นเปิดอยู่และทำงานอยู่แล้ว
กิจกรรมที่รองรับ Intent ที่มี Deep Link ควรลบล้าง
onNewIntent()
เพื่อจัดการคำขอใหม่
เมื่อเริ่มเล่น Assistant อาจเพิ่มค่าสถานะเพิ่มเติม
ใน Intent ที่ส่งไปยังแอปของคุณ โดยเฉพาะอย่างยิ่ง Assistant อาจเพิ่ม
FLAG_ACTIVITY_CLEAR_TOP หรือ
FLAG_ACTIVITY_NEW_TASK หรือทั้ง 2 อย่าง แม้ว่าโค้ดของคุณ
ไม่จำเป็นต้องจัดการแฟล็กเหล่านี้ แต่ระบบ Android จะตอบสนองต่อแฟล็กดังกล่าว
ซึ่งอาจส่งผลต่อลักษณะการทำงานของแอปเมื่อคำขอเล่นรายการที่ 2 ที่มี URI ใหม่มาถึง
ขณะที่ URI ก่อนหน้ายังคงเล่นอยู่ คุณควรทดสอบว่าแอปตอบสนองอย่างไรในกรณีนี้ คุณใช้เครื่องมือบรรทัดคำสั่ง adb เพื่อจำลองสถานการณ์ได้ (ค่าคงที่ 0x14000000 คือบูลีนบิตไวส์ OR ของ 2 แฟล็ก)
adb shell 'am start -a android.intent.action.VIEW --ez android.intent.extra.START_PLAYBACK true -d "<first_uri>"' -f 0x14000000
adb shell 'am start -a android.intent.action.VIEW --ez android.intent.extra.START_PLAYBACK true -d "<second_uri>"' -f 0x14000000
การเล่นจากบริการ
หากแอปมี
media browser service
ที่อนุญาตการเชื่อมต่อจาก Assistant
Assistant จะเริ่มแอปได้โดยสื่อสารกับ
media sessionของบริการ
บริการเบราว์เซอร์สื่อไม่ควรเปิดใช้กิจกรรม
Assistant จะเปิดใช้งานกิจกรรมตาม PendingIntent ที่คุณกำหนด
ด้วย setSessionActivity()
อย่าลืมตั้งค่า MediaSession.Token เมื่อคุณ เริ่มต้นบริการเบราว์เซอร์สื่อ อย่าลืมตั้งค่าการดำเนินการเล่นที่รองรับ ตลอดเวลา รวมถึงในระหว่างการเริ่มต้น Assistant คาดหวังให้แอปสื่อ ของคุณตั้งค่าการดำเนินการเล่นก่อนที่ Assistant จะส่งคำสั่งเล่น คำสั่งแรก
หากต้องการเริ่มต้นจากบริการ ผู้ช่วยจะใช้ Media Browser Client API โดยจะเรียกใช้ TransportControls ที่ทริกเกอร์การเรียกกลับการดำเนินการ PLAY ในเซสชันสื่อของแอป
แผนภาพต่อไปนี้แสดงลำดับการเรียกที่ Assistant สร้างขึ้นและ การเรียกกลับของเซสชันสื่อที่เกี่ยวข้อง (ระบบจะส่งการเรียกกลับ prepare เฉพาะในกรณีที่แอปของคุณรองรับเท่านั้น) การเรียกใช้ทั้งหมดเป็นแบบอะซิงโครนัส Assistant จะไม่รอการตอบกลับจากแอปของคุณ

เมื่อผู้ใช้ออกคำสั่งเสียงให้เล่น Assistant จะตอบกลับด้วยประกาศสั้นๆ ทันทีที่ประกาศเสร็จสมบูรณ์ Assistant จะออกการดำเนินการ PLAY โดยไม่ต้องรอสถานะการเล่นที่เฉพาะเจาะจง
หากแอปของคุณรองรับACTION_PREPARE_* Assistant จะเรียกใช้การดำเนินการ PREPARE ก่อนเริ่มประกาศ
การเชื่อมต่อกับ MediaBrowserService
หากต้องการใช้บริการเพื่อเริ่มแอป Assistant ต้องเชื่อมต่อกับ MediaBrowserService ของแอปและ
เรียกข้อมูล MediaSession.Token ของแอปได้ ระบบจะจัดการคำขอเชื่อมต่อในเมธอด onGetRoot() ของบริการ คุณจัดการคำขอได้ 2 วิธี ดังนี้
- ยอมรับคำขอเชื่อมต่อทั้งหมด
- ยอมรับคำขอเชื่อมต่อจากแอป Assistant เท่านั้น
ยอมรับคำขอเชื่อมต่อทั้งหมด
คุณต้องส่งคืน BrowserRoot เพื่ออนุญาตให้ Assistant ส่งคำสั่งไปยังเซสชันสื่อ วิธีที่ง่ายที่สุดคือการอนุญาตให้แอป MediaBrowser ทั้งหมดเชื่อมต่อกับ MediaBrowserService คุณต้องส่งคืน BrowserRoot ที่ไม่ใช่ค่าว่าง นี่คือโค้ดที่เกี่ยวข้องจาก Universal Music Player
Kotlin
override fun onGetRoot( clientPackageName: String, clientUid: Int, rootHints: Bundle? ): BrowserRoot? { // To ensure you are not allowing any arbitrary app to browse your app's contents, you // need to check the origin: if (!packageValidator.isCallerAllowed(this, clientPackageName, clientUid)) { // If the request comes from an untrusted package, return an empty browser root. // If you return null, then the media browser will not be able to connect and // no further calls will be made to other media browsing methods. Log.i(TAG, "OnGetRoot: Browsing NOT ALLOWED for unknown caller. Returning empty " + "browser root so all apps can use MediaController. $clientPackageName") return MediaBrowserServiceCompat.BrowserRoot(MEDIA_ID_EMPTY_ROOT, null) } // Return browser roots for browsing... }
Java
@Override public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) { // To ensure you are not allowing any arbitrary app to browse your app's contents, you // need to check the origin: if (!packageValidator.isCallerAllowed(this, clientPackageName, clientUid)) { // If the request comes from an untrusted package, return an empty browser root. // If you return null, then the media browser will not be able to connect and // no further calls will be made to other media browsing methods. LogHelper.i(TAG, "OnGetRoot: Browsing NOT ALLOWED for unknown caller. " + "Returning empty browser root so all apps can use MediaController." + clientPackageName); return new MediaBrowserServiceCompat.BrowserRoot(MEDIA_ID_EMPTY_ROOT, null); } // Return browser roots for browsing... }
ยอมรับแพ็กเกจแอปและลายเซ็นของ Assistant
คุณอนุญาตให้ Assistant เชื่อมต่อกับบริการเบราว์เซอร์สื่อได้อย่างชัดเจนโดยตรวจสอบชื่อแพ็กเกจและลายเซ็น แอปจะได้รับชื่อแพ็กเกจในเมธอด onGetRoot ของ MediaBrowserService คุณต้องส่งคืน BrowserRoot เพื่ออนุญาตให้ Assistant ส่งคำสั่งไปยังเซสชันสื่อ ตัวอย่าง เครื่องเล่นเพลงสากล จะดูแลรักษารายชื่อชื่อแพ็กเกจและลายเซ็นที่รู้จัก ด้านล่างนี้คือชื่อแพ็กเกจและลายเซ็นที่ Google Assistant ใช้
<signature name="Google" package="com.google.android.googlequicksearchbox">
<key release="false">19:75:b2:f1:71:77:bc:89:a5:df:f3:1f:9e:64:a6:ca:e2:81:a5:3d:c1:d1:d5:9b:1d:14:7f:e1:c8:2a:fa:00</key>
<key release="true">f0:fd:6c:5b:41:0f:25:cb:25:c3:b5:33:46:c8:97:2f:ae:30:f8:ee:74:11:df:91:04:80:ad:6b:2d:60:db:83</key>
</signature>
<signature name="Google Assistant on Android Automotive OS" package="com.google.android.carassistant">
<key release="false">17:E2:81:11:06:2F:97:A8:60:79:7A:83:70:5B:F8:2C:7C:C0:29:35:56:6D:46:22:BC:4E:CF:EE:1B:EB:F8:15</key>
<key release="true">74:B6:FB:F7:10:E8:D9:0D:44:D3:40:12:58:89:B4:23:06:A6:2C:43:79:D0:E5:A6:62:20:E3:A6:8A:BF:90:E2</key>
</signature>