دستیار گوگل و برنامه های رسانه ای

Google Assistant به شما امکان می دهد از دستورات صوتی برای کنترل بسیاری از دستگاه ها مانند Google Home، تلفن خود و غیره استفاده کنید. دارای قابلیت داخلی برای درک دستورات رسانه ("بازی چیزی توسط بیانسه") و از کنترل های رسانه (مانند مکث، پرش، سریع به جلو، شست بالا) پشتیبانی می کند.

دستیار با استفاده از یک جلسه رسانه با برنامه های رسانه Android ارتباط برقرار می کند. می تواند از intent ها یا خدمات برای راه اندازی برنامه شما و شروع پخش استفاده کند. برای بهترین نتایج، برنامه شما باید تمام ویژگی های توضیح داده شده در این صفحه را اجرا کند.

از یک جلسه رسانه ای استفاده کنید

هر برنامه صوتی و تصویری باید یک جلسه رسانه اجرا کند تا «دستیار» بتواند پس از شروع پخش، کنترل‌های انتقال را اجرا کند.

توجه داشته باشید که در حالی که دستیار فقط از اقدامات ذکر شده در این بخش استفاده می کند، بهترین کار این است که همه API های آماده سازی و پخش را برای اطمینان از سازگاری با سایر برنامه ها پیاده سازی کنید. برای هر اقدامی که پشتیبانی نمی‌کنید، تماس‌های جلسه رسانه به سادگی می‌توانند با استفاده از ERROR_CODE_NOT_SUPPORTED خطا را برگردانند.

با تنظیم این پرچم‌ها در شی MediaSession برنامه، کنترل‌های رسانه و انتقال را فعال کنید:

کاتلین

session.setFlags(
        MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
        MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
)

جاوا

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 فقط برای شرکت هایی کار می کند که URI را به Google ارائه می کنند. برای کسب اطلاعات بیشتر در مورد توصیف محتوای رسانه ای خود در Google، به Media Actions مراجعه کنید.

با پیاده سازی API های آماده سازی، تاخیر پخش پس از فرمان صوتی را می توان کاهش داد. برنامه‌های رسانه‌ای که می‌خواهند تأخیر پخش را بهبود بخشند، می‌توانند از زمان اضافی برای شروع ذخیره محتوا و آماده‌سازی پخش رسانه استفاده کنند.

جستارهای جستجو را تجزیه کنید

هنگامی که کاربر به دنبال یک آیتم رسانه ای خاص، مانند «Play jazz on [Your name app]» یا «Listen to [Song Title]» را جستجو می کند، روش پاسخ تماس onPrepareFromSearch() یا onPlayFromSearch() یک پارامتر پرس و جو و یک بسته اضافی دریافت می کند. .

برنامه شما باید عبارت جستجوی صوتی را تجزیه کند و با دنبال کردن مراحل زیر شروع به پخش کند:

  1. از بسته نرم افزاری اضافی و رشته درخواست جستجوی بازگشتی از جستجوی صوتی برای فیلتر کردن نتایج استفاده کنید.
  2. بر اساس این نتایج یک صف پخش بسازید.
  3. مرتبط ترین آیتم رسانه ای را از نتایج پخش کنید.

متد onPlayFromSearch() یک پارامتر اضافی با اطلاعات دقیق‌تر از جستجوی صوتی می‌گیرد. این موارد اضافی به شما کمک می کند محتوای صوتی را در برنامه خود برای پخش پیدا کنید. اگر نتایج جستجو قادر به ارائه این داده ها نیستند، می توانید منطق را برای تجزیه پرس و جو جستجوی خام و پخش آهنگ های مناسب بر اساس پرس و جو پیاده سازی کنید.

موارد اضافی زیر در سیستم عامل Android Automotive و Android Auto پشتیبانی می شوند:

قطعه کد زیر نحوه نادیده گرفتن متد onPlayFromSearch() در اجرای MediaSession.Callback خود برای تجزیه عبارت جستجوی صوتی و شروع پخش نشان می دهد:

کاتلین

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
    }
}

جاوا

@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
    }
}

برای مثال دقیق تر در مورد نحوه اجرای جستجوی صوتی برای پخش محتوای صوتی در برنامه خود، به نمونه پخش کننده موسیقی جهانی Android مراجعه کنید.

