Google Assistant และแอปสื่อ

Google Assistant ให้คุณใช้คำสั่งเสียงเพื่อควบคุมอุปกรณ์ต่างๆ ได้ เช่น Google Home, โทรศัพท์ของคุณ และอีกมากมาย มีความสามารถในตัว เข้าใจคำสั่งสื่อ ("เปิดอะไรก็ตามของ Beyoncé") และรองรับ การควบคุมสื่อ (เช่น หยุดชั่วคราว ข้าม กรอไปข้างหน้า ยกนิ้วโป้ง)

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

ใช้เซสชันสื่อ

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

โปรดทราบว่าแม้ Assistant จะใช้เฉพาะการดำเนินการที่ระบุไว้ในส่วนนี้ แนวทางปฏิบัติที่ดีที่สุดคือการใช้ API การเตรียมความพร้อมและการเล่นทั้งหมด ความสามารถในการใช้งานร่วมกันกับแอปพลิเคชันอื่น สำหรับการดำเนินการใดก็ตามที่คุณไม่รองรับ Callback ของเซสชันสื่อสามารถแสดงผลข้อผิดพลาดได้โดยใช้ ERROR_CODE_NOT_SUPPORTED

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

เซสชันสื่อของแอปต้องประกาศการดำเนินการที่รองรับ และใช้ Callback ของเซสชันสื่อที่เกี่ยวข้อง ประกาศการดำเนินการที่รองรับใน setActions()

โปรแกรมเล่นเพลง Android สากล โปรเจ็กต์ตัวอย่างเป็นตัวอย่างที่ดีของวิธีตั้งค่าเซสชันสื่อ

การเล่น

ในการเริ่มเล่นจากบริการ เซสชันสื่อต้องมีการดำเนินการ PLAY ต่อไปนี้และ Callback

การทำงาน การติดต่อกลับ
ACTION_PLAY onPlay()
ACTION_PLAY_FROM_SEARCH onPlayFromSearch()
ACTION_PLAY_FROM_URI (*) onPlayFromUri()

เซสชันของคุณควรใช้การดำเนินการ PREPARE ต่อไปนี้และ Callback

การทำงาน การติดต่อกลับ
ACTION_PREPARE onPrepare()
ACTION_PREPARE_FROM_SEARCH onPrepareFromSearch()
ACTION_PREPARE_FROM_URI (*) onPrepareFromUri()

(*) การดำเนินการตาม URI ของ Google Assistant จะใช้ได้กับบริษัทเท่านั้น ที่ส่ง URI ให้ Google ดูข้อมูลเพิ่มเติมเกี่ยวกับการอธิบายเนื้อหาสื่อของคุณให้ Google ทราบ ดูการดำเนินการกับสื่อ

การใช้ API ที่จัดเตรียมจะทำให้เวลาในการตอบสนองการเล่นหลังจากคำสั่งเสียง สามารถลดขนาดลงได้ แอปสื่อที่ต้องการปรับปรุงเวลาในการตอบสนองของการเล่นสามารถใช้ มีเวลามากขึ้นในการเริ่มแคชเนื้อหาและเตรียมการเล่นสื่อ

แยกวิเคราะห์คำค้นหา

เมื่อผู้ใช้ค้นหารายการสื่อที่เฉพาะเจาะจง เช่น "เปิดเพลงแจ๊สใน [ชื่อแอปของคุณ]" หรือ "ฟัง [ชื่อเพลง]" onPrepareFromSearch() หรือ onPlayFromSearch() Callback Method จะได้รับพารามิเตอร์การค้นหาและ Bundles เพิ่มเติม

แอปของคุณควรแยกวิเคราะห์คำค้นหาด้วยเสียง และเริ่มเล่นโดยทำตามวิธีต่อไปนี้ ขั้นตอน:

  1. ใช้กลุ่มเพิ่มเติมและสตริงข้อความค้นหาที่แสดงผลจากการค้นหาด้วยเสียง เพื่อกรองผลลัพธ์
  2. สร้างคิวการเล่นจากผลลัพธ์เหล่านี้
  3. เล่นรายการสื่อที่เกี่ยวข้องมากที่สุดจากผลการค้นหา

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

