«دستیار Google» و برنامه‌های رسانه

«دستیار Google» به شما امکان می‌دهد از فرمان‌های صوتی برای کنترل کردن بسیاری از دستگاه‌ها، مانند Google Home، تلفنتان، و غیره استفاده کنید. این برنامه قابلیت داخلی برای درک فرمان‌های رسانه («آهنگی از بیانسه پخش کن») دارد و از کنترل‌های رسانه (مثل مکث، رد شدن، جلو بردن سریع، رأی موافق) پشتیبانی می‌کند.

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

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

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

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

پروژه نمونه پخش‌کننده موسیقی Android جهانی نمونه خوبی از نحوه راه‌اندازی جلسه رسانه است.

کنش‌های بازپخش

برای شروع بازپخش از سرویس، جلسه رسانه باید این کنش‌های 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 را ببینید.

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

تجزیه پرسمان‌های جستجو

وقتی کاربر فایل رسانه‌ای خاصی را جستجو می‌کند، مثلاً «Play jazz on [your app name]» یا «Listen to [song title]»، روش فراخوانی برگشتی onPrepareFromSearch() یا onPlayFromSearch() پارامتر پُرسمان و بسته موارد اضافی را دریافت می‌کند.

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

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

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

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

وقتی کاربر می‌گوید «Play music on [your app name]» (در [نام برنامه شما] موسیقی پخش کن)، «سیستم‌عامل Android Automotive» یا Android Auto با فراخوانی روش onPlayFromSearch() برنامه شما، تلاش می‌کند برنامه شما را راه‌اندازی کند و صدا پخش کند. بااین‌حال، چون کاربر نام فایل رسانه‌ای را نگفته است، روش onPlayFromSearch() پارامتر پُرسمان خالی دریافت می‌کند. در این موارد، برنامه‌تان باید با پخش فوری صدا، مثلاً آهنگی از جدیدترین فهرست پخش یا صف تصادفی، پاسخ دهد.

اعلام پشتیبانی قدیمی برای کنش‌های گفتاری

در بیشتر موارد، مدیریت کنش‌های بازپخش شرح‌داده‌شده در بالا همه عملکردهای بازپخش موردنیاز را به برنامه‌تان می‌دهد. بااین‌حال، برخی‌از سیستم‌ها نیاز دارند که برنامه شما حاوی فیلتر 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() ۳۰ ثانیه به عقب
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 عبارت «Ok Google» برای استفاده
onPlay()

«پخش کن.»

«ازسرگیری».

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

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

«Play (song | artist | album | genre | playlist) on (app name).‎» ((آهنگ | هنرمند | آلبوم | ژانر | فهرست پخش) را در (نام برنامه) پخش کن.)

رادیو «Play (frequency | station) on (app name).‎» ((فرکانس | ایستگاه) را در (نام برنامه) پخش کن.)
کتاب صوتی

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

«Read (audiobook) on (app name).» ((کتاب صوتی) را در (نام برنامه) بخوان.)

پادکست‌ها «Play (podcast) on (app name).‎» ((پادکست) را در (نام برنامه) پخش کن.)
onPause() «توقف موقت».
onStop() «Stop» (توقف).
onSkipToNext() ‫«Next (song | episode | track).» ((ترانه | قسمت | قطعه) بعدی.)
onSkipToPrevious() «Previous (song | episode | track).‎» ([آهنگ | قسمت | قطعه] قبلی.)
onSeekTo()

«بازراه‌اندازی».

«## ثانیه جلو برو.»

«Go back ## minutes.‎» (‫## دقیقه به عقب برگرد.)

ناموجود (MediaMetadata خود را به‌روز نگه دارید) «What’s playing?‎» (چه چیزی درحال پخش است؟)

خطاها

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

بازپخش با قصد

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

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

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

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

مدیریت کردن هدف‌ها درحین فعال بودن

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

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

هنگام شروع بازپخش، «دستیار» ممکن است پرچم‌های اضافی به قصدی که به برنامه شما ارسال می‌کند اضافه کند. به‌ویژه، ممکن است FLAG_ACTIVITY_CLEAR_TOP یا FLAG_ACTIVITY_NEW_TASK یا هر دو را اضافه کند. اگرچه کد شما نیازی به رسیدگی به این پرچم‌ها ندارد، سیستم Android به آن‌ها پاسخ می‌دهد. این امر ممکن است بر رفتار برنامه‌تان هنگام دریافت دومین درخواست بازپخش با شناسه منبع یکسان جدید درحالی‌که شناسه منبع یکسان قبلی هنوز درحال پخش است تأثیر بگذارد. بهتر است آزمایش کنید که برنامه‌تان در این مورد چگونه پاسخ می‌دهد. می‌توانید از ابزار خط فرمان 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 داشته باشد که به اتصالات از «دستیار» اجازه دهد، «دستیار» می‌تواند با برقراری ارتباط با media session سرویس، برنامه را شروع کند. سرویس مرورگر رسانه هرگز نباید «فعالیتی» را راه‌اندازی کند. «دستیار» «فعالیت» شما را براساس PendingIntent که با setSessionActivity() تعریف می‌کنید راه‌اندازی می‌کند.

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

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

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

درحال شروع بازپخش با جلسه رسانه

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

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

درحال اتصال به MediaBrowserService

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

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

پذیرفتن همه درخواست‌های اتصال

برای اینکه به «دستیار» اجازه دهید به جلسه رسانه شما فرمان ارسال کند، باید BrowserRoot را برگردانید. ساده‌ترین راه این است که به همه برنامه‌های MediaBrowser اجازه دهید به MediaBrowserService شما متصل شوند. باید BrowserRoot غیرتهی برگردانید. کد مربوطه از Universal Music Player در اینجا آمده است:

کاتلین

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

پذیرفتن بسته و امضای برنامه «دستیار»

می‌توانید با بررسی نام بسته و امضای سرویس مرورگر رسانه، صریحاً به «دستیار» اجازه دهید به آن متصل شود. برنامه‌تان نام بسته را در روش onGetRoot از MediaBrowserService شما دریافت خواهد کرد. برای اینکه به «دستیار» اجازه دهید به جلسه رسانه شما فرمان ارسال کند، باید BrowserRoot را برگردانید. نمونه Universal Music Player فهرستی از نام‌ها و امضاهای بسته شناخته‌شده را نگهداری می‌کند. در زیر نام‌های بسته و امضاهایی که «دستیار 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>