پرس و جوهای خالی را مدیریت کنید

اگر onPrepare() ، onPlay() ، onPrepareFromSearch() ، یا onPlayFromSearch() بدون درخواست جستجو فراخوانی شوند، برنامه رسانه شما باید رسانه "جاری" را پخش کند. اگر رسانه فعلی وجود ندارد، برنامه باید سعی کند چیزی را پخش کند، مانند آهنگی از آخرین لیست پخش یا یک صف تصادفی. هنگامی که کاربر بدون اطلاعات اضافی درخواست «پخش موسیقی در [نام برنامه شما]» را می‌دهد، دستیار از این APIها استفاده می‌کند.

وقتی کاربر می‌گوید «موسیقی را در [نام برنامه شما] پخش کنید» ، سیستم‌عامل Android Automotive یا Android Auto با فراخوانی روش onPlayFromSearch() برنامه شما تلاش می‌کند تا برنامه شما را راه‌اندازی کند و صدا پخش کند. با این حال، چون کاربر نام آیتم رسانه را نگفته است، متد onPlayFromSearch() یک پارامتر query خالی دریافت می کند. در این موارد، برنامه شما باید با پخش فوری صدا، مانند آهنگی از آخرین لیست پخش یا یک صف تصادفی، پاسخ دهد.

پشتیبانی قدیمی از اقدامات صوتی را اعلام کنید

در بیشتر موارد، انجام اقدامات بازپخشی که در بالا توضیح داده شد، تمام عملکرد پخش مورد نیاز را به برنامه شما می‌دهد. با این حال، برخی از سیستم‌ها نیاز دارند که برنامه شما حاوی فیلتر Intent برای جستجو باشد. شما باید پشتیبانی از این فیلتر Intent را در فایل‌های مانیفست برنامه خود اعلام کنید.

این کد را در فایل مانیفست برنامه تلفن قرار دهید:

<activity>
    <intent-filter>
        <action android:name=
             "android.media.action.MEDIA_PLAY_FROM_SEARCH" />
        <category android:name=
             "android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

کنترل های حمل و نقل

پس از فعال شدن جلسه رسانه برنامه، دستیار می‌تواند فرمان‌های صوتی را برای کنترل پخش و به‌روزرسانی فراداده رسانه صادر کند. برای اینکه این کار کار کند، کد شما باید اقدامات زیر را فعال کرده و فراخوان های مربوطه را پیاده سازی کند:

اقدام پاسخ به تماس توضیحات
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 را توصیه می کنیم

پادکست

باید پشتیبانی : پخش، مکث، توقف، و جستجو برای

پیشنهاد پشتیبانی برای : پرش به بعدی و پرش به قبلی

کتاب صوتی باید پشتیبانی : پخش، مکث، توقف، و جستجو برای
رادیو باید پشتیبانی : پخش، مکث و توقف
اخبار باید پشتیبانی کند : پخش، مکث، توقف، پرش به بعدی و پرش به قبلی
ویدئو

باید پشتیبانی کند : پخش، مکث، توقف، جستجو برای، عقب و سریع به جلو

اکیداً پشتیبانی از موارد زیر را توصیه می کنیم : پرش به بعدی و پرش به قبلی

شما باید تا جایی که پیشنهادات محصول شما اجازه می دهد از اقدامات ذکر شده در بالا پشتیبانی کنید، اما همچنان به هر اقدام دیگری با مهربانی پاسخ دهید. به عنوان مثال، اگر فقط کاربران ممتاز توانایی بازگشت به مورد قبلی را داشته باشند، ممکن است اگر یک کاربر سطح رایگان از «دستیار» بخواهد به مورد قبلی بازگردد، خطا ایجاد کنید. برای راهنمایی بیشتر به بخش رسیدگی به خطا مراجعه کنید.

نمونه سوالات صوتی را امتحان کنید

جدول زیر برخی از پرس و جوهای نمونه را نشان می دهد که باید هنگام آزمایش پیاده سازی خود از آنها استفاده کنید:

MediaSession Callback عبارت «Hey Google» برای استفاده
onPlay()

"بازی"

"رزومه."

onPlayFromSearch()
onPlayFromUri()
موسیقی

"پخش موسیقی یا آهنگ در (نام برنامه) ." این یک پرس و جو خالی است.