เมื่อผู้ใช้พูดว่า "เปิดเพลงใน [ชื่อแอปของคุณ]" Android Automotive OS หรือ Android Auto พยายามเปิดแอปและเล่นเสียงโดยโทรหา onPlayFromSearch() ของแอป แต่เนื่องจากผู้ใช้ไม่ได้พูดชื่อรายการสื่อ onPlayFromSearch() จะได้รับพารามิเตอร์การค้นหาที่ว่างเปล่า ในกรณีเหล่านี้ แอปของคุณควร โต้ตอบด้วยการเล่นเสียงทันที เช่น เพลงจากเพลงล่าสุด หรือคิวแบบสุ่ม

ประกาศการรองรับการสั่งงานด้วยเสียงแบบเดิม

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

การทำงาน การติดต่อกลับ คำอธิบาย
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

การสั่งงานด้วยเสียงที่คุณสนับสนุนมักจะแตกต่างกันไปตามประเภทเนื้อหา

ประเภทเนื้อหา การดำเนินการที่จำเป็น
เพลง

ต้องมีการรองรับ: เล่น หยุดชั่วคราว หยุด ข้ามไปรายการถัดไป และข้ามไปที่ก่อนหน้า

แนะนำการสนับสนุนอย่างยิ่งสำหรับ: "กรอไปยัง"

พอดแคสต์

ต้องมีการสนับสนุน: เล่น หยุดชั่วคราว หยุด และกรอไปยัง

แนะนำการสนับสนุนสำหรับ: ข้ามไปยังรายการถัดไปและข้ามไปยังก่อนหน้า

หนังสือเสียง ต้องมีการสนับสนุน: เล่น หยุดชั่วคราว หยุด และกรอไปยัง
วิทยุ ต้องรองรับ: เล่น หยุดชั่วคราว และหยุด
ข่าว ต้องมีการรองรับ: เล่น หยุดชั่วคราว หยุด ข้ามไปรายการถัดไป และข้ามไปที่ก่อนหน้า
วิดีโอ

ต้องมีการรองรับ: เล่น หยุดชั่วคราว หยุด กรอไปข้างหน้า และกรอไปข้างหน้า

แนะนำการสนับสนุนอย่างยิ่งสำหรับ: ข้ามไปยังรายการถัดไปและข้ามไปยังก่อนหน้า

คุณต้องรองรับการดำเนินการตามที่แสดงไว้ข้างต้นให้ได้มากที่สุดเหมือนกับข้อเสนอผลิตภัณฑ์ อนุญาต แต่ยังตอบสนองต่อการดำเนินการอื่นๆ ได้อย่างดี ตัวอย่างเช่น หาก ผู้ใช้ระดับพรีเมียมสามารถ กลับมาที่รายการก่อนหน้าได้ คุณอาจเพิ่ม ข้อผิดพลาดหากผู้ใช้รุ่นฟรีขอให้ Assistant กลับไปยังรายการก่อนหน้า ดูคําแนะนําเพิ่มเติมในส่วนการจัดการข้อผิดพลาด

ตัวอย่างคำถามแบบเสียงที่จะลองใช้

ตารางต่อไปนี้จะสรุปตัวอย่างการค้นหาที่คุณควรใช้ในฐานะ ทดสอบการใช้งาน:

การติดต่อกลับ MediaSession วลี "Ok Google" ที่จะใช้
onPlay()

"เล่น"

"ฟังต่อ"

onPlayFromSearch()
onPlayFromUri()
เพลง

"เปิดเพลงหรือเพลงใน (ชื่อแอป)" คำค้นหานี้ว่างเปล่า

"เปิด (เพลง | ศิลปิน | อัลบั้ม | แนวเพลง | เพลย์ลิสต์) ใน (ชื่อแอป)"

วิทยุ "เปิด (ความถี่ | สถานี) ใน (ชื่อแอป)"
Audiobook

"อ่านหนังสือเสียงของฉันใน (ชื่อแอป)"

"อ่าน (หนังสือเสียง) ใน (ชื่อแอป)"

พอดแคสต์ "เปิด (พอดแคสต์) ใน (ชื่อแอป)"
onPause() "หยุดชั่วคราว"
onStop() "หยุด"
onSkipToNext() "(เพลง | ตอน | แทร็ก) ถัดไป"
onSkipToPrevious() "(เพลง | ตอน | แทร็ก) ก่อนหน้า"
onSeekTo()