«پخش (آهنگ | هنرمند | آلبوم | سبک | لیست پخش) در (نام برنامه)

رادیو «پخش (فرکانس | ایستگاه) در (نام برنامه) ».
کتاب صوتی

«کتاب صوتی من را در (نام برنامه) بخوانید.»

خواندن (کتاب صوتی) در (نام برنامه) .

پادکست ها « پادکست را در (نام برنامه) پخش کنید.»
onPause() "مکث."
onStop() "ایست کن."
onSkipToNext() "بعدی (آهنگ | قسمت | آهنگ) ."
onSkipToPrevious() "قبلی (آهنگ | قسمت | آهنگ) ."
onSeekTo()

"راه اندازی مجدد."

" ## ثانیه به جلو بپرید."

" ## دقیقه به عقب برگرد."

N/A ( MediaMetadata خود را به روز نگه دارید) "چی بازی میکنه؟"

خطاها

«دستیار» خطاهای یک جلسه رسانه را هنگام رخ دادن کنترل می کند و آنها را به کاربران گزارش می دهد. مطمئن شوید که جلسه رسانه شما وضعیت انتقال و کد خطا را در 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 را همانطور که هست حفظ کنید.
  • کاربر محتوایی را درخواست می کند که مطابقت دقیق آن در دسترس نباشد. به عنوان مثال، یک کاربر سطح آزاد که محتوایی را فقط برای کاربران سطح برتر درخواست می کند.
    • توصیه می‌کنیم خطا را برنگردانید و در عوض باید چیزی شبیه به بازی را پیدا کنید. پیش از شروع پخش، «دستیار» با مرتبط‌ترین پاسخ صوتی صحبت می‌کند.

پخش با قصد

دستیار می‌تواند یک برنامه صوتی یا تصویری را راه‌اندازی کند و با ارسال یک هدف با پیوند عمیق ، پخش را شروع کند.

هدف و پیوند عمیق آن می تواند از منابع مختلفی باشد:

  • وقتی «دستیار» یک برنامه تلفن همراه را راه‌اندازی می‌کند، می‌تواند از جستجوی Google برای بازیابی محتوای علامت‌گذاری‌شده استفاده کند که عملکرد تماشا را با پیوند ارائه می‌کند.
  • وقتی «دستیار» یک برنامه تلویزیونی را راه‌اندازی می‌کند، برنامه شما باید دارای ارائه‌دهنده جستجوی تلویزیون باشد تا URI‌های محتوای رسانه را در معرض دید قرار دهد. دستیار درخواستی را به ارائه‌دهنده محتوا ارسال می‌کند که باید یک هدف حاوی یک URI برای پیوند عمیق و یک اقدام اختیاری را برگرداند. اگر پرس و جو اقدامی را در intent برگرداند، دستیار آن عملکرد و URI را به برنامه شما برمی‌گرداند. اگر ارائه‌دهنده اقدامی را مشخص نکرده باشد، Assistant ACTION_VIEW به Intent اضافه می‌کند.

«دستیار» EXTRA_START_PLAYBACK اضافی را با ارزشی true به هدفی که به برنامه شما ارسال می‌کند، اضافه می‌کند. برنامه شما باید زمانی که هدفی با EXTRA_START_PLAYBACK دریافت کرد، پخش را شروع کند.

مدیریت مقاصد در حین فعال بودن

وقتی برنامه شما همچنان محتوای درخواست قبلی را پخش می‌کند، کاربران می‌توانند از دستیار بخواهند چیزی پخش کند. این بدان معناست که برنامه شما می‌تواند در حالی که فعالیت پخش آن از قبل راه‌اندازی و فعال است، قصدهای جدیدی برای شروع پخش دریافت کند.

فعالیت‌هایی که از intent با پیوندهای عمیق پشتیبانی می‌کنند، باید روی onNewIntent() برای رسیدگی به درخواست‌های جدید لغو شوند.

هنگام شروع پخش، دستیار ممکن است پرچم‌های بیشتری را به هدفی که به برنامه شما ارسال می‌کند اضافه کند. به ویژه، ممکن است FLAG_ACTIVITY_CLEAR_TOP یا FLAG_ACTIVITY_NEW_TASK یا هر دو را اضافه کند. اگرچه کد شما نیازی به کنترل این پرچم ها ندارد، اما سیستم اندروید به آنها پاسخ می دهد. هنگامی که درخواست پخش دوم با یک URI جدید در حالی که URI قبلی هنوز در حال پخش است، می رسد، این ممکن است بر رفتار برنامه شما تأثیر بگذارد. بهتر است در این مورد نحوه واکنش برنامه خود را آزمایش کنید. می توانید از ابزار خط فرمان adb برای شبیه سازی وضعیت استفاده کنید (ثابت 0x14000000 بیتی یا بولی دو پرچم است):

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 است که امکان اتصال از دستیار را فراهم می کند، دستیار می تواند با برقراری ارتباط با media session سرویس، برنامه را راه اندازی کند. سرویس مرورگر رسانه هرگز نباید یک Activity راه اندازی کند. Assistant Activity شما را بر اساس PendingIntent که با setSessionActivity() تعریف کرده اید راه اندازی می کند.

هنگام راه اندازی سرویس مرورگر رسانه، حتما MediaSession.Token را تنظیم کنید. به یاد داشته باشید که اقدامات پخش پشتیبانی شده را همیشه تنظیم کنید، از جمله در هنگام شروع اولیه. «دستیار» انتظار دارد که برنامه رسانه شما اقدامات پخش را قبل از ارسال اولین فرمان پخش توسط «دستیار» تنظیم کند.

برای شروع از یک سرویس، Assistant API های سرویس گیرنده مرورگر رسانه را پیاده سازی می کند. تماس‌های TransportControls را انجام می‌دهد که در جلسه رسانه برنامه شما، تماس‌های کنش PLAY را فعال می‌کند.

نمودار زیر ترتیب تماس های ایجاد شده توسط Assistant و تماس های مربوط به جلسه رسانه را نشان می دهد. (بازگشت های آماده فقط در صورتی ارسال می شوند که برنامه شما از آنها پشتیبانی کند.) همه تماس ها ناهمزمان هستند. «دستیار» منتظر هیچ پاسخی از برنامه شما نیست.

شروع پخش با یک جلسه رسانه

هنگامی که کاربر فرمان صوتی را برای پخش صادر می کند، دستیار با یک اعلامیه کوتاه پاسخ می دهد. به محض تکمیل اعلامیه، دستیار یک اقدام PLAY را صادر می کند. منتظر هیچ حالت پخش خاصی نمی ماند.

اگر برنامه شما از کنش‌های ACTION_PREPARE_* پشتیبانی می‌کند، دستیار قبل از شروع اعلامیه، اقدام PREPARE را فراخوانی می‌کند.

اتصال به MediaBrowserService

برای استفاده از سرویسی برای راه اندازی برنامه، دستیار باید بتواند به MediaBrowserService برنامه متصل شود و MediaSession.Token آن را بازیابی کند. درخواست های اتصال در روش onGetRoot() سرویس رسیدگی می شود. دو راه برای رسیدگی به درخواست ها وجود دارد:

  • تمام درخواست های اتصال را بپذیرید
  • درخواست‌های اتصال را فقط از برنامه دستیار بپذیرید

تمام درخواست های اتصال را بپذیرید

شما باید یک BrowserRoot را برگردانید تا به دستیار اجازه دهید دستورات را به جلسه رسانه شما ارسال کند. ساده ترین راه این است که به همه برنامه های MediaBrowser اجازه دهید به MediaBrowserService شما متصل شوند. شما باید یک BrowserRoot غیر تهی را برگردانید. در اینجا کد قابل اجرا از پخش کننده موسیقی جهانی آمده است:

کاتلین

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...
}

جاوا

@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 را بپذیرید

می‌توانید به صراحت به دستیار اجازه دهید با بررسی نام بسته و امضای آن به سرویس مرورگر رسانه شما متصل شود. برنامه شما نام بسته را در روش onGetRoot MediaBrowserService شما دریافت می کند. شما باید یک BrowserRoot را برگردانید تا به دستیار اجازه دهید دستورات را به جلسه رسانه شما ارسال کند. نمونه پخش‌کننده موسیقی جهانی فهرستی از نام‌ها و امضاهای بسته‌های شناخته شده را نگهداری می‌کند. در زیر نام بسته ها و امضاهایی وجود دارد که توسط دستیار Google استفاده می شود.

<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>