"รีสตาร์ท"

"ข้ามไปข้างหน้า ## วินาที"

"ย้อนกลับไป ## นาที"

ไม่มี (เก็บ MediaMetadata อัปเดตแล้ว) "เปิดอะไรอยู่"

ข้อผิดพลาด

Assistant จัดการข้อผิดพลาดจากเซสชันสื่อเมื่อเกิดเหตุการณ์ขึ้น และส่งรายงาน ให้แก่ผู้ใช้ ตรวจสอบว่าเซสชันสื่ออัปเดตสถานะการนำส่งและ ใน PlaybackState อย่างถูกต้อง ตามที่อธิบายไว้ใน การทำงานกับ เซสชันสื่อ Assistant จดจำรหัสข้อผิดพลาดทั้งหมดที่แสดงผลโดย 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 เปิดอยู่ แอปดังกล่าวสามารถใช้การค้นหาของ Google เพื่อเรียกเนื้อหาที่มาร์กอัปที่ ใส่ลิงก์ให้กับการดำเนินการดูวิดีโอ
  • เมื่อ Assistant กำลังเริ่มแอป TV แอปของคุณควรมี ผู้ให้บริการค้นหาทีวี เพื่อแสดง URI ของเนื้อหาสื่อ Assistant ส่งคำถามไปยัง ผู้ให้บริการเนื้อหาซึ่งควรแสดงผล Intent ที่มี URI สำหรับ Deep Link และ การดำเนินการที่ไม่บังคับ หากการค้นหาแสดงการดำเนินการใน Intent Assistant จะส่งการดำเนินการและ URI กลับไปยังแอปของคุณ หากผู้ให้บริการไม่ได้ระบุ การดําเนินการ Assistant จะเพิ่ม ACTION_VIEW ลงใน Intent

Assistant เพิ่ม EXTRA_START_PLAYBACK ที่มีค่า true ตามจุดประสงค์ที่ส่งไปยังแอปของคุณ แอปควรเริ่มเล่นเมื่อ ได้รับ Intent ด้วย EXTRA_START_PLAYBACK

การจัดการ Intent ขณะใช้งาน

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

กิจกรรมที่รองรับ Intent ที่มี Deep Link ควรลบล้าง onNewIntent() ในการจัดการคำขอใหม่

เมื่อเริ่มเล่น Assistant อาจเพิ่ม แฟล็ก ตามจุดประสงค์ที่ส่งไปยังแอปของคุณ โดยเฉพาะอย่างยิ่ง อาจเพิ่ม FLAG_ACTIVITY_CLEAR_TOP หรือ FLAG_ACTIVITY_NEW_TASK หรือทั้งคู่ แม้ว่าโค้ดของคุณ ไม่จำเป็นต้องจัดการกับการแจ้งว่าไม่เหมาะสมเหล่านี้ แต่ระบบ Android จะตอบสนองต่อการแจ้งดังกล่าว การทำเช่นนี้อาจส่งผลต่อลักษณะการทำงานของแอปเมื่อมีคำขอเล่นครั้งที่ 2 ที่มี URI ใหม่เข้ามา ขณะที่ URI ก่อนหน้ายังเล่นอยู่ คุณควรทดสอบว่าแอปตอบสนองอย่างไรในกรณีนี้ คุณใช้คำสั่ง adb ได้ เครื่องมือขีดเส้นเพื่อจำลองสถานการณ์ (ค่า 0x14000000 คงที่คือบิตไวส์บูลีน OR ของค่าสถานะทั้งสอง):

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 จะส่งการเล่นครั้งแรก คำสั่ง

โดย Assistant จะใช้ API ไคลเอ็นต์ของเบราว์เซอร์สื่อเพื่อเริ่มต้นใช้งานจากบริการ ดำเนินการเรียกใช้ TransportControl ที่เรียกใช้ Callback การดำเนินการ PLAY บน เซสชันสื่อของแอป

แผนภาพต่อไปนี้แสดงลำดับการเรียกที่ Assistant สร้างขึ้นและ Callback ของเซสชันสื่อที่เกี่ยวข้อง (ระบบจะส่ง Callback ที่เตรียมไว้ให้เท่านั้น หากแอปรองรับ) การเรียกทั้งหมดทำงานไม่พร้อมกัน 